광고 차단 프로그램이 감지되었습니다

이 사이트는 광고 수익을 통해 무료로 콘텐츠와 서비스를 제공하고 있습니다.

더 나은 서비스를 위해 광고 차단 프로그램을 비활성화 해주세요.

광고 차단 해제 방법 보기
Loading...

Docker 멀티스테이지 빌드 & --target

Docker로 Node.js 앱을 빌드할 때 개발 의존성, 빌드 도구, 테스트 라이브러리까지 모두 포함된 무거운 이미지(수백 MB~1GB 이상)가 만들어집니다. 실제 배포에는 nginx와 빌드된 정적 파일만 필요한데, 불필요한 것들이 함께 패키징되어 배포 속도가 느리고 보안 취약점도 증가합니다.

핵심 쟁점:

빌드 환경과 실행 환경을 어떻게 분리할 것인가

CI/CD에서 테스트만 실행하고 싶을 때 전체 빌드를 돌려야 하는가

팀원들이 각자 다른 방식으로 Dockerfile을 작성해 일관성이 없음

이미지 크기가 커서 배포 시간이 오래 걸림(3~10분)

예상 vs 현실: "Dockerfile 하나면 되겠지"라고 생각했지만, 실제로는 개발/테스트/프로덕션 환경마다 다른 이미지가 필요하고, 각각 별도 Dockerfile을 관리하다 보니 중복 코드와 유지보수 부담이 커집니다.

영향 범위:

빌드 시간 증가: 매 커밋마다 5분 이상 소요

스토리지 비용: 이미지 하나당 500MB~1GB, 레지스트리 비용 증가

배포 지연: 큰 이미지로 인한 다운로드 시간 증가

보안 리스크: 불필요한 패키지로 인한 취약점 노출 증가🔍 원인 투시근본 원인: 전통적인 단일 스테이지 Dockerfile은 "빌드에 필요한 모든 것"과 "실행에 필요한 것"을 구분하지 않습니다. Node.js 개발자는 npm install로 수백 개의 패키지를 설치하지만, 최종 배포에는 빌드된 HTML/JS/CSS 파일과 웹서버만 있으면 됩니다.

인과 흐름:

단일 FROM → 모든 도구 설치 → 소스 복사 → 빌드 실행 → 빌드 산출물과 도구가 모두 이미지에 남음

이미지 크기 증가 → 레지스트리 푸시/풀 시간 증가 → CI/CD 파이프라인 병목

불필요한 패키지 포함 → 보안 스캔에서 취약점 경고 → 패치 부담 증가

공감 사례:

"npm install만 해도 300MB인데 실제 빌드된 파일은 10MB밖에 안 돼요"

"테스트만 돌리고 싶은데 왜 프로덕션 이미지까지 빌드해야 하죠?"

"Dockerfile이 3개나 되는데 설정 하나 바꾸려면 다 수정해야 해요"

숨겨진 요인: 많은 개발자가 Docker 이미지를 "실행 환경"이 아니라 "개발 환경"처럼 생각합니다. 로컬에서 편한 것이 프로덕션에서도 좋다고 착각하지만, 실제로는 최소한의 구성만 포함해야 안전하고 빠릅니다.🛠️ 해결 설계도1. 멀티스테이지 Dockerfile 기본 구조 만들기핵심 행동: 기존 단일 FROM을 여러 개의 FROM으로 분리하여 빌드 스테이지와 실행 스테이지 구분하기

실행 가이드:

# Before (단일 스테이지 - 문제 있음)
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]

# After (멀티 스테이지 - 최적화됨)
# 1단계: 빌드 스테이지 (AS로 이름 지정)
FROM node:14-alpine AS builder
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build

# 2단계: 실행 스테이지 (경량 이미지 사용)
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

# 변화 포인트:
# - 이미지 크기: 800MB → 23MB (97% 감소)
# - builder 스테이지의 node_modules는 최종 이미지에 포함되지 않음
# - nginx만 실행 환경에 존재

성공 지표:

docker images 명령으로 최종 이미지 크기가 50MB 이하

빌드된 정적 파일만 nginx 이미지에 존재

docker history로 레이어 확인 시 node 관련 레이어가 없음실수 방지·용기 팁:

