Skip to content

Dockerfile

Dockerfile에 대한 내용을 정리한다.

Examples

Build

Dockerfile 빌드는 아래와 같이 진행한다.

$ docker build -t [REPO_NAME]/[TAG_NAME] [DOCKERFILE_PATH]

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
  • Volume: 한마디로 디렉토리 공유.
  • RUN: 이미지 빌드 시 컨테이너에서 실행할 명령어 정의
  • COPY: 호스트에서 컨테이너로 파일 및 디렉토리 복사
  • ARG: docker image build를 실행할 때 사용하는 변수
  • EXPOSE: 컨테이너가 노출하는 포트
  • VOLUME: 호스트나 다른 컨테이너에서 마운트할 수 있는 포인트 생성
  • LABEL: 이미지에 추가하는 메타데이터
  • STOPSIGNAL: 컨테이너에 전달되면 컨테이너를 종료하는 시스템 시그널 설정
  • 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

See also

Favorite site

Examples

Guide

References


  1. 가장 빨리 만나는 Docker 7장 - 6. ENTRYPOINT 

  2. Docker_Best_Practices_for_Python_Developers_TestDriven.io.pdf