개발 환경의 docker-compose.yml을 그대로 프로덕션에 올리면 장애 시 컨테이너가 재시작되지 않고, 메모리를 무제한으로 소비하며, 로그가 디스크를 가득 채운다. 실무에서는 개발용과 프로덕션용 Compose 파일을 분리하고, 재시작 정책·리소스 제한·로그 드라이버를 명시적으로 선언해야 한다. 이 글은 그 핵심 설정을 하나씩 짚는다.
개발용 이미지에는 devDependency, hot-reload 도구, 소스 마운트가 포함된다. 프로덕션 이미지는 멀티 스테이지 빌드로 최소화한다.
# Dockerfile.prod
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/main.js"]
Compose에서는 build.dockerfile로 지정한다.
services:
api:
build:
context: .
dockerfile: Dockerfile.prod
컨테이너가 비정상 종료되면 자동 재시작이 필요하다. restart: always 는 Docker 데몬 재시작 후에도 컨테이너를 복구한다.
services:
api:
restart: always
worker:
restart: on-failure # 비정상 종료 시에만 재시작
on-failure — exit code가 0이 아닐 때만 재시작. 의도적 종료(exit 0)는 재시작하지 않는다.
리소스 제한 없이 배포하면 단일 컨테이너가 호스트 전체 메모리를 점유할 수 있다. deploy.resources로 상한을 설정한다.
services:
api:
deploy:
resources:
limits:
cpus: "1.0"
memory: 512m
reservations:
memory: 256m
reservations — 컨테이너 시작 시 호스트에서 보장받는 최소 자원. 스케줄러가 배치 결정에 활용한다.
기본 로그 드라이버(json-file)는 로테이션 없이 디스크를 무한 증가시킨다. max-size와 max-file을 반드시 지정한다.
services:
api:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
중앙 집중 로깅이 필요하면 driver: fluentd 또는 driver: awslogs로 교체한다.
환경 변수로 DB 패스워드를 넘기면 docker inspect로 노출된다. Docker Secrets 또는 외부 시크릿 매니저를 사용한다.
secrets:
db_password:
file: ./secrets/db_password.txt
services:
db:
image: postgres:16
secrets:
- db_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
시크릿 파일은 컨테이너 내부 /run/secrets/<name> 경로에 마운트된다. 환경 변수가 아니라 파일로 읽는다.
push to main
│
▼
[CI] docker build -f Dockerfile.prod -t app:$SHA .
│
▼
[CI] docker push registry/app:$SHA
│
▼
[CD] ssh prod-server
"IMAGE_TAG=$SHA docker compose -f compose.prod.yml up -d"
compose.prod.yml에서 이미지 태그를 환경 변수로 받으면 CI/CD 파이프라인에서 롤백이 쉬워진다.
services:
api:
image: registry/app:${IMAGE_TAG}
| 파일 | 용도 |
|---|---|
compose.yml | 공통 서비스 정의 |
compose.override.yml | 개발 전용 볼륨·포트 |
compose.prod.yml | 프로덕션 전용 리소스·로그·시크릿 |
docker compose -f compose.yml -f compose.prod.yml up -d 처럼 파일을 명시적으로 병합해 실행한다. compose.override.yml은 docker compose up 시 자동 적용되므로 프로덕션에서는 반드시 파일을 명시해야 한다.