본문으로 바로가기

올바른 Dockerfile 작성법

category 프로그래밍 & IT/Docker 2017.10.24 15:44
  1. Dockerfile Best Practice
    1. General principle
      1. 설치 구성의 최소화
        컨테이너는 효율적인 리소스 사용 및 배포의 자동화를 위해, 사용량을 고려하여 scale in/out 될 수 있는구조 입니다. 
        따라서 해당 컨테이너가 필요에 따라 생성되거나 삭제될 수 있다는 점을 고려하여, 컨테이너에 필요 이상의 설정을 하지 않고 최소한의 설정/구성으로 구동할 것을 권장합니다.
      2. 복잡성, 의존성을 최소화 하기 위하여 불필요한 library의 설치를 지양해야 합니다.
      3. 컨테이너가 삭제될 경우 컨테이너 내부의 데이터도 함께 삭제 됩니다. 사용자에 의해 변경되거나 기록될 수 있는 데이터는 VOLUME 명령어를 이용하여 외부에 적재해야 합니다.

    2.  .dockerignore 파일의 활용
      빌드 작업을 수행할 때 docker engine은 build script 파일(Dockerfile)있는 경로와 모든 하위 경로의 파일/디렉토리를 docker context에 저장한 후 build 작업을 수행합니다. 
      이 경우 docker build 에 직접적으로 사용되지 않더라도 해당 경로 하위에 있는 파일/디렉토리가 context에 포함될 수 있습니다. 
      이를 방지하기 위하여 .dockerignore 파일을 이용하여 빌드 시에 제외할 파일/디렉토리를 지정할 수 있습니다.
      빌드 되는 컨테이너 이미지의 기능 차이는 없으나, 빌드 성능을 높이기 위하여 build 가 이루어지는 디렉토리에서 .dockerignore 파일을 생성하여 활용하시기 바랍니다.
      가장 좋은 방법은 빈 디렉토리를 생성한 후에 Dockerfile과 build에 반드시 필요한 파일/디렉토리만을 해당 디렉토리 내부에 위치하여 container 이미지를 생성하는 방법입니다.



    3. 1 application per 1 container
      1개의 컨테이너 안에 2개 이상의 어플리케이션을 구동하여 사용하는 것은 컨테이너로 구동되어 있는 어플리케이션 간의 결합성을 높이고 확장성을 떨어트립니다. 
      자원의 효율적인 확장을 위하여 1개의 컨테이너 안에 웹서버, 데이터베이스 등을 모두 설치하여 사용하는 방식을 지양해야 합니다.

    4. Dockerfile 스크립트 최소화
      Docker 이미지의 구성 레이어 수는 Dockerfile 의 예약어 수에 비례합니다. 가독성을 높이기 위하여 Dockerfile의 예약어를 여러 라인에 걸쳐 사용할 수 있지만, 
      레이어의 수가 증가하여 파일크기, 빌드시간 등이 늘어날 수 있으므로 가독성과 이미지 크기를 적절히 고려하여 Dockerfile 스크립트를 구성해야 합니다.

    5. Caching 기능 활용
      빌드 시간을 단축하기 위하여 캐시 기능을 활용할 수 있습니다. Docker engine은 한번 이상 빌드한 Dockerfile의 이미지를 스크립트 라인 단위로 캐싱 합니다. 
      변경되지 않은 라인의 경우 기존의 캐싱 데이터를 이용하므로, 자주 변경될 수 있는 예약어의 경우 Dockerfile의 하단에 위치하는 것이 좋습니다.

  2. Command instruction
    1. FROM
      Base 이미지의 경우 docker hub에서 제공하는 official 이미지를 사용하는 것을 권장합니다. official 이미지는 docker principle 에 따라 최소한의 설치 요소로 구성되어 있습니다.

    2. ENV
      1. ENV 예약어를 통한 version 명시
        ENV 예약어를 이용하여 설치된 어플리케이션의 major, minor version을 명시하면 직관성을 높일 수 있습니다.


      2. 실행 경로 추가
        구동 되어질 컨테이너 내부의 환경변수를 정의합니다. WORKDIR, USER 등의 명령어를 조합하여 사용하지 않는 경우, 
        환경변수 PATH에 어플리케이션의 경로를 추가하여 구동 시 임의의 위치에서 명령어가 실행 될 수 있도록 지정할 수 있습니다.

    3. ADD, COPY 명령어 
      1. COPY
        host 환경의 파일, 디렉토리를 대상 컨테이너 이미지 안으로 복사합니다.
      2. ADD
        1. Auto-extraction : 복사하는 대상 파일이 압축 파일(tar, tar.gz)일 경우, 해당 파일의 압축을 해제하여 복사합니다.
        2. Remote-URL : wget등을 통하여 원격지의 파일을 복사할 파일로 지정할 수 있습니다. 
      3. ADD 명령어의 경우 auto-extraction, remote-url 기능을 추가적으로 지원합니다. 해당 기능을 사용하는 경우가 아니라면, 직관성이 더 높은 COPY 명령어를 권장합니다.

    4. RUN 명령어
      대부분의 RUN명령어는 apt-get(debian,ubuntu), yum(centos) 로 사용됩니다.

      1. apt, yum command
        1. 최소구성을 위한 자동 update 지양
          apt-get명령어를 사용할 경우 불필요한 apt-get upgrade 등의 명령어를 사용하지 않을 것을 권장합니다. 
          최소 구성을 위한 설치 이외의 권장되지만(nice to have) 반드시 필요하지는 않는 라이브러리 또한 함께 설치되어 이미지 레이어 크기가 증가합니다.

        2. 다중 파라미터
          명령어의 파라미터가 많은 경우, 중복 명령어 판별성을 높이기를 위하여 알파벳순으로 정렬해서 여러라인으로 표시합니다.

        3. cachinig 방식 유의(cache busting)
          Docker engine은 ADD, COPY 이외의 명령어에 대하여 string 값을 비교하여 캐싱 작업을 수행합니다.
          예를 들어,

          14: RUN apt-get update
          15: RUN apt-get install -y curl

          위의 빌드 스크립트를 포함한 docker image를 생성하여 사용한 후에, 사용 뒤의 용도 변경으로 인하여

          14: RUN apt-get update
          15: RUN apt-get install -y curl nginx

          위와 같이 변경하였을 경우, docker engine은 14번째 라인까지 캐싱 값을 사용하여 15번째 라인부터 명령어를 수행합니다. 
          이 경우 최신 update를 사용하지 않게 되어, nginx 가 latest버전으로 설치 되지 않을 수 있습니다. 설치하는 library, middle ware 의 최신화를 위화여 update 구문은 항상

          14: RUN apt-get update && apt-get install something ..

          위와 같이 파이프라인을 통하여 함께 수행하는것을 권장합니다.

        4. apt, yum 캐시 제거
          apt-get update, apt-get install 명령어를 수행한 후에 파이프라인을 통하여 apt cache를 제거하면 레이어의 크기를 줄일 수 있습니다.

        5. 위의 instruction을 정리하여 아래와 같은 방식으로 apt-get 명령어를 수행하는 것을 권장합니다.

          RUN apt-get update \
          && apt-get install -y --no-install-recommends libjemalloc1 \
          curl \
          nginx \
          && rm -rf /var/lib/apt/lists/*



      2. Using pipes

        RUN wget -O - https://some.site | wc -l > /number

        위의 구문 같은 경우 wget 의 성공/실패 여부와 상관없이 그 결과 출력의 wc -l 구문 결과가 /number에 성공적으로 저장되면서 docker build engine은 이 경우 언제나 성공으로 인식합니다. 
        build 초기에 잡히는 구문 오류가 아닌, 이러한 논리적 오류을 없애기 위해선

        RUN set -o pipefail && wget -O - https://some.site | wc -l > /number

        이와 같은 방식으로 set -o option을 같이 적용해줘야 합니다. 

    5. CMD, ENTRYPOINT 활용
      ENTRYPOINT와 CMD는 모두 컨테이너가 생성될때 명령이 실행된다는 점에서는 동일하지만 해당 컨테이너를 docker run 명령어로 구동할때 동작방식이 다릅니다.cmd 명령어는 docker run 후에 오는 명령어의 파라미터가 있을 경우 적용되지 않습니다. 이를 이용하여 ENTRYPOINT의 인자로 실행할 컨테이너 내부의 main application의 명령어를 지정하고CMD에 그 default 파라미터를 부여하는 방식을 권장합니다. 아래와 같이 build script를 구성하여 이미지(이미지명 : s3cmd)를 빌드한 경우

      20 : ENTRYPOINT ["s3cmd"]
      21 : CMD ["–help"]

      docker run s3cmd 라고 입력할 경우 해당 명령어의 help command를 볼 수 있고, 
      docker run ls s3://mybucket 와 같이 입력하여 명령어의 해당 기능을 실행해 볼 수 있습니다.

    6. VOLUME
      General principal 에서 전술되었듯이, 컨테이너 이미지 내부의 파일/디렉토리는 컨테이너 삭제 시 함께 삭제 됩니다. user에 의해서 서비스가능한 모든부분(설정,로그,데이터)은 반드시 VOLUME을 이용하는 것을 권장합니다.

    7. USER
      특별한 권한이 없이 서비스 되는 application의 경우 user를 지정해야 합니다. USER명령어로 user를 지정하기 전에는 아래와 같은 명령어를 먼저 실행하여 user와 group(option)을 생성해줍니다.

      RUN groupadd -r testuser && useradd --no-log-init -r -g testuser testuser

      Dockerfile 내부에서 USER 를 여러 번 전환하여, 의미 없는 레이어를 증가시키지 않도록 해야 합니다.



    8. WORKDIR
      RUN, CMD, ENTRYPOINT, COPY 등의 명령어가 수행되는 경로를 지정합니다. 
      WORKDIR의 경우 cd(change directory command)와 마찬가지로 상대 경로를 통하여 이동하므로, 
      가독성을 높이기 위하여 항상 절대 경로를 이용하여 이동하는 것을 권장합니다.



 Other Contents 

댓글을 달아 주세요

티스토리 툴바