본문 바로가기

Docker/Docker (도커)

Dockerfile 표준화 하기

# Dockerfile 표준화 작업 진행

Dockerfile 작성 레퍼런스 사이트 : https://docs.docker.com/engine/reference/builder/

 

Dockerfile reference

 

docs.docker.com

1. Dockerfile 작성 시 기본 명령어는 아래와 같다.

명령설명

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

2. Dockerfile에서 주석 사용방법

# 이것은 첫번째 주석입니다
명령 인수

# 이것은 두번째 주석입니다
명령 인수  # 이것도 주석입니다

3. Dockerfile 작성

Dockerfile에는 Docker 컨테이너를 어떤 Docker 이미지로부터 생성할지 정보를 반드시 기술 해야한다. 

이 이미지를 베이스 이미지라고 할 수 있다.

FROM 명령 (베이스 이미지 정보를 기술)

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

Docker image란 컴퓨터의 CD와도 같다고 볼 수 있다. 그래서 Docker image는 수정 할 수 없다. 단 이미지에 추가로 무언가를 추가 할 수는 있다.

Docker image는 레이어 구조로 되어 있고, 즉 기본이 되는 레이어가 존재하고, 그 기본 레이어에 계속해서 추가하는 방식으로 이미지를 생성 한다.

Docker image를 조회하는 명령어는 아래와 같다.

docker inspect {이미지 이름}

4. zulu-open-zdk:13을 베이스 이미지로 한 Dockerfile

태그명을 입력하지 않으면 베이스 이미지의 최신 버전(latest)이 적용된다.
이미지명이나 태그명은 작성자가 임의의 값을 붙일 수 있으므로 Dockerfile을 수정해도 똑같은 이름으로 몇 번이든 이미지를 만들 수 있다.

# 베이스 이미지 설정
FROM azul/zulu-openjdk:13

다이제스트 확인

다이제스트는 Docker Hub에 업로드하면 자동으로 부여되는 식별자를 말함
이 다이제스트는 고유한 식별자이기 때문에 이미지를 고유하게 지정할 수 있음

docker image ls --digests azul/zulu-openjdk

다이제스트를 지정한 Dockerfile

FROM azul/zulu-openjdk@sha256:12945255963826437ca7c52f2ffe45b6862b24b4b73dfb74af05d461607f75ac

Dockerfile의 빌드와 이미지 레이어

Dockerfile로 부터 이미지를 생성하려면 docker build 명령을 사용한다.

docker build 명령의 서식

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

docker build 명령의 실행 예

Dockerfile로 부터 sample 이라는 이미지를 작성 태그명: 1.0, Dockerfile의 저장 위치를 절대 경로로 지정 

/home/docker/sample 물론 상대경로로 지정할 수도 있다.

docker build -t sample:1.0 /home/docker/sample

이미지 확인하는 명령어는 아래와 같다.

docker image ls

새로운 이미지의 작성 예시 → 생성할 이름은 다르지만 동일한 이미지가 생성된다.

docker build -t sample:2.0 /home/docker/sample

파일명을 지정한 docker build 명령 실행

현재 디렉토리에 있는 Dockerfile.base라는 이름의 파일을 -f 옵션으로 지정하여 build
파일명이 Dockerfile 이외의 이름인 경우는 Docker Hub에서 이미지의 자동 생성 기능을 사용할 수 없음

docker build -t sample -f Dockerfile.base .

표준 입력에서의 빌드

표준 입력을 경유하여 Dockerfile을 지정하여 빌드를 할 수도 있음
표준 입력의 내용은 Dockerfile의 내용을 docker build 명령의 인수로 전달하므로 -(하이픈)을 지정한다.

docker build - < Dockerfile

압축 아카이브를 활용하여 빌드를 수행 할 수도 있다.

표준 입력에서의 빌드: 빌드에 필요한 파일을 포함시킬 수 없기 때문에 Dockerfile과 빌드에 필요한 파일을 tar로 모아두고 표준 입력에서 지정함

docker build - < docker.tar.gz

중간 이미지의 재이용

Docker는 이미지를 빌드할 때 자동으로 중간 이미지를 생성하고, 해당 이미지를 다른 이름으로 빌드할 때 중간 이미지를 내부적으로 재이용함으로써 빌드를 고속으로 수행함, 이미지를 재이용하고 있을 때는 빌드 로그에 'Using cache' 라고 표시된다.

