Docker Multi Stage build
: 도커 멀티 스테이지 빌드란 하나의 Dockerfile 안에서 빌드(컴파일) 환경과 실행 환경을 분리하여 최종 이미지를 최적화하는 기술입니다.
작동 방식
: 하나의 Dockerfile 안에 FROM 명령어를 여러 번 사용하여 여러 스테이지를 구성합니다.
- 빌드 스테이지 (작업실 ): 첫 번째 FROM문으로 시작하며, 소스 코드를 컴파일하는 데 필요한 모든 도구(컴파일러, SDK 등)가 설치된 무거운 이미지를 사용합니다. 여기서 애플리케이션을 빌드하여 실행 파일을 만듭니다.
- 최종 스테이지 (배송 상자 ): 두 번째 FROM문으로 시작하며, scratch나 alpine 같은 초경량 이미지를 기반으로 합니다. 그런 다음 COPY --from=[빌드 스테이지 이름] 명령을 사용하여 첫 번째 스테이지에서 만들어진 실행 파일만 복사해 옵니다.
이렇게 하면 빌드에만 필요했던 무거운 도구와 라이브러리는 최종 이미지에 포함되지 않습니다.
# 예시 Dockerfile
# stage 1 : 빌드 환경
FROM ubuntu:22.04 AS build-image
RUN apt-get update && apt-get install -y gcc
COPY src/hello.c /tmp
WORKDIR /tmp
RUN gcc -o hello-world hello.c
CMD ["/tmp/hello-world"]
# stage 2 : 이미지 생성
FROM scratch AS runtime-image
COPY --from=build-image /tmp/hello-world .
CMD ["./hello-world"]
Stage 1: "작업실" - 빌드 환경
- 목적: 소프트웨어를 컴파일하거나 빌드하기 위한 모든 도구를 갖춘 환경입니다.
- 베이스 이미지: ubuntu, debian, golang, node 등 필요한 컴파일러, 라이브러리, 빌드 도구가 포함된 무거운 전체 운영체제를 사용합니다.
- 역할: 이 스테이지는 오직 최종 실행 파일을 만들어 내는 역할만 하고, 빌드가 끝나면 이 환경 전체는 버려집니다.
Stage 2: "제품" - 최종 실행 환경
- 목적: 빌드된 애플리케이션을 '실행'만 시키기 위한 최소한의 환경입니다.
- 베이스 이미지: scratch (완전히 비어있는 이미지), alpine (초경량 리눅스), 또는 distroless (언어 런타임만 포함된 이미지)처럼 극도로 가벼운 이미지를 사용합니다.
- 역할: COPY --from=[Stage 1 이름] 명령을 사용해 "작업실"에서 만들어진 최종 결과물(실행 파일)만 가져와 담습니다. 작업실에 있던 무거운 도구들이나 소스 코드는 일절 포함하지 않습니다.
도커 Multi Stage build를 왜 할까?
- 최종 이미지 크기 최소화: 최종 이미지는 수백 MB가 아닌 수 MB 수준으로 극단적으로 작아집니다.
- 보안 강화: 셸(shell), 패키지 매니저(apt, yum) 등 불필요한 도구가 전혀 없으므로 공격 표면(Attack Surface)이 획기적으로 줄어듭니다.
- 배포 및 관리 효율성: 이미지가 작아 레지스트리에 푸시하고 클러스터에서 풀(pull)하는 속도가 매우 빨라집니다.
* 공격 표면(Attack Surface)이 획기적으로 줄어듭니다.
: 해커가 공격할 수 있는 방법이나 통로의 수를 줄인다는 의미입니다. Docker 이미지에서 불필요한 프로그램(셸, 네트워크 도구 등)을 모두 제거하면, 해커가 이용할 수 있는 보안 취약점(문과 창문) 자체가 사라져서 훨씬 안전해집니다.