Dockerfile
Dockerfile에 대한 내용을 정리한다.
Examples
- Selenium WebDriver#Selenium for Dockerfile - Chrome, ChromeDriver 설치 방법
Build
Dockerfile 빌드는 아래와 같이 진행한다.
Command
-
FROM
: 부모 이미지를 지정한다. 어떤 이미지로부터 새로운 이미지를 생성할지 지정한다. -
MAINTAINER
: Dockerfile을 생성-관리하는 사람의 정보를 입력한다. -
ENV
: 환경 변수를 지정한다. -
EXPOSE
: 가상 머신에 오픈할 포트를 지정한다.docker run
명령의--expose
옵션과 동일합니다. -
WORKDIR
: 명령어를 실행할 작업 디렉토리(Working directory)를 설정한다. -
ADD
: 파일을 이미지에 추가한다. 형식은ADD [복사할 파일 경로] [이미지에서 파일이 위치할 경로]
이다.- ADD 인스트럭션으로 추가 된 파일은 해시기반 체크섬 검증을 해주는 것이 좋다.
CMD
: 컨테이너에서 실행될 명령어를 지정한다. 다만 docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
시 COMMAND
가 존재할 경우 실행하지 않는다.- 운영 체제를 담은 기반 이미지를 만드는 경우처럼 특수한 경우에만 사용하면 된다.
- 안정성 보장이 되지 않으므로 COPY 를 사용하자.
ENTRYPOINT
: CMD와 비슷하다. 다만 docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
시 COMMAND
가 존재할 경우 ENTRYPOINT
의 추가인자로 덧붙인다. 1 RUN
: 이미지 빌드 시 컨테이너에서 실행할 명령어 정의 COPY
: 호스트에서 컨테이너로 파일 및 디렉토리 복사 ARG
: docker image build를 실행할 때 사용하는 변수 EXPOSE
: 컨테이너가 노출하는 포트 VOLUME
: 호스트나 다른 컨테이너에서 마운트할 수 있는 포인트 생성 LABEL
: 이미지에 추가하는 메타데이터 STOPSIGNAL
: 컨테이너에 전달되면 컨테이너를 종료하는 시스템 시그널 설정 HEALTHCHECK
: 컨테이너 안에서 명령을 실행 후 결과를 헬스 체크에 사용- 명령 사용 예시 - Docker Compose#Healthcheck
USER
: 컨테이너 실행 시 컨테이너 사용자- 이미지 빌드시 USER 뒤에 나오는 RUN 인스트럭션도 해당 사용자의 권한으로 실행된다.
ONBUILD
: 컨테이너 안에서 실행되는 명령 정의, 이미지에서 실행되지 않는다.- ONBUILD 를 정의한 이미지를 기반 이미지로 삼아 다른 이미지를 빌드할 때 실행된다.
Setup
보통 아래와 같이 시작한다.
CentOS 7의 경우:
FROM centos:7
MAINTAINER yourname <[email protected]>
Ubuntu 14.04의 경우:
FROM ubuntu:14.04
MAINTAINER yourname <[email protected]>
Example
FROM ubuntu:12.04
MAINTAINER Daekwon Kim <[email protected]>
# COMMENT
RUN apt-get -qq -y install git curl build-essential
RUN apt-get -qq -y install apache2
ENV APACHE_RUN_USER www-data
# ...
RUN ./var/www/moniwiki/secure.sh
EXPOSE 80
CMD ["/usr/sbin/apache2", "-D", "FOREGROUND"]
ENV APP_HOME /myapp
WORKDIR $APP_HOME
ADD Gemfile* $APP_HOME/
ADD . $APP_HOME
기반 이미지
- scratch: 아무 것도 없는 이미지
- https 통신이 필요한 경우 cacert.pem 을 /etc/ssl/certs 에 추가해야한다.
- 디버깅도 힘들다
- busybox: 기본 유틸리티 (echo, ls 등) 이 있는 이미지
- 패키지 관리자가 없다.
- 디버깅은 좀 낫다.
- alpine: busybox 기반으로 4MB 지만 apk 패키지 매니저가 있다.
- glibc 대신 musl을 쓴다.
-
apk add --no-cache package
-
apk add --no-cache --virtual=ailas package && apk del --no-cache ailas
-
- distroless 이미지
- 운영체제 기능은 없이 언어에 중점을 둔 이미지이다.
- distroless 에서 확인 가능하며 주로 구글이 배포한다.
- gcr.io/distroless/base 이미지는 glibc 기반이며 컴파일 애플리케이션을 실행하는 데에 적합하다. (Go)
- ca-certificates 및 TLS/SSL 관련 라이브러리 등 최소한의 라이브러리만 있다.
- CVE 취약점도 업데이트 된다고 한다.
MySQL dockerfile
FROM ubuntu:14.04
## apt-get 설치시 사용자 입력을 받지 않는다는 환경변수 설정.
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN echo "mysql-server mysql-server/root_password password" | debconf-set-selections
RUN echo "mysql-server mysql-server/root_password_again password" | debconf-set-selections
RUN apt-get install -y mysql-server
WORKDIR /etc/mysql
RUN sed -i "s/127.0.0.1/0.0.0.0/g" my.cnf
Multi-stage build
Use a previous stage as a new stage
You can pick up where a previous stage left off by referring to it when using the FROM directive. For example:
FROM alpine:latest as builder
RUN apk --no-cache add build-base
FROM builder as build1
COPY source1.cpp source.cpp
RUN g++ -o /binary source.cpp
FROM builder as build2
COPY source2.cpp source.cpp
RUN g++ -o /binary source.cpp
Docker image build script
프로젝트용 이미지를 만들 수 있는 bash 스크립트:
#!/usr/bin/env bash
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)
WORKING_DIR=$SCRIPT_DIR
DOCKERFILE_PATH=$SCRIPT_DIR/project-python-3.8.9.dockerfile
IMAGE_NAME=yourname/project
IMAGE_TAG=python-3.8.9
TAG_NAME=$IMAGE_NAME:$IMAGE_TAG
TAG_LATEST=$IMAGE_NAME:latest
USAGE_MESSAGE="
Build project docker image.
Usage: project-build.sh [options]
Available options are:
-p, --push Push an image to a registry.
-l, --latest Add 'latest' tag.
-n, --dry-run Don’t actually do anything, just show what would be done.
-h, --help Print this message.
"
function exit_on_error
{
local code=$?
if [[ $code -ne 0 ]]; then
exit $code
fi
}
function run_command
{
local dry_run=$1
shift
if [[ $dry_run -eq 1 ]]; then
echo "$@"
else
"$@"
fi
exit_on_error
}
function recc_node_build_main
{
local src="$OPM_HOME/INFORMATION"
local enable_push=0
local add_latest=0
local dry_run=0
while [[ ! -z $1 ]]; do
case $1 in
-h|--help)
echo "$USAGE_MESSAGE"
return 0
;;
-p|--push)
enable_push=1
shift
;;
-n|--dry-run)
dry_run=1
shift
;;
-l|--latest)
add_latest=1
shift
;;
*)
break
;;
esac
done
local build_commands=("--file" "$DOCKERFILE_PATH" "-t" "$TAG_NAME")
if [[ $add_latest -eq 1 ]]; then
build_commands+=("-t" "$TAG_LATEST")
fi
build_commands+=("$WORKING_DIR")
run_command $dry_run docker build ${build_commands[*]}
if [[ $enable_push -eq 0 ]]; then
return 0
fi
run_command $dry_run docker push $TAG_NAME
if [[ $add_latest -eq 0 ]]; then
return 0
fi
run_command $dry_run docker push $TAG_LATEST
}
recc_node_build_main "$@"
dockerd 튜닝
-
max-concurrent-downloads
: 기본값은 3이며, docker image pull 로 한 번에 다운로드 되는 이미지 스레드 수를 증가시켜준다. -
max-concurrent-uploads
: 기본값은 5이며, docker image push 시에 이미지 업로드 스레드 수를 증가시켜준다. -
registry-mirrors
: Docker hub의 미러 레지스트리를 만들어 트래픽 향상에 이점을 줄 수 있다.
Tools
- hadolint - Dockerfile best practices 에 기반해 이미지를 생성했는지 검증.
- container-structure-test - yaml 기반 테스트.
- goss - yaml 기반 테스트. 실제 포트 및 서비스가 서빙 중인지 확인이 가능해 더 유용할 것으로 보인다.
- Vault - secret
See also
Favorite site
- 가장 빨리 만나는 Docker 16장 - 1. 워드프레스 Dockerfile 작성하기
- 가장 빨리 만나는 Docker 16장 - 2. MySQL 데이터베이스 Dockerfile 작성하기
- 가장 빨리 만나는 Docker 16장 - 3. 워드프레스와 데이터베이스 컨테이너 생성하기
- Docker, Rails, & Docker Compose together in your development workflow
- Dockerfile의 모든 것 | Gracefullight
Examples
Guide
- [추천] Docker Best Practices for Python Developers | TestDriven.io 2 - Python 개발자를 위한 Docker 모범 사례
References
-
Docker_Best_Practices_for_Python_Developers_TestDriven.io.pdf ↩