본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로인프라 › 컨테이너 › Docker

9. Dockerfile

목차

Dockerfile을 사용한 구성 관리

Dockerfile은 Docker상에서 작동시킬 컨테이너의 구성정보를 기술하기 위한 파일.

docker build 명령을 통해 Dockerfile에 기술된 구성정보를 바탕으로 Docker 이미지를 작성한다.

Dockerfile의 기본 서식

명령 인수

명령은 대소문자 상관없이 사용가능하며 관례적으로 대문자를 통일해 사용.

명령설명
FROM베이스 이미지 지정
RUN명령 실행
CMD컨테이너 실행 명령
LABEL라벨 설정
EXPOSE포트 익스포트
ENV환경변수
ADD파일/디렉토리 추가
COPY파일 복사
ENTRYPOINT컨테이너 실행 명령
VOLUME볼륨 마운트
USER사용자 지정
WORKDIR작업 디렉토리
ARGDockerfile 안의 변수
ONBUILD빌드 완료 후 실행되는 명령
STOPSIGNAL시스템 콜 시그널 설정
HEALTHCHECK컨테이너 헬스 체크
SHELL기본 쉘 설정

Dockerfile에 주석을 쓰는경우 앞에 #을 붙인다.

#주석 주석입니다.
명령 인수
명령 인수    # 이것도 주석

Dockerfile 작성

Dockerfile에는 ‘Docker 컨테이너를 어떤 Docker 이미지로부터 생서할지’라는 정보를 기술해야한다. 이걸 베이스 이미지라 한다.

Dockerfile에는 ’Docker 컨테이너를 어떤 Docker 이미지로부터 생서할지’라는 정보를 기술해야한다. 이걸 베이스 이미지라 한다.

FROM 명령

FROM [이미지명]
FROM [이미지명]:[태그명]
FROM [이미지명]@[다이제스트]

FROM명령은 필수 항목이며 CentOS 7버전을 베이스 이미지로 사용할 경우

# FROM [이미지명]:[태그명]
FROM centos:centos7
# 태그명을 생략할경우 최신버전이 적용된다 (latest)
FROM centos

다이제스트를 저장한 Dockerfile

ls 명령에서 —digests 옵션을 지정하면 다이제스틀 확인할 수 있다.

ls 명령에서 –digests 옵션을 지정하면 다이제스틀 확인할 수 있다.

$ docker image ls --digests nginx
REPOSITORY   TAG       DIGEST                                                                    IMAGE ID       CREATED      SIZE
nginx        latest    sha256:b95a99feebf7797479e0c5eb5ec0bdfa5d9f504bc94da550c2f58e839ea6914f   2b7d6430f78d   9 days ago   142MB
# 베이스 이미지 설정
#FROM [이미지명]@[다이제스트]
FROM nginx@sha256:b95a99feebf7797479e0c5eb5ec0bdfa5d9f504bc94da550c2f58e839ea6914f

Dockerfile 빌트 및 이미지 레이어

Dockerfile로부터 Docker 이미지 만들기

$ docker build -t [생성할 이미지명]:태그명 [Dockerfile의 위치]

도커파일 생성

% mkdir sample && cd $_ 

sample % touch Dockerfile
sample % ls
Dockerfile

centos 7버전 내용 작성

FROM centos:centos7

Dockerfile 실행

% docker build -t sample:1.0 .

[+] Building 26.3s (6/6) FINISHED
 => [internal] load build definition from Dockerfile                                         0.0s
 => => transferring dockerfile: 62B                                                          0.0s
 => [internal] load .dockerignore                                                            0.0s
 => => transferring context: 2B                                                              0.0s
 => [internal] load metadata for docker.io/library/centos:centos7                            6.4s
 => [auth] library/centos:pull token for registry-1.docker.io                                0.0s
 => [1/1] FROM docker.io/library/centos:centos7@sha256:c73f515d06b0fa07bb18d8202035e739a49  19.8s
 => => resolve docker.io/library/centos:centos7@sha256:c73f515d06b0fa07bb18d8202035e739a494  0.0s
 => => sha256:2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b5 76.10MB / 76.10MB  16.1s
 => => sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b 1.20kB / 1.20kB  0.0s
 => => sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f 529B / 529B   0.0s
 => => sha256:eeb6ee3f44bd0b5103bb561b4c16bcb82328cfe5809ab675bb17ab3a16c51 2.75kB / 2.75kB  0.0s
 => => extracting sha256:2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc    3.3s
 => exporting to image                                                                       0.0s
 => => exporting layers                                                                      0.0s
 => => writing image sha256:72b64f44af7b171e762593a7834a88ba13c30b6f349c75532807fd903c5ee79  0.0s
 => => naming to docker.io/library/sample:1.0