AS 키워드를 빼먹으면 --target을 쓸 수 없으니 항상 첫 번째 스테이지부터 이름 지정

alpine 이미지를 사용하면 크기를 더 줄일 수 있음

완벽하지 않아도 됩니다. 일단 두 단계로 나누는 것만으로도 큰 개선입니다2. --target 옵션으로 선택적 빌드 구현핵심 행동: 테스트/개발/프로덕션 환경에 맞게 필요한 스테이지까지만 빌드하기

실행 가이드:

# 3단계 멀티스테이지 Dockerfile
FROM node:14-alpine AS dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM dependencies AS builder
COPY . .
RUN npm run build

FROM dependencies AS tester
COPY . .
RUN npm run test

FROM nginx:alpine AS production
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

# 사용 명령어:
# 1. 테스트만 실행
docker build --target tester -t myapp:test .

# 2. 빌드까지만 (nginx 없이)
docker build --target builder -t myapp:build .

# 3. 전체 프로덕션 이미지
docker build -t myapp:prod .

성공 지표:

CI/CD에서 테스트 단계와 배포 단계가 분리됨

--target tester 빌드는 30초 이내 완료

테스트 실패 시 프로덕션 이미지가 생성되지 않음실수 방지·용기 팁:

--target 뒤에는 반드시 AS로 지정한 이름을 써야 함 (숫자 인덱스 사용 불가)

스테이지 순서가 중요: 자주 변경되는 코드는 뒤쪽 스테이지에 배치

각 스테이지 이름은 명확하게: build1, build2보다 dependencies, builder, tester처럼 목적이 드러나게3. CI/CD 파이프라인 통합핵심 행동: GitHub Actions, GitLab CI 등에서 단계별 빌드 자동화

실행 가이드:

# .github/workflows/docker-build.yml
name: Docker Build & Test

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run tests in Docker
        run: |
          docker build --target tester -t myapp:test .
          # 테스트 실패 시 여기서 중단됨
  
  build-and-push:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build production image
        run: docker build -t myapp:prod .
      - name: Push to registry
        run: docker push myapp:prod

# 변화 포인트:
# - 테스트 실패 시 배포 단계로 진행 안 됨
# - 각 단계가 독립적으로 실행되어 병렬 처리 가능
# - 빌드 시간 단축: 전체 7분 → 테스트 2분 + 빌드 3분 (병렬 실행 시 3분)

성공 지표:

PR마다 자동으로 테스트 실행

테스트 통과한 커밋만 프로덕션 이미지 생성

CI/CD 전체 실행 시간이 50% 이상 단축실수 방지·용기 팁:

needs 키워드로 의존성 명확히 설정

캐시 활용: GitHub Actions의 docker/build-push-action 사용

실패 시 빠른 피드백: 테스트 단계를 가장 먼저 실행4. 로컬 개발 워크플로우 최적화핵심 행동: 개발 중에도 멀티스테이지 빌드 활용해 빠른 피드백 받기

실행 가이드:

# 1. 빌드 결과물만 확인 (디버깅용)
docker build --target builder -t myapp:dev .
docker run --rm myapp:dev ls -la /app/build

# 2. 특정 스테이지 실행 후 셸 접속
docker build --target dependencies -t myapp:deps .
docker run -it --rm myapp:deps sh
# 컨테이너 안에서: npm list, ls -la 등으로 확인

# 3. 빠른 테스트 실행
docker build --target tester -t myapp:test . && \
  docker run --rm myapp:test

# 4. 프로덕션 이미지 로컬 테스트
docker build -t myapp:prod .
docker run -p 8080:80 myapp:prod
# 브라우저에서 localhost:8080 확인

성공 지표:

코드 변경 후 1분 이내 테스트 결과 확인

각 스테이지를 독립적으로 디버깅 가능

로컬과 CI/CD가 동일한 Dockerfile 사용실수 방지·용기 팁:

--rm 플래그로 테스트 후 컨테이너 자동 삭제

docker-compose도 target 지정 가능:

services:

app:

build:

context: .

target: development

🧠 핵심 개념 해부개념1: 멀티스테이지 빌드 (Multi-Stage Build)아주 쉬운 설명:

요리에 비유하면, 재료 손질하는 도마/칼과 최종 음식을 담는 접시를 분리하는 것입니다. 손질 도구는 주방에 두고, 손님에게는 깨끗한 접시에 담긴 음식만 내놓는 것처럼, Docker도 빌드 도구는 버리고 실행 파일만 최종 이미지에 담습니다.

실생활 또는 실무 예시:

Netflix, Uber 등 대형 기업들은 멀티스테이지로 이미지 크기를 90% 이상 줄이고, Kubernetes 클러스터에서 수천 개 컨테이너를 빠르게 배포합니다.

실질적 중요성:

이미지 1GB vs 50MB는 단순 용량 차이가 아닙니다. 100개 서버에 배포 시 네트워크 전송량 95GB 절약, 배포 시간 10배 단축, 그리고 보안 취약점 80% 이상 감소합니다.

오해·진실 구분:

❌ 오해: "멀티스테이지는 복잡한 프로젝트에만 필요"

✅ 진실: 간단한 React 앱도 800MB→20MB로 줄일 수 있어 모든 프로젝트에 유용

개념2: AS 키워드 - 스테이지 이름 지정아주 쉬운 설명:

FROM 뒤에 AS 이름을 붙이면 그 단계에 별명을 주는 것입니다. "1번 단계", "2번 단계"라고 부르는 것보다 "빌더 단계", "테스터 단계"라고 부르는 게 훨씬 명확하죠.

실생활 또는 실무 예시:

FROM node:14 AS builder  # "builder"라는 이름으로 참조 가능
FROM node:14 AS 0  # ❌ 이렇게는 쓸 수 없음

실질적 중요성:

AS 없으면 COPY --from=0 처럼 숫자로만 참조 가능하고, --target 옵션을 아예 사용할 수 없습니다. 팀 협업에서는 필수입니다.

오해·진실 구분:

❌ 오해: "AS는 선택사항이니 안 써도 됨"

✅ 진실: --target 쓰려면 필수. 실무에서는 항상 사용하는 것이 표준

개념3: --target 옵션 - 선택적 빌드아주 쉬운 설명:

책을 읽을 때 3장까지만 읽고 멈추는 것처럼, Dockerfile의 특정 스테이지까지만 실행하고 중단하는 명령입니다. 전체 책을 다 읽지 않아도 필요한 부분만 볼 수 있죠.

실생활 또는 실무 예시:

# 테스트만 실행 (빌드 시간 70% 단축)
docker build --target tester -t app:test .

# 개발용 이미지 (핫 리로드 포함)
docker build --target development -t app:dev .

# 프로덕션 이미지 (최적화됨)
docker build -t app:prod .  # target 없으면 끝까지

실질적 중요성:

CI/CD에서 게임 체인저입니다. PR마다 전체 빌드(5분) 대신 테스트만(1분) 실행하면 개발 속도가 5배 향상됩니다.

오해·진실 구분:

❌ 오해: "--target builder는 builder 직전까지 실행"

✅ 진실: builder 포함해서 그 스테이지까지 완전히 실행됨

개념4: COPY --from=스테이지명 - 스테이지 간 파일 전달아주 쉬운 설명:

이전 작업실에서 완성된 제품만 가져오는 것입니다. 작업 과정, 도구, 쓰레기는 두고 결과물만 깨끗하게 전달받습니다.

실생활 또는 실무 예시:

FROM node:14 AS builder
RUN npm install  # 300MB node_modules 생성
RUN npm run build  # 10MB 빌드 결과물 생성

FROM nginx:alpine
# builder에서 10MB만 가져옴 (300MB는 버림)
COPY --from=builder /app/build /usr/share/nginx/html

실질적 중요성:

이것이 멀티스테이지의 핵심 마법입니다. 빌드 도구 전체(수백 MB)를 버리고 결과물(수십 MB)만 가져와 이미지 크기를 10배 이상 줄입니다.

오해·진실 구분:

❌ 오해: "전체 /app 디렉터리를 복사해야 함"

✅ 진실: 필요한 파일/폴더만 정확히 지정. /app/build만 복사하면 나머지는 최종 이미지에 없음

개념5: 이미지 레이어 캐싱 전략아주 쉬운 설명:

