본문 바로가기

Docker

도커 파일

 

이미지 생성하는 방법

  1. 아무것도 존재하지 않는 이미지(우분투, CentOS 등)로 컨테이너를 생성
  2. 애플리케이션을 위한 환경을 설치하고 소스코드 등을 복사해 잘 동작하는 것을 확인
  3. 컨테이너를 이미지로 커밋(commit)

도커는 이러한 일련의 과정을 손쉽게 기록하고 수행할 수 있는 빌드 명령어를 제공하며 이러한 작업을 기록한 파일의 이름을 DockerFile이라 한다.

 

도커 파일


도커 파일 예시

# vi Dokerfile

FROM ubuntu:14.04
MAINTAINER me
LABEL "purpose"="practice"
RUN apt-get update
RUN apt-get install apache2 -y
ADD test.html /var/www/html
WORKDIR /var/www/html
RUN ["/bin/bash", "-c", "echo hello >> test2.html"]
EXPOSE 80
CMD apachectl -DFOREGROUND

 

FROM

생성할 이미지의 베이스가 될 이미지를 뜻한다. FROM 명령어는 반드시 한 번 이상 입력해야 한다.

 

MAINTAINER

이미지를 생성한 개발자의 정보를 나타낸다. 도커 1.13.0 버전 이후로 사용하지 않으며 LABEL로 교체해 표현한다.

 

LABEL

이미지에 메타데이터를 추가한다. 메타데이터는 '키:값'의 형태로 저장되며 여러 개의 메타데이터가 저장될 수 있다. docker inspect 명령어로 이미지의 메타데이터를 확인할 수 있다.

 

RUN

이미지를 만들기 위해 컨테이너 내부에서 명령어를 실행한다. 단 Dockerfile을 이미지로 빌드하는 과정에서는 별도의 입력이 불가능하기 때문에 apt-get install apache2 명령어에서 설치할 것일지를 선택하는 Y/N을 Yes로 설정해야 한다. 이미지를 빌드할 때 별도의 입력을 받아야 하는 RUN이 있다면 빌드를 종료한다.

 

RUN 명령어에 ["/bin/bash", "echo hello >> test2.html"]과 같이 입력하면 배열의 형태처럼 명령어를 실행할 수 있다.
RUN의 경우에는 다음과 같은 형태로 사용된다.
RUN ["실행 가능한 파일", "명령줄 인자 1", "명령줄 인자 2", ... ]

이는 JSON 배열의 입력 형식을 따르기 때문에 JSON 형식과 일치해야 한다.

 

ADD

파일을 이미지에 추가한다. 추가하는 파일은 Dockerfile이 위치한 디렉터리인 컨텍스트(Context)에서 가져온다. 

ADD 명령어는 JSON 배열의 형태로도 사용될 수 있으면 추가할 파일명은 여러 개를 지정할 수 있으며 배열의 마지막 원소가 컨테이너에 추가될 위치이다.

 

WORKDIR

명령어를 실행할 디렉터리를 나타낸다. 배시 셸에서 cd 명령어를 입력하는 것과 같은 기능을 수행한다.

 

EXPOSE

Dockkerfile의 빌드로 생성된 이미지에서 노출할 포트를 설정한다. 하지만 EXPOSE로 포트를 설정했다고 해서 반드시 이 포트가 호스트의 포트와 바인딩되는 것은 아니며 단지 사용할 것임을 나타내는 것뿐이다. 

 

CMD

CMD는 컨테이너가 시작될 때마다 실행할 명령어를 설정하며 Dockerfile에서 한 번만 사용할 수 있다. CMD는 run 명령어의 이미지 이름 뒤에 입력하는 커맨드와 같은 역할을 하지만 docker run 명령어에서 커맨드 명령줄 인자를 입력하면 Dockerfile에서 사용한 CMD의 명령어는 run의 커맨드로 덮어 쓰인다. 

 

Dockerfile 빌드


dockerfile을 작성 후 이미지로 빌드하는 명령어는 docker build 이다.

 

### -t 옵션은 생성될 이미지의 이름을 설정한다
### build 명령어의 끝에는 Dockerfile이 저장된 경로를 입력한다
docker build -t mybuild:0.0 ./

 

기본적으로 Dockerfile이라는 파일을 기반으로 이미지를 생성하지만 -f 혹은 --file 옵션으로 빌드할 Dockerfile의 이름을 지정할 수 있다.

 

