Dockerfile

chris·2022년 12월 10일
0

dokcer

목록 보기
2/2
post-thumbnail

Image를 생성하는 방법


1. 아무것도 없는 이미지(ubuntu, CentOS etc.)로 컨테이너 생성
2. Application을 위한 환경을 설치하고 소스코드 등을 복사해 잘 동작하는 것을 확인
3. Container를 이미지로 Commit

이 방법을 사용하면 Application이 동작하는 환경을 구성하기 위해 일일이 수작업으로 패키지를 설치하고 소스코드를 Git에서 Clone하거나 Host에서 복사해야 한다.


Docker는 위와 같이 일련의 과정을 손쉽게 기록하고 수행할 수 있는 Build 명령어를 제공한다.
완성된 Image를 생성하기 위해 Container에 설치해야 하는 패키지, 추가해야 하는 소스코드, 실행해야 하는 명령어와 Shell Script 등을 하나의 파일에 기롷해 두면 도커는 이 파일을 읽어 컨테이너에서 작업을 수행한 뒤 Image로 만든다.

이러한 작업을 기록한 파일을 Dockerfile이라고 한다.


Dockerfile 작성

Dockerfile은 한 줄이 하나의 명령어가 되고, 명령어를 명시한 뒤에 옵션을 추가하는 방식이다.
명령어를 소문자로 표기해도 상관은 없지만 일반적으로 대문자로 표기한다.

명령어

FROM

생성할 Image의 Base가 될 Image를 선언한다. From 명령어는 Dockerfile을 작성할 때 반드시 한 번 이상 사용된다.

FROM ubuntu:22.04
...

LABEL

Image에 metadata를 추가한다. Metadata는 key:value 형태로 저장되며, 여러 개의 Metadata가 저장될 수 있다.

LABEL maintaner "chris han"

RUN

Image를 만들기 위해 Container 내부에서 명령어를 싱행한다.
이때 주의할 점은 Dockerfile을 Image로 빌드하는 과정에서는 별도의 입력이 불가능하기 때문에 apt-get install apache2와 같은 명령어를 사용할 때 Y/N을 Yes로 설정해야 한다. Image를 빌드할 때 별도의 입력을 받아야 하는 RUN이 있다면 build 명령어는 이를 오류로 간주하고 빌드를 종료한다.

ADD

파일을 Image에 추가한다. 추가하는 파일은 Dockerfile이 위치한 디렉터리인 Conext에서 가져온다.
ADD 명령어는 JSON 배열의 형태로 ["source", ... "dest"]와 같이 사용할 수 있다. 추가할 파일명은 여러 개를 지정할 수 있으며 배열의 마지막 원소가 컨테이너에 추가될 위치이다.

...
ADD file1 /var/www/html/
ADD file2 /var/www/html/
...
OR
ADD ["file1", "file2", ..., "/var/www/html/"]
...

COPY

COPY는 Local Directory에서 읽어 들인 Context로부터 이미지에 파일을 복사한다. 사용방법은 ADD와 같다.
COPY와 ADD의 다른 점은, COPY는 Local의 파일만 Image에 추가할 수 있지만 ADD는 외부 URL 및 tar 파일에서도 파일을 추가할 수 있다.

WORKDIR

명령어를 실행할 Directory를 선언한다. Bash shell에서 cd명령어를 사용하는 것과 같은 기능이다.
예를 들어 WORKDIR을 /var/www/html로 선언하고 RUN touch test를 실행하면 /var/www/html/ Directory에 test파일이 생성된다. WORKDIR을 여러번 사용하면 cd명령어를 여러번 사용한 것과 같다.

WORKDIR /var
WORKDIR www/html

위 내용은 다음 내용과 같다.

WORKDIR /var/www/html

EXPOSE