레고 블록처럼 Docker는 각 명령어를 층층이 쌓습니다. 변경되지 않은 층은 재사용하고, 변경된 층부터 다시 빌드합니다. 자주 바뀌는 것은 위쪽에, 안 바뀌는 것은 아래쪽에 배치하면 빌드가 훨씬 빠릅니다.

실생활 또는 실무 예시:

# ❌ 나쁜 예: 코드 변경마다 npm install 재실행 (2분 소요)
FROM node:14-alpine
COPY . .
RUN npm install
RUN npm run build

# ✅ 좋은 예: package.json 안 바뀌면 캐시 사용 (5초 소요)
FROM node:14-alpine
COPY package.json package-lock.json ./
RUN npm install  # 캐시됨
COPY . .  # 코드만 변경됨
RUN npm run build

실질적 중요성:

실무에서 하루 수십 번 빌드합니다. 매번 2분 vs 5초는 하루 1시간 vs 5분 차이입니다. 1년이면 250시간 절약.

오해·진실 구분:

❌ 오해: "캐시는 자동이니 신경 안 써도 됨"

✅ 진실: Dockerfile 명령어 순서가 캐시 효율을 결정. 전략적 배치 필수

🔮 성장 전략 & 실전 지혜예방·지속 전략1. Dockerfile 작성 체크리스트 습관화

첫 번째 FROM에 AS 이름 지정했는가?

자주 변경되지 않는 의존성이 먼저 복사되는가?

.dockerignore 파일로 node_modules, .git 제외했는가?

alpine 같은 경량 베이스 이미지 사용 중인가?

최종 이미지 크기가 100MB 이하인가?2. 정기 이미지 감사

매주 금요일마다:

# 이미지 크기 체크
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# 보안 취약점 스캔
docker scout cves myapp:latest  # 또는 trivy 사용

# 불필요한 이미지 정리
docker image prune -a

3. 팀 코드 리뷰 필수 항목

PR에 Dockerfile 변경 시 이미지 크기 변화 코멘트

--target 사용 가능 여부 확인

스테이지 이름이 팀 네이밍 컨벤션 준수하는지 체크장기적 성장 포인트인프라 엔지니어로의 발전:

멀티스테이지 빌드를 마스터하면 Kubernetes, CI/CD 최적화, 클라우드 비용 절감 등 인프라 전반을 이해하게 됩니다. DevOps 엔지니어의 핵심 역량입니다.

비용 절감 실적:

이미지 최적화로 AWS ECR 비용 월 $500 → $50 절감, 배포 시간 단축으로 개발 생산성 30% 향상 같은 수치를 이력서에 기재할 수 있습니다.

오픈소스 기여:

인기 있는 오픈소스 프로젝트의 Dockerfile을 멀티스테이지로 개선하는 PR은 높은 승인율을 보입니다. 실제 기여 사례를 만들 좋은 기회입니다.

전문가 마인드셋·실전 노하우고수들의 사고방식:

최소주의: "이 패키지 진짜 필요한가?"를 항상 질문

측정 우선: 체감이 아닌 docker images, docker history로 수치 확인

레이어 의식: 모든 명령어가 레이어를 만든다는 것을 인지하고 RUN 결합

보안 중심: 작은 이미지 = 적은 취약점. 크기는 보안의 부산물실전 트릭:

# 여러 RUN을 하나로 결합 (레이어 최소화)
RUN apk add --no-cache git \
    && git clone ... \
    && make install \
    && apk del git  # 빌드 도구 삭제

# FROM scratch로 궁극의 경량화 (Go, Rust 등)
FROM golang:1.21 AS builder
RUN go build -o app

FROM scratch  # 0바이트 베이스!
COPY --from=builder /app /app

학습 로드맵초급 (1-2주):

Docker 공식 문서 Multi-stage builds 섹션 정독

간단한 React/Vue 앱을 멀티스테이지로 변환

--target 옵션으로 테스트/빌드 분리 실습중급 (3-4주):

Spring Boot, Django 등 백엔드 앱 멀티스테이지 구현

GitHub Actions에 --target 통합

docker-compose에서 target 활용고급 (1-2개월):

BuildKit 고급 기능 활용 (병렬 빌드, 마운트 캐시)