이 캐시를 이용하고 싶지 않을 경우는 docker build 명령에서 --no-cache 옵션을 지정하여 빌드를 수행 한다.

Docker 이미지의 레이어 구조

4개의 명령을 갖고 있는 Dockerfile의 예

Dockerfile과 동일한 디렉토리에 임의의 'index.html' 이라는 이름의 파일을 생성하고 docker build 명령으로 이미지를 작성하면
각 레이어마다 이미지가 생성되고 네개의 이미지가 생성된다.

# STEP:1 Ubuntu (베이스 이미지)
FROM ubuntu:latest

# STEP:2 Nginx 설치
RUN apt-get update && apt-get install -y -q nginx

# STEP:3 파일 복사
COPY index.html /usr/share/nginx/html/

# STEP:4 Nginx 시작
CMD ["nginx", "-g", "daemon off;"]

멀티스테이지 빌드를 사용한 Dockerfile 만들기

Sample 앱

git clone https://github.com/asashiho/dockertext2
cd dockertext2/chap05/multi-stage/

Dockerfile 작성 예시

  1. 개발 환경용 Docker 이미지
  • 개발용 언어 Go 버전 1.8.4를 베이스 이미지로 작성 후 builder 라는 별명을 붙임
# 1. Build Image
FROM golang:1.8.4-jessie AS builder
  • 개발에 필요한 버전을 설치하여 로컬 환경에 있는 소스코드를 컨테이너 안으로 복사함
# Install dependencies
WORKDIR /go/src/github.com/asashiho/greet
RUN go get -d -v github.com/urfave/cli
  • 소스코드를 go build 명령으로 빌드하여 greet 라는 이름의 실행 가능 바이너리 파일을 작성
# build modules
COPY main.go .
RUN GOOS=linux go build -a -o greet .
  1. 제품 환경용 Docker 이미지
  • 베이스 이미지는 busybox(기본적인 Linux 명령들을 하나의 파일로 모아 놓은 것, 최소한으로 필요한 Linux 쉘 환경 제공)를 사용
# 2. Production Image
FROM busybox
WORKDIR /opt/greet/bin
  • 개발용 환경의 Docker 이미지로 빌드한 greet라는 이름의 실행 가능 바이너리 파일을 제품 환경용 Docker 이미지로 복사 
    --from 옵션을 사용하여 builder 라는 이름의 이미지로 부터 복사 한다는 것을 선언
# Deploy modules
COPY --from=builder /go/src/github.com/asashiho/greet/ .
  • 복사한 실행 가능 바이너리 파일을 실행하는 명령 작성
ENTRYPOINT ["./greet"]

전체 dockerfile 코드

# 1. Build Image
FROM golang:1.8.4-jessie AS builder

# Install dependencies
WORKDIR /go/src/github.com/asashiho/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/greet/ .
ENTRYPOINT ["./greet"]

생성한 이미지 확인

개발 환경용 이미지인 goland:1.8.4-jessie는 803MB 지만 제품 환경용 greet 는 겨우 6.02MB으로 빌드 되었다.
제품 환경용 베이스 이미지인 busybox 의 1.22MB에 애플리케이션의 실행에 필요한 모듈만을 추가한 정도임
제품 환경에서는 부하에 따라 작동하는 컨테이너의 수가 바뀜
가능한 한 용량이 적은 이미지를 사용하면 시스템 전체의 컴퓨팅 리소스를 효율적으로 활용할 수 있음

docker image ls

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
greet               latest              56b7008ab820        41 seconds ago      6.02MB
busybox             latest              83aa35aa1c79        6 days ago          1.22MB
golang              1.13                3a7408f53f79        2 weeks ago         803MB

Docker 컨테이너 실행

Sample 앱은 인수를 사용하여 인사를 반환하는 간단한 커맨드라인 툴이지만
제품 환경용으로 만든 저용량 이미지인 greet만으로 작동하고 있다는 것을 알 수 있음

docker container run -it --rm greet asa
Hello asa

docker container run -it --rm greet --lang=es asa
Hola asa

실행중인 docker 프로세스 확인

sudo docker ps -a
:~$ sudo docker ps -a
CONTAINER ID   IMAGE          COMMAND                CREATED       STATUS       PORTS                                       NAMES
184bf0f54ed2   notice-board   "java -jar /app.jar"   9 hours ago   Up 9 hours   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   notice-board