명령을 실행하면 해당 ./sample 에 저장된 Dockerfile로 부터 sample이라는 이름의 도커 이미지가 생성된다. 베이스 이미지인 centos:centos7이 로컬 환경에 없을경우 Docker Repository에서 다운받은 후 sample이라는 이름에 1.0 태그를 설정하면 sample:1.0이라는 이미지가 생성된다.

% docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
sample       1.0       72b64f44af7b   11 months ago   204MB
centos          latest    5d0da3dc9764   11 months ago   231MB

Dockerfile에 임의이 파일명 작성

docker build 명령에서 -f 옵션을 사용하여 임의의 파일명을 사용할 수 있다. 디렉토리에서 Dockerfile.[이름]라는 이름을 파일을 지정하면된다.

$ docker build -t sample -f Dockerfile.base .

단 파일명이 Dockerfile 이외의 이름을 지닌 경우 Docker Hub에서 이미지 자동 생성 기능을 사용할 수 없다.

Docker 이미지 레이어 구조

Dockerfile을 빌드하여 Docker이미지를 작성하면 Dockerfile 이미지를 작성할 수 있다. 작성된 여러 개의 이미지는 레이어 구조로 되어있다.

# STEP1 : ubunutu(base image)
FROM ubuntu:latest

# STEP2 : nginx install
RUN apt-get update && apt-get install -y -q nginx

# STEP3 : copy file
#Dockerfile 디렉토리에 index.html 파일을 둬야함.
COPY index.html /usr/share/nginx/html/

# STEP4 : Start Nginx
CMD ["nginx", "-g", "daemon off;"]

컨테이너 Health Check 명령

컨테이너 안의 프로세스가 정상적으로 작동하고 있는지 체크하기 위해 사용.

HEALTHCHECK [옵션] CMD 실행할 명령
옵션설명기본값
—interval=n헬스 체크 간격30s
—timeout=n헬스 체크 타임아웃30s
—retries=N타임아웃 횟수3
옵션설명기본값
–interval=n헬스 체크 간격30s
–timeout=n헬스 체크 타임아웃30s
–retries=N타임아웃 횟수3

ex)

HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1

결과는 docker container inspect명령으로 확인 가능.

환경 및 네트워크 설정

환경변수 설정(ENV)

ENV [key] [value]
ENV [key]=[value]

# ex) key value type
ENV myName "devPaik"
ENV myNickName "DEV"

# ex) key=value type
ENV myName="devPaik" \
    myNickName="DEV"

작업 디렉토리 지정(WORKDIR)

## 지정한 디렉토리가 없으면 새로 생성
WORKDIR [작업 디렉토리 경로]

ex)

## result : /first/second/third
WORKDIR /first
WORKDIR second
WORKDIR third
RUN ["pwd"]


## result : /first/second
ENV DIRPATH /first
ENV DIRNAME second
WORKDIR $DIRPATH/$DIRNAME
RUN ["pwd"]

사용자 지정 (USER)

이미지 실행 시 사용자를 지정할 때 사용

USER [사용자명/UID]

라벨 지정(LABEL)

이미지 버전정보 및 작성자 정보 코멘트 등을 제공할 때 사용.

LABEL <KEY>=<VALUE>
LABEL <KEY> <VALUE>

ex)

LABEL maintainer "DevPaik"
LABEL title="WebApp"
LABEL version="1.0"
LABEL description="This image is sample WebApp"

포트설정(EXPOSE)

컨테이너의 공개포트 번호를 지정할 때 사용

EXPOSE <포트번호>
EXPOSE 8080

Dockerfile 내 변수 설정(ARG)

변수 정의할 때 사용.

ARG <이름> [=기본값]
# 변수 정의
ARG NAME="PAIK"
RUN echo $NAME

기본 쉘 설정(SHELL 명령)

쉘 형식으로 명령을 실행할 때 사용.

SHELL ["쉘의 경로", "파라미터"]
SHELL ["/bin/bash", "-c"]

RUN echo hello

파일 설정

파일 및 디렉토리 추가(ADD)

이미지에 호스트 상의 파일이나 디렉토리를 추가

ADD <호스트의 파일 경로> <Docker 이미지의 파일 경로>
ADD ["<호스트의 파일 경로>" "<Docker 이미지의 파일 경로>"]

ex)

## host.html 추가
ADD host.html /docker_dir/

## [hos]로 시작하는 모든 파일 추가
ADD hos* /docker_dir/

## [hos]+ 임의 한 문자 롤에 해당하는 파일 추가
ADD hos?.txt /docker_dir/

Docker 이미지 안의 파일은 절대경로를 지정하거나 WORKDIR 명령에서 지정한 디렉토리를 기점으로 한 명령을 지정

ex) /docker_dir을 지정하고 그 안에 web이라는 디렉토리에 host.html를 복사

WORKDIR /docker_dir
ADD host.html web/

파일복사(COPY)

이미지에 호스트상의 파일이나 디렉토리를 복사할 때

COPY <호스트 파일 경로> <Docker 이미지의 경로>
COPY ["<호스트 파일 경로>" "<Docker 이미지의 경로>"]

ADD명령은 원격 파일의 다운로드나 아카이브 압축 해제 등과 같은 기능을 갖고있고, COPY 명령은 호스트상의 파일을 이미지 안으로 복사하는 처리만 한다.

볼륨 마운트(VOLUME)

이미지에 볼륨을 할당할 때 사용

# 지정한 이름의 마운트 포인트를 작성하고 호스트나 그 외 다른 컨테이너로부터 볼륨의 외부 마운트를 수행.
VOLUME ["/마운트 포인트"]

실제로 빌드 가능한 정적 웹 이미지

앞의 centos:centos7과 오래된 Nginx 다이제스트는 과거 실습 기록이므로 새 프로젝트의 버전 선택 기준으로 삼지 않는다. 다음 예시는 index.html 파일이 있는 실습 디렉터리에서 시작한다.

FROM nginx:stable
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
printf '<h1>Dockerfile test</h1>\n' > index.html
docker build -t web-lab:1.0 .
docker run --rm -d --name web-lab -p 127.0.0.1:8080:80 web-lab:1.0
curl -s http://127.0.0.1:8080/
docker rm -f web-lab

빌드의 마지막 .은 Dockerfile 경로가 아니라 빌드 컨텍스트다. COPY는 컨텍스트 안의 index.html을 이미지에 넣는다. 파일이 다른 디렉터리에 있거나 .dockerignore에서 제외됐다면 COPY 단계가 실패한다. EXPOSE는 이미지가 사용할 포트를 문서화하지만 외부 공개는 docker run -p에서 따로 결정한다. 원문의 CMD ["nginx" "-g", ...]는 JSON 배열의 쉼표가 빠진 잘못된 예시여서 위처럼 고쳤다.

flowchart LR
  C[빌드 컨텍스트와 Dockerfile] -->|docker build| I[이미지 계층]
  I -->|docker run| R[읽기·쓰기 가능한 컨테이너]
  R -->|포트 게시| H[호스트 요청]

캐시와 결과 이미지

Docker는 빌드 지시어와 입력을 비교해 재사용 가능한 단계를 캐시한다. 예를 들어 Node 애플리케이션이라면 패키지 메타데이터를 먼저 복사해 의존성을 설치하고, 자주 바뀌는 소스를 나중에 복사하면 코드 수정 시 의존성 설치 단계를 재활용할 여지가 생긴다. 반대로 COPY . .를 처음에 두면 작은 소스 변경도 그 뒤 단계의 캐시를 무효화할 수 있다. .dockerignore에 node_modules, .git, 비밀 값 파일, 큰 빌드 산출물을 제외하면 전송량과 우발적 포함을 줄인다.

빌드 도구가 필요한 애플리케이션은 멀티 스테이지 빌드를 고려한다. 첫 단계에서 컴파일하고 두 번째 단계에는 실행 파일과 필요한 런타임만 복사한다. 빌드 도구를 최종 이미지에 넣지 않아 이미지 크기와 공격 표면을 줄일 수 있다. ARG나 ENV에 비밀 값을 넣으면 이미지 기록 또는 메타데이터에 남을 수 있으므로 BuildKit 비밀 마운트나 배포 환경의 비밀 관리 기능을 사용한다. USER를 지정해 런타임을 비 root로 실행할 수 있지만 애플리케이션의 파일 권한과 포트 요구사항을 함께 맞춰야 한다.

관찰확인할 부분
COPY 파일 없음빌드 컨텍스트, 현재 디렉터리, .dockerignore
재빌드가 계속 느림변경이 잦은 COPY가 의존성 설치보다 앞인지
컨테이너가 바로 종료됨CMD/ENTRYPOINT의 프로세스와 docker logs
브라우저 접속 불가컨테이너의 수신 포트, EXPOSE와 -p의 차이

태그 latest는 고정 버전이 아니다. 베이스 이미지의 보안 업데이트를 반영하려면 정기적으로 재빌드·테스트해야 한다. 같은 Dockerfile도 베이스 이미지나 외부 패키지가 바뀌면 결과가 달라질 수 있으므로 배포 이미지의 버전과 출처를 기록한다.

참고: Dockerfile 작성 모범 사례, 멀티 스테이지 빌드, 빌드 캐시, 빌드 비밀 값.

같은 카테고리의 글