모노레포에서 멀티스테이지 전략

Kaniko, Buildah 등 대안 도구 탐색추천 자료:

Docker 공식 Best Practices 가이드

"Docker Deep Dive" by Nigel Poulton

Spacelift, Blacksmith 블로그의 최신 멀티스테이지 가이드🌟 실전 적용 플랜즉시 실행 액션(3가지)1. 현재 프로젝트 Dockerfile 진단 (5분)

# 현재 이미지 크기 확인
docker build -t current:check .
docker images current:check

# 레이어 분석
docker history current:check

기준: 500MB 이상이면 개선 필요, 100MB 이하면 우수

2. 2단계 멀티스테이지로 변환 (30분)

# 최소 구현: 빌드 + 실행 분리
FROM [현재_베이스] AS builder
# ... 빌드 명령어 ...

FROM [경량_베이스]
COPY --from=builder [결과물_경로] [목적지]

목표: 이미지 크기 50% 이상 감소

3. --target으로 테스트 자동화 (15분)

# package.json의 scripts에 추가
"docker:test": "docker build --target tester -t app:test ."
"docker:prod": "docker build -t app:prod ."

중기 현장 프로젝트(2~3가지)프로젝트 1: 팀 표준 Dockerfile 템플릿 구축 (1주)

언어/프레임워크별 멀티스테이지 템플릿 3개 작성

.dockerignore, 네이밍 컨벤션 포함

팀 위키에 가이드 문서화프로젝트 2: CI/CD 파이프라인 최적화 (2주)

기존 빌드 시간 측정

--target으로 테스트/빌드/배포 단계 분리

캐시 전략 적용 후 시간 비교 리포트 작성

목표: 빌드 시간 50% 단축프로젝트 3: 모니터링 대시보드 구축 (2주)

이미지 크기 추이 그래프

취약점 개수 트래킹

배포 빈도 vs 빌드 시간 상관관계 분석숙련도 자가진단법기초 레벨 (3가지 중 2개 이상 가능):

 FROM을 2개 이상 사용한 Dockerfile 작성 가능

 COPY --from=스테이지명 문법 설명 가능

 단일 스테이지 대비 멀티스테이지 장점 3가지 말할 수 있음중급 레벨 (3가지 중 2개 이상 가능):

 --target 옵션으로 CI/CD 파이프라인 구성 가능

 이미지 크기를 70% 이상 줄인 경험 있음

 레이어 캐싱 전략을 설명하고 Dockerfile에 적용 가능고급 레벨 (3가지 중 2개 이상 가능):

 5단계 이상의 복잡한 멀티스테이지 설계 및 구현 가능

 BuildKit의 고급 기능 (마운트 캐시, secrets) 활용 가능

 팀 표준을 만들고 코드 리뷰에서 멀티스테이지 최적화 지도 가능추천 자료·플랫폼공식 문서:

Docker Docs: Multi-stage builds

Docker Docs: Building best practices실전 가이드:

Spacelift: Docker Multistage Builds 완벽 가이드

Blacksmith: Understanding Multi-Stage Docker Builds

Talent500: Modern Docker Best Practices 2025도구:

Dive: 이미지 레이어 시각화 분석 도구

Docker Scout: 공식 보안 취약점 스캐너

Trivy: 오픈소스 컨테이너 스캐너커뮤니티:

Docker Community Slack

Reddit r/docker

Stack Overflow [docker-multistage] 태그📝 핵심 메시지 압축 요약멀티스테이지 빌드는 단순한 최적화 기법이 아니라, 프로덕션 배포의 필수 전략입니다. AS 키워드로 스테이지에 이름을 붙이고, --target으로 필요한 단계만 실행하면 빌드 시간 70% 단축, 이미지 크기 90% 감소, 보안 취약점 80% 감소를 동시에 달성할 수 있습니다. 지금 당장 여러분의 Dockerfile에 두 번째 FROM을 추가하는 것으로 시작하세요. 그 한 줄이 배포 속도를 10배 빠르게 만들고, 여러분을 진정한 DevOps 엔지니어로 성장시킬 것입니다.

목차
목차를 불러오는 중...

댓글

Loading...

댓글 로딩 중...

구글 검색