Dockerfile의 빌드로 생성된 이미지에서 노출할 포트를 선언한다. EXPOSE를 설정한 이미지로 컨테이너를 생성했다고 해서 반드시 이 포트가 Host의 포트와 바인딩되는 것은 아니며 단지 컨테이너의 80번 포트를 사용할 것임을 나타내는 것 뿐이다.

ENV

Dockerfile에서 사용될 환경변수를 지정한다. 설정한 환경변수는 ${ENV_NAME} 또는 $ENV_NAME 형태로 사용할 수 있다. 이 환경변수는 Dockerfile뿐 아니라 Image에도 저장되므로 빌드된 이미지로 컨테이너를 생성하면 환경변수를 사용할 수 있다.

# 다음은 con_str이라는 환경변수에 "Server=..." 값을 설정한다.
ENV con_str "Server=..."

ARG

build 명령어를 실행할 때 추가로 입력을 받아 Dockerfile 내에서 사용될 변수의 값을 설정한다.

# vi Dockerfile
FROM ubuntu:22.04

ARG my_arg

RUN touch ${my_arg}/my_touch

위 내용을 Dockerfile로 저장한 뒤 이미지를 빌드한다. build 명령어를 실행할 때 --build-arg 옵션을 사용해 Dockerfile의 ARG에 값을 입력할 수 있다.

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

ARGENV의 값을 사용하는 방법은 ${}로 같으므로 Dockerfile에서 ARG로 설정한 변수를 ENV에서 같은 이름으로 다시 정의하면 --build-arg 옵션에서 설정하는 값은 ENV에 의해 덮어쓰여진다.

USER

USER로 컨테이너 내에서 사용될 사용자 계정의 이름이나 UID를 설정하면 그 아래의 명령어는 해당 사용자 권한으로 실행된다. 일반적으로 RUN으로 사용자의 그룹과 계정을 생성한 뒤 사용한다. root 권한이 필요하지 않다면 USER를 사용하는 것을 권장한다.

RUN groupadd -r author && useradd -r -g aothor chris
USER chris

CMD

CMD는 컨테이너가 시작될 때 시랳ㅇ할 명령어를 설정한다.

CMD ["/bin/bash"]

ENTRYPOINT

ENTRYPOINT도 CMD와 동일하게 컨테이너가 시작될 때 수행할 명령을 지정한다.
다른점은 ENTRYPOINT는 CMD를 인자로 받아 사용할 수 있는 스크립트의 역할을 할 수 있는 것이다.

ENTRYPOINT ["dotnet", "main.dll"]

JSON 배열 형태와 일반 형식의 차이점

JSON 배열 형태가 아닌 CMD와 ENTRYPOINT를 사용하면 실제로 이미지를 생성할 때 cmd와 entrypoint에 /bin/sh -c가 앞에 추가된다.

CMD echo test
# -> /bin/sh -c echo test

ENTRYPOINT /entrypoint.sh
# -> /bin/sh -c /entrypoint.sh

반면에 JSON 배열 형태를 사용하면 다음과 같다.

CMD ["echo", "test"]
# -> echo test

ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
# -> /bin/bash /entrypoint.sh

Multistage build

일반적으로 Application을 빌드 할 때는 많은 의존성 패키지와 라이브러리를 필요로 한다.
예를 들어, Go로 작성된 소스코드를 빌드하기 위해서는 Go와 관련된 빌드 툴과 라이브러리가 미리 설치되어 있어야 한다.
하지만 이는 단지 빌드에 필요한 자원일 뿐 Application을 배포해서 사용하는데는 사용되지 않는다.
최종 이미지 사이즈를 줄이기 위해서 Multistage build 방법을 사용할 수 있다.

FROM golang

COPY main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go

FROM alpine:latest
WORKDIR /root
COPY --from=0 /root/mainApp .
CMD ["./mainApp"]

--from=0은 첫 번째 FROM에서 빌드된 이미지의 최종 상태를 의미한다.

profile
software engineer

0개의 댓글