도커파일
2.4 Dockefile
2.4.1 이미지를 생성 하는 방법
개발한 애플리케이션을 컨테이너화 핳때 가장 먼저 생각나는 방법은
- 이미지로 커컨테이너 생성
- 환경을 설치 하고 관리
- 컨테이너를 이미지로 커밋
이 방법을 사용하면 애플리케이션이 동작하는 환경을 구성하기 위해 일일 수작업으로 패키지를 설치하고 깃에서 복제하거나 호스트에 복사해야함
이 과정을 간략하기 위해 Dockerfile이라는 파일을 작성함
Dockerfile은 애플리케이션을 개발하는 용도 외에도 여러 목적으로 사용 될 수 있음이미지를 생성하는 방법을 기록해 놓은것이 Dockefile
2.4.2 Dockerfile 작성
앞에서 설명한 것 처럼 Dockerfile에는 컨테이너에서 수행해야 할 작업을 명시해야 함 dockerfile을 정의하기 위해서는 갹종 명령어를 알아 둬야 할 필요가 있음
Dockerfile에서 사용되는 명령어에는 여러가지가 있지만 FROM RUN ADD 등 기초적인 명령어가 있음
# Example Dockerfile
FROM ubuntu:18.04
# 기본 이미지 우분투
MAINTAINER jaehyunL
# 컨테이너 제작자
LABEL "purpose"="pracice"
# 라벨
RUN apt-get update
# 시행 되는 명령
ADD test.html /var/www/html
# 파일을 추가 해줌
WORKDIR /var/www/html
# 동작하는 디렉터리
RUN ["bin/bash", "-c", "echo hello >> test2.html"]
# 도커파일이 시작 ㅈ돌때 실행하는 명령
EXPOSE 80
# 80포트 바인딩
CMD appachctl -DFOREGROUND
- FROM: 생성할 이미지의 베이스가 돨 이미지를 뜻함
- MAINTAINER: 이미지를 생성한 개발자의 정보를 나타냄
- LALBEL: 이미지를 생성한 개발자의 정보를 나타냄
- RUN: 이미지를 만들기 위해 컨테이너 내부에서 명령어를 실행 함
- ADD: 파일을 이미지에 추가함 추가한 파일은 Dockefile이 위치한 디렉터리인 컨텍스트에서 가져 옴
- WORKDIR: 명령어를 싫애할 디렉터리
- EXPOSE: 노출할 ㅗ포트를 설정
- CMD: 컨테이너가 시작할때마다 수행되는 명령어
2.4.3 Dockerfile 빌드
2.4.3.1 이미지 생성
docker buid -t mybuild:0.0 ./
# 작성된 기준으로 도커파일을 빌드함
해당 도커파일을 기준으로 빌드함 빌드된 내용은 docker image 에 mybuild:0.0 이라는 명칭으로 저장돰
docker run -d -p --name myserver mybuild:0.0
# 이미지를 컨테이너로 실행함
2.4.3.2 빌드 과정 살펴보기
이미지 빌드를 시작하면 도커는 가장 먼저 빌드 컨텍스트를 읽어 들입니다. 빌드 컨텍스트는 이미지를 생성하는데 필요한 각종 파일, 소스코드, 메타데이터 등을 담고 있는 디렉터리를 의미함
빌드 컨텍스트는 Dockerfile에서 빌드될 이미지에 파일을 추가할 때 사용됨 Dockerfile에서 이미지에 파일을 추가하는 방법은 앞에서 설명한 ADD 외에도 COPY가 있는데 이 명령어들을 빌드 컨텍스트의 파일을 이미지에 추가 함 위 예제에서는 빌드 경로를 ./로 지정함으로써 test.html 파일을 빌드 ㅋ컨텍스트에 추가했으며, ADD 명령어를 통해 빌드 컨텍스트에서 test.html 파일을 이미지에 추가 함 .
컨텍스트는 build 명령어의 맨 마지막에 지정된 위치에 있는 파일을 전부 포함함 git과 같은 외부 URL에서 Dockerfile을 읽어 들인다면 해당 저장소에 있는 파일과 서브 모듈을 포함함. 따라서 Dockerfile이 위치한 곳에는 이미지 빌드에 필요한 파일만 있는 것이 바람직함
불필요한 파일을 빌드를 방지하기 위해서는 .dokerignore라는 파일을 작성하면 빌드 시 이 파일에 명시된 이름의 파일을 컨텍스트에서 제외함.
.dockerignore 파일의 예
test.html
*.html
test.htm?
Dockerfile을 이용한 컨테이너 생성과 커밋
build 명령어는 Dockerfile에 기록된 대로 컨테이너를 실행한 뒤 완성된 이미지를 만들어 냄 그렇지만 이미지로 만드는 과정이 하나의 컨테이너에서 일어나는 것은 아님
ADD, RUN 등의 명령어가 실행 될 때마다 새로운 컨테이너가 하나씩 생성되며 이를 이미지로 커밋합니다. 즉, Dockerfile에서 명령어 한 줄이 실행될 때마다 이전 Step에서 생성된 이미지에 의해 새로운 컨테이너가 생성되며, Dockerfile에 적힌 명령어를 수행하고 다시 새로운 이미지 레이어로 저장됨
캐시를 이용한 이미지 빌드
한 번 이미지를 마치고 난 뒤 다시 같은 빌드를 진행하면 이전의 이미지 빌드에서 사용했던 캐시를 사용함
Dockefile 빌드시 -f 옵션으로 도커파일 이름을 지정 함
docker build -f Dockerfile2 -f mycache:0.0 .
Using Cache라는 풀력 내용이 있으면 빌드 과정이 진행 되지 않고 바로 이미지가 생성 됬음을 알 수 있음 같은 명령 줄까지 이전에 사용한 이미지 레이어를 활용해 이미지를 생성함 이는 같은 명령어를 여러 번 실행해야 하는 여러 개의 이미지를 빌드하거나 빌드 도중 Dockerfile의 문법과 기타 오류가 발생했을 때 불필요하게 다시 명령어를 실행하지 않게 함
이미지 빌드 중 오류가 발생했을 때는 build 명령어가 중지되며, 이미지 레이어 생성을 위해 마지막으로 생성된 임시 컨테이너가 삭제되지 않은채로 남게 됨
하지만 도커 캐시 기능이 너무 과한 나머지 필요하지 않을때도 존재함 이럴떄는 —no-cache 명령어를 사용해 기능을 해제 할 수 있음
docker build —no-cache -t mybuild:0.0 .
2.4.3.3 멀티 스테이지를 이용한 Dockerfile 빌드하기
일반적으로 애플리케이션을 빌드할 떄는 많은 의존성 패키지와 라이브러를 필요함 Dockerfile에서 Go소스코드를 빌드하기 위해서 가장 먼저 생각나는 방법은 아래의 Dockerfile처럼 Go와 관련된 도구들이 미리 설치돈 이미지를 FROM에 명시한 뒤, RUN 명령어로 소스코드를 컴파일 하는 것
이 때 필요 이상으로 이미지의 크기가 설정됨 이를 방지하기 위해서 멀티스테이지 빌드 방법을 사용할 수 있음
Dockerfile에서 빌드된 이미지와 동일한 역할을 하지만 멀티스테이지 빌드를 사용해 이미지를 빌드하는 예시를 살펴봄
FROM golang
ADD 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"]
일반적인 Dockerfile과 다르게 2개의 FROM을 통해 2개의 이미지가 명시되었습니다. 첫 번 째 FROM에 명시된 golang 이미지는 이전과 동일하게 main.go 파일을 /root/mainAPP으로 빌드하였슴 그러나 두 번째 FROM 아래에서 사용된 COPY 명령어는 첫 번째 FROM에서 사용된 이미지의 최종 상태에 존재하는 /root/mainAPP 파일을 두번째 이미지인 alpine:latest 에 복사합니다. 이 때, —from=0 첫 번째 FROM 에서 빌드된 이미지의 최종 상태를 의미합니다.
alpine이나 busybox와 같은 이미지는 우분투나 CentOS에 비해 이미지 크기가 매우 작지만 기본적인 프로그램 실행에 필요한 필수적인 런타임 요소가 포함되어 있는 리눅스 배포판 이미지임 이러한 이미지를 활용하면 경량화된 애플리케이션 이미지를 간단히 생성할 수 있음
멀티 스테이지 빌드를 사용하는 Dockerfile은 2개 이상의 이미지를 사용할 수 있으며, 각 이미지는 먼저 FROM에서 명시된 순서대로 0, 1.. 의 순으로 차례대로 구분되어 사용됨
FROM golang
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go
FROM golang
ADD main2.go /root
WORKDIR /root
RUN go build -o /root/mainApp2 /root/maoin2.go
FROM alpine:latest
WORKDIR /root
COPY --from=0 /root/mainApp .
COPY --from=1 /root/mainApp2 .
또는 특정 단계의 이미지에 별도의 일므을 정의해 사용할 수 있습니다. 아래는 첫 번쨰 단계의 최종 이미지에 빌더라는 이름을 붙여 사용한 예시
FROM golang as builder
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go
FROM alpine:latest
WORKDIR /root
COPY --from=builder /root/mainApp .
CMD ["./mainApp"]
2.4.4 기타 Dockerfile 명령어
2.4.4.1 ENV, VOLUME, ARG, USER
- ENV: 도커파일에서 사용될 환경변수를 지정함
- VOLUEM: 빌드된 이미지로 컨테이너 생성했을 때 호스트와 공유할 컨테이너 내부의 디렉터리를 설정함
- ARG: 빌드 명령어를 실행할 때 추가로 입력을 받아 Dockerfile 내에서 사용될 변수의 값을 설정 함
- USER: USER로 컨테이너 내에서 사용될 사용자 계정의 이름이나 UID를 설정함
2.4.4.2 Onbuild, Stopsignal, Healthchek, Shell
- ONBUILD: 빌드된 이미지를 기반으로 하는 다른 이미지가 Dockerfile로 생성돨 때 실행할 명령어를 추가 함
- STOPSIGNAL: 컨테이너가 정지될 때 사용될 시스템 콜의 종류를 지정함. 아무것도 설정하지 않으면 기본적으로 SIGTEMR으로 서정되지만 Dockerfile에 STOPSIGNAL을 정의해 컨테이너가 종료되는데 사용될 신호를 선택할 수 있다.
- HEALTHCHECK: 이미지로 부터 생성된 컨테이너에서 동작하는 애플리케이션의 상태를 체크하도록 설정 함
- SHELL: 뒤에서 다시 설명하겠지만 Dockerfile에서 기본적으로 사용하는 셸은 리눅스에서 명령어를 수행함
2.4.4.3 ADD, COPY
COPY는 로컬 디렉터리에서 읽어 들인 컨텍스트로부터 이미지에 파일을 복사하는 역할을 함
ADD는 외부 URL 및 tar 파일에서 파일을 추가할 수 있는 점에서 다름
2.4.4.4 ENTRYPOINT, CMD
ENTRYPOINT 는 커맨드와 동이랗게 컨테이너가 시작될 때 수행할 명령을 지정한다는 점에서 같지만 커맨드 인자로 받아 사용할 수 있는 스크립트의 역할을 한다는 점에서 차이가 있음 EX) ENTRYPOINT[”/bin/bash”, “/entrypoint.sh”]
2.4.5 Dockerfile로 빌드할 때 주의할 점
Dockerfile을 사용하는데도 좋은 습관이 있음
- 문단을 나눌때는 \ 로 나눠 가독성을 높임
- RUN 명령 수행시 && 연산으로 이미지의 크기를 줄임
- export, import 를 사용해 이미지의 크기를 줄임