빌드된 이미지로 컨테이너를 생성한다.

 

### -P 옵션은 이미지에 설정된 EXPOSE의 모든 포트를 호스트에 연결하다록 설정한다
docker run -d -P --name myserver mybuild:0.0

 

-P 옵션으로 이미지에 설정된 80 포트로 포트 포워딩이 된 컨테이너가 생성되었고 docker ps 또는 docker port 명령어로 컨테이너와 연결된 호스트의 포트를 확인할 수 있다.

 

 

Dockerfile에 이미지의 라벨을 purpose = practice로 설정했으므로 docker images 명령어의 필터에 이 라벨을 적용할 수 있다.

 

docker images --filter "label=purpose=practice"

 

이미지뿐만 아니라 컨테이너에도 메타데이터를 추가할 수 있다. docker run 명령어에 --label 옵션을 사용할 수 있고 docker ps에서 --filter 옵션으로 적용할 수 있다.

 

빌드 컨텍스트


 

이미지 빌드를 시작하면 도커는 가장 먼저 빌드 컨텍스트를 읽어 들인다. 빌드 컨텍스트는 이미지를 생성하는 데 필요한 각종 파일, 소스코드, 메타데이터 등을 담고 있는 디렉터리를 의미하며 Dockerfile이 위치한 디렉터리가 빌드 컨텍스트가 된다

 

컨텍스트는 단순 파일뿐 아니라 하위 디렉터리도 전부 포함하게 되므로 빌드에 불필요한 파일이 없게 해야 한다.

 

이를 방지하기 위해 깃에서 사용하는. gitignore와 유사한 기능이 있는데. dockerignore이다.

 

. dockerignore 파일의 예

