Skip to content

Dockerfile 작성하기 ​

Dockerfile은 만들고자 하는 Docker 이미지를 빌드하는 데 필요한 모든 명령이 순차적으로 적힌 텍스트 파일입니다. Dockerfile은 정해진 형식과 명령어들로 구성됩니다.

Docker 이미지는 읽기 전용 레이어로 구성되며, 각 레이어는 Dockerfile 명령어를 나타냅니다.

dockerfile
# syntax=docker/dockerfile:1

FROM ubuntu:22.04
COPY . /app
RUN make /app
CMD python /app/app.py

위에서 각 명령어는 하나의 레이어를 생성합니다.

  • FROM은 ubuntu:22.04 Docker 이미지 레이어를 생성합니다.
  • COPY는 Docker 클라이언트의 현재 디렉터리에서 파일을 복사합니다.
  • RUN은 make를 사용하여 앱을 빌드합니다.
  • CMD는 컨테이너 내에서 실행할 명령을 지정합니다.

멀티 스테이지 빌드 ​

멀티 스테이지 빌드(Multi-stage builds)는 Dockerfile을 더 쉽게 유지 관리할 수 있도록 도와주며, Docker 이미지 최적화가 어려운 사용자에게 매우 유용합니다.

멀티 스테이지 빌드에서는 여러개의 FROM문을 사용합니다. 각 FROM 명령어는 서로 다른 기반의 이미지를 사용할 수 있으며, 각 명령어는 각각 새로운 스테이지로 시작됩니다.
한 마디로 여러 스테이지의 빌드 과정이 있는 Dockerfile이 있다면 최종적으로 만들어지는 이미지에는 원하는 것들만 남겨 이미지 용량을 최적화 할 수 있습니다.

다음 Dockerfile에는 바이너리를 빌드하는 첫 번째 스테이지와 만들어진 바이너리를 복사하는 두 번째 스테이지로 구성되어 있습니다.

dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.21
WORKDIR /src
COPY <<EOF ./main.go
package main

import "fmt"

func main() {
  fmt.Println("hello, world")
}
EOF
RUN go build -o /bin/hello ./main.go

FROM scratch
COPY --from=0 /bin/hello /bin/hello
CMD ["/bin/hello"]

Dockerfile만 있으면 됩니다. 별도의 빌드 스크립트 없이 Docker 빌드를 실행하기만 하면 됩니다.

sh
$ docker build -t hello .

최종 결과물은 내부에 바이너리만 있는 작은 Production 이미지 입니다. 앱을 빌드하는 데 필요한 빌드 도구는 결과 이미지에 포함되지 않습니다.

어떻게 작동할까요? 두 번째 FROM 명령어는 scratch 이미지를 바탕으로 새 빌드 스테이지를 시작합니다. COPY --from=0은 이전 스테이지에서 빌드된 결과물만 두 번째 스테이지로 복사합니다. Go SDK를 포함 모든 중간 결과물은 그대로 유지되며 최종 결과물에는 저장되지 않습니다.

빌드 스테이지 별칭 지정 ​

기본적으로 스테이지마다 이름이 지정되지 않으며, 첫 번째 FROM 명령이 있는 스테이지를 0으로 시작하는 정수로 참조할 수 있습니다. 그러나 FROM 명령에 AS <NAME>을 추가하여 스테이지 별칭으로 지정할 수 있습니다. 다음 예에서는 스테이지 별칭을 지정하고 COPY 명령에 별칭을 사용하여 이전 예제를 개선해 보도록 하겠습니다. 즉, 나중에 Dockerfile의 명령어 순서가 바뀌더라도 COPY는 중단되지 않습니다.

dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.21 as build
WORKDIR /src
COPY <<EOF /src/main.go
package main

import "fmt"

func main() {
  fmt.Println("hello, world")
}
EOF
RUN go build -o /bin/hello ./main.go

FROM scratch
COPY --from=build /bin/hello /bin/hello
CMD ["/bin/hello"]

특정 빌드 스테이지에서 중지하기 ​

이미지를 빌드할 때 반드시 모든 스테이지를 포함한 전체 Dockerfile을 빌드할 필요는 없습니다. 대상 빌드 스테이지를 지정할 수 있습니다. 다음 명령은 기존 Dockerfile을 사용하고 있지만 build라는 스테이지에서 중지한다고 가정합니다.

sh
$ docker build --target build -t hello .

이 기능이 유용하게 쓰일 수 있는 다음과 같은 시나리오가 있습니다.

  • 특정 빌드 스테이지 디버깅
  • 모든 디버깅 기호 또는 도구가 활성화된 debug 스테이지와 간결한 Production 스테이지 사용
  • 테스트 데이터로만 이루어진 test 스테이지를 사용하지만 실제 데이터를 사용하는 다른 스테이지를 사용하여 production용으로 빌드하는 경우

외부 이미지를 스테이지로 사용 ​

멀티 스테이지 빌드를 사용하는 경우 Dockerfile에서 이전에 생성한 스테이지로부터 복사하는 것만 가능한 것이 아닙니다. 로컬 이미지 명, 로컬 또는 Docker 레지스트리에서 사용할 수 있는 태그 또는 태그 ID를 사용하여 별도의 이미지로부터 복사하는 COPY --from 명령어를 사용할 수 있습니다.

dockerfile
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

이전 스테이지를 새 스테이지로 사용 ​

FROM 지시문을 사용할 때 이전 스테이지를 참조하여 이전 스테이지에서 정의된 부분에 이어서 시작할 수 있습니다. 다음 예:

dockerfile
# syntax=docker/dockerfile:1

FROM alpine:latest AS builder
RUN apk --no-cache add build-base

FROM builder AS build1
COPY source1.cpp source.cpp
RUN g++ -o /binary source.cpp

FROM builder AS build2
COPY source2.cpp source.cpp
RUN g++ -o /binary source.cpp

Made with VitePress.