1. Dockerfile 주요 명령어 요약
도커 파일은 아래에서 위로 쌓이는 레이어(Layer) 구조 형성
- FROM: 모든 빌드의 시작점이며, 기반이 될 베이스 이미지 지정
- WORKDIR: 컨테이너 내부에서 명령어가 실행될 작업 디렉토리 설정 (없으면 자동 생성)
- COPY / ADD: 호스트의 파일을 컨테이너 내부로 복사 (ADD는 URL 다운로드 및 압축 해제 기능 추가 포함)
- RUN: 이미지 빌드 도중에 실행할 명령어 (패키지 설치, 파일 권한 변경 등 신규 레이어 생성)
- CMD / ENTRYPOINT: 컨테이너가 시작되는 시점에 실행할 명령
- CMD: 인자값이 변경될 수 있는 기본 명령 (덮어쓰기 가능)
- ENTRYPOINT: 컨테이너 실행 목적에 맞게 고정된 명령 (덮어쓰기 불가)
- EXPOSE: 컨테이너가 외부와 통신할 때 사용할 포트 명시(안내용)
- ENV: 컨테이너 내부 환경 변수를 설정
2. 이미지 최적화가 필요한 이유
- 이미지가 무거우면 빌드 및 네트워크 전송 속도가 저하
- 운영 서버 배포 시 컨테이너 기동 속도가 느려짐
- 불필요한 개발 도구가 포함되면 보안 취약점(공격 표면, Attack Surface)이 늘어나므로 최적화가 필수적
3. 💡 핵심 최적화 전략 (실무 필수)
① 경량 베이스 이미지 선택 (Alpine & Slim)
- Alpine: 5MB 내외의 초경량 리눅스 배포판으로 가볍고 보안에 강력함 (단, C 라이브러리 호환성 체크 필요)
- Slim: 필요한 언어 런타임만 포함하고 불필요한 패키지를 제거하여 용량을 대폭 줄인 이미지.
② 레이어 수 최소화 (Layer Flattening)
도커는 RUN, COPY, ADD 명령마다 새로운 레이어를 생성하므로, 비슷한 명령어는 && 연산자로 묶어 하나의 레이어로 합치고 임시 필터 파일은 즉시 지워야 함
- 예시: RUN apt-get update && apt-get install -y python3 && rm -rf /var/lib/apt/lists/*
③ 레이어 캐싱 (Layer Caching) 효율 극대화
도커는 명령어 집합이 변경되지 않았다면 기존 빌드된 레이어를 재사용. 하지만 단 하나의 레이어라도 변경되면 그 이후의 모든 캐시는 파괴(Cache Busting)
- 최적의 배치: "변하지 않는 파일(의존성 정의)" ➔ "자주 변하는 파일(소스 코드)" 순으로 작성해야 무거운 패키지 설치 과정을 캐시 처리할 수 있음
- Good-Case 예시:
Dockerfile
COPY package.json package-lock.json ./
RUN npm install # package.json이 바뀌지 않았다면 이 무거운 작업은 항상 캐시됨 (초고속 빌드)
COPY . . # 자주 바뀌는 소스 코드는 맨 마지막에 복사
④ 멀티 스테이지 빌드 (Multi-stage Build) ⭐⭐⭐
단일 Dockerfile 내에서 FROM 구문을 여러 번 사용하여 "빌드 단계(builder)"와 "실행 단계(production)"를 완전히 분리하는 기법입니다.
- 원리: 빌드 단계에서는 무거운 컴파일러와 SDK를 사용해 결과물(바이너리 또는 배포용 패키지)만 만들어내고, 최종 실행 단계에서는 초경량 이미지(Slim, Alpine)를 가져와 앞 단계의 결과물(아티팩트)만 COPY --from=builder로 쏙 빼와서 실행
- 이점: 무거운 빌드 툴체인이 배포 이미지에서 완전히 제외되므로 용량이 수 GB에서 수십 MB 단위로 극적으로 감소하며, 공격 표면이 사라져 보안성 극대화
4. 빌드 방식 전후 비교 및 체크리스트
빌드 방식 포함되는 구성 요소 최종 이미지 용량 보안성 (공격 표면)
| 빌드 방식 | 포함되는 구성 요소 | 최종 이미지 용량 | 보안성 (공격 표면) |
| 단일 스테이지 빌드 | 언어 SDK + 소스 코드 + 빌드 툴 + 실행 파일 | 약 800 MB | ⚠️ 위험 (컴파일 도구 노출) |
| 멀티 스테이지 빌드 | 초경량 Linux(Alpine) + 최종 실행 파일 | 약 20 MB | 안전 (필수 파일만 존재) |
🛠️ 효율적인 Dockerfile 검증 체크리스트
- Alpine이나 Slim 같은 가장 가벼운 베이스 이미지를 썼는가?
- 빌드 툴과 실행 환경을 분리하는 멀티 스테이지 빌드를 활용했는가?
- 캐시 효율을 고려해 COPY package.json / requirements.txt를 COPY . .보다 앞 배치했는가?
- 불필요한 임시 파일과 캐시 삭제 처리를 RUN 명령어 끝에 함께 묶어 수행했는가?
- .dockerignore 파일을 생성하여 .git이나 node_modules 같은 불필요한 파일 유입을 차단했는가?
'데이터 엔지니어링 > Docker' 카테고리의 다른 글
| 5. Docker Compose 이해 (1) | 2026.05.28 |
|---|---|
| 3. Docker의 핵심 3단계 워크플로우(Lifecycle) (0) | 2026.05.27 |
| 2. Docker 실행 프로세스 (0) | 2026.05.27 |
| 1. Docker 개요와 이미지, 컨테이너의 이해 그리고 설치 (0) | 2026.05.27 |