# vi .dockerignore
test2.html
*.html
*/*.html
test.htm?

# 예외 파일
*.html
!test*.html

 

Dockerfile의 각 스텝은 이미지 레이어를 생성한다. 따라서 이미지의 빌드가 완료되면 Dockerfile의 명령어 줄 수만큼의 레이어가 존재하게 된다.

 

또한 빌드는 캐시를 이용해 이미지를 빌드한다. 이전에 도커 파일을 빌드할 때 동일한 스텝이 있다면 캐시를 이용해서 더욱 빠르게 이미지로 빌드한다.

 

하지만 가끔 캐시를 사용하고 싶지 않은 스텝이 있을 시 빌드할 때 --no-cahce 옵션을 추가하면 캐시를 사용하지 않는다.

 

멀티 스테이지를 이용한 Dockerfile 빌드

 

멀티 스테이지 빌드는 하나의 Dockerfile 안에 여러 개의 FROM 이미지를 정의함으로써 빌드 완료 시 최종적으로 생성될 이미지의 크기를 줄이는 역할을 한다.

 

# 1. Build Image
FROM golang:1.13 AS builder

# Install dependencies
WORKDIR /go/src/github.com/asashiho/dockertext-greet
RUN go get -d -v github.com/urfave/cli

# Build modules
COPY main.go .
RUN GOOS=linux go build -a -o greet .

# ------------------------------
# 2. Production Image
FROM busybox
WORKDIR /opt/greet/bin

# Deploy modules
COPY --from=builder /go/src/github.com/asashiho/dockertext-greet/ .
ENTRYPOINT ["./greet"]

 

COPY 명령어에서 --from 옵션으로 이전 FROM 이미지에서 빌드한 내용을 두 번째 FROM 이미지에 복사한다.

 

기타 Dockerfile 명령어


ENV

Dockerfile에서 사용될 환경변수를 지정한다. 설정한 환경변수는 ${ENV_NAME} 또는 $ENV_NAME의 형태로 사용할 수 있다. 이 환경변수는 이미지에도 저장이 된다.

 

# vi Dockerfile
FROM ubuntu:14.04
ENV test /home
WORKDIR $test
RUN touch $test/mytouchfile

# 이미지를 빌드하고 컨테이너를 생성해 환경변수를 확인하면 /home 값이 적용되어 있다.
docker run -i -t --name env_test myenv:0.0 /bin/bash
echo $test --> /home

컨테이너를 생성할 때 run 명령어에서 -e 옵션을 사용해 같은 이름의 환경변수를 사용하면 기존의 값이 덮어 쓰인다.

 

docker run -i -t --name env_test_override -e test=myvalue myenv:0.0 /bin/bash
echo $test --> myvalue

 

VOLUME

빌드된 이미지로 컨테이너를 생성했을 때 호스트와 공유할 컨테이너 내부의 디렉터리를 설정한다.

JSON 배열의 형식으로 여러 개를 사용할 수 있다.

 

# vi Dockerfile
FROM ubuntu:14.04
RUN mkdir /home/volume
RUN echo test >> /home/volume/testfile
VOLUME /home/volume

 

이미지를 빌드한 뒤 컨테이너를 생성하면 볼륨이 생성되어 있다. (docker volume ls로 확인)

 

이 볼륨은 컨테이너 내부의 /home/volume 디렉터리를 호스트와 공유한다.

 

ARG

build 명령어를 실행할 때 추가로 입력을 받아 Dockerfile 내에서 사용될 변수의 값을 설정한다. ARG의 값은 기본적으로 build 명령어에서 입력받아야 하지만 default 값도 지정할 수 있다.

 

# vi Dockerfile
FROM ubuntu:14.04
ARG my_arg
ARG my_arg_2=value2
RUN touch ${my_arg}/mytouch

 

해당 Dockerfile로 이미지를 빌드할 때 --build-arg 옵션을 사용해 Dockerfile의 ARG에 값을 입력할 수 있다.

 

docker build --build-arg my_arg=/home -t myarg:0.0 ./

 

ARG와 ENV의 값을 사용하는 방법은 ${}으로 동일하다.

 

ARG로 설정한 변수를 ENV에서 같은 이름으로 재정의하면 --build-arg 옵션에서 설정한 값은 ENV에 의해 덮어 쓰인다.

 

ONBUILD

빌드된 이미지를 기반으로 하는 다른 이미지가 Dockerfile로 생성될 때 실행할 명령어를 추가한다. ONBUILD가 있는 Dockerfile을 실행하면 실행이 안되지만 해당 Dockerfile을 기반으로 하는 이미지가 다른 Dockerfile의 FROM에 있으면 실행이 된다.

 

HEALTHCHECK

말 그대로 컨테이너에서 동작하는 애플리케이션의 상태를 체크한다. 다음 예시는 nginx 애플리케이션의 상태를 체크한다.

 

# vi Dockerfile
FROM nginx
RUN apt-get update -y && apt-get install curl -y
HEALTHCHECK --interval=1m --timetout=3s --retries=3 CMD curl -f http://localhost || exit 1

 

--interval 옵션은 컨테이너의 상태를 체크하는 주기이며 --timeout은 상태를 체크하는 명령어가 설정한 시간을 초과하면 상태 체크에 실패한 것을 간주하며 --retries의 횟수만큼 명령어를 반복한다. --retries 횟수만큼 상태 체크에 실패하면 해당 컨테이너는 unhealthy 상태로 설정된다.

 

ADD / COPY

ADD와 COPY는 로컬 디렉터리에서 읽어 들인 컨텍스트로부터 이미지에 파일을 복사하는 역할을 하는 측면에서는 비슷하다.

 

하지만 ADD는 외부 URL 및 tar 파일에서도 파일을 추가할 수 있다.

 

ENTRYPOINT / CMD

컨테이너를 생성할 때 --entrypoint가 존재한다면 cmd에 설정된 명령어는 단지 entrypoint의 인자의 기능을 한다.

 

### entrypoint 옵션 존재
docker run -it --entrypoint="echo" --name entrypoint_container ubuntu:14.04 /bin/bash
--> /bin/bash

### entrypoint 옵션 제거
docker run -it --name no_entrypoint_container ubuntu:14.04 /bin/bash
--> 컨테이너의 커맨드가 /bin/bash로 실행

 

CMD 또는 ENTRYPOINT는 배열로도 명령어를 실행할 수 있다. 배열로 커맨드를 실행하면 입력된 명령어가 그대로 이미지에서 사용되지만 배열 형태가 아닐 경우 이미지를 생성할 때 CMD와 ENTRYPOIT에 /bin/sh -c가 앞에 자동으로 추가가 된다.

'Docker' 카테고리의 다른 글

도커 스웜  (0) 2021.09.20
도커 데몬 모니터링  (0) 2021.09.18
도커 이미지 관리  (0) 2021.09.11
컨테이너 자원 할당 제한  (0) 2021.09.11
도커 네트워크  (0) 2021.09.11