Docker Compose를 위한 YAML: 설정 패턴과 팁
Docker Compose는 YAML을 사용하여 멀티 컨테이너 애플리케이션을 정의합니다. 잘 구조화된 docker-compose.yml은 원활한 개발 환경과 컨테이너 이슈 디버깅에 수시간을 투자하는 것의 차이입니다. 이 가이드에서는 필수 패턴과 일반적인 함정을 다룹니다.
기본 구조
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
depends_on:
- api
api:
build: ./api
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://db:5432/myapp
depends_on:
- db
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD: secret
volumes:
pgdata:
환경 변수
인라인
services:
api:
environment:
NODE_ENV: production
PORT: "3000"
DEBUG: "false"
파일에서
services:
api:
env_file:
- .env
- .env.local # .env 값을 오버라이드
변수 치환
호스트 환경 변수를 참조:
services:
api:
image: myapp:${TAG:-latest} # "latest"로 기본값
environment:
API_KEY: ${API_KEY} # 필수 - 미설정 시 실패
LOG_LEVEL: ${LOG_LEVEL:-info} # "info"로 기본값
네트워킹
커스텀 네트워크
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
internal: true # 외부 접근 불가
같은 네트워크의 서비스는 서비스 이름으로 서로 접근할 수 있습니다. db 서비스는 api에서만 접근 가능하고 web에서는 불가능합니다.
포트 매핑
ports:
- "8080:80" # 호스트:컨테이너
- "443:443"
- "127.0.0.1:3000:3000" # localhost에만 바인딩
- "3000" # 랜덤 호스트 포트
볼륨
명명된 볼륨 (영구적)
services:
db:
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
driver: local
바인드 마운트 (개발용)
services:
api:
volumes:
- ./src:/app/src # 소스 코드
- /app/node_modules # 익명 볼륨 (오버라이드 방지)
익명 볼륨 패턴 (/app/node_modules)은 호스트 바인드 마운트가 컨테이너에 설치된 종속성을 덮어쓰는 것을 방지합니다.
헬스 체크
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
api:
depends_on:
db:
condition: service_healthy
이렇게 하면 api가 db가 컨테이너 시작이 아닌 헬스 체크를 통과한 후에만 시작됩니다.
확장 필드 (DRY 패턴)
x- 접두사 필드와 YAML 앵커를 사용하여 반복을 줄이세요:
x-common: &common
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
x-env: &common-env
TZ: UTC
LOG_FORMAT: json
services:
api:
<<: *common
build: ./api
environment:
<<: *common-env
PORT: "3000"
worker:
<<: *common
build: ./worker
environment:
<<: *common-env
QUEUE: default
YAML 앵커에 대한 더 많은 내용은 YAML 앵커와 별칭 가이드를 참조하세요.
멀티 스테이지 Compose
개발 vs 프로덕션
# docker-compose.yml (기본)
services:
api:
build: ./api
environment:
DATABASE_URL: postgres://db:5432/myapp
# docker-compose.override.yml (개발 - 자동 로드)
services:
api:
volumes:
- ./api/src:/app/src
environment:
NODE_ENV: development
DEBUG: "true"
ports:
- "3000:3000"
- "9229:9229" # 디버그 포트
# docker-compose.prod.yml
services:
api:
environment:
NODE_ENV: production
deploy:
replicas: 3
# 개발 (override 자동 로드)
docker compose up
# 프로덕션
docker compose -f docker-compose.yml -f docker-compose.prod.yml up
일반적인 함정
1. 따옴표 없는 포트 번호
# 위험 - YAML이 80:80을 60진수로 해석
ports:
- 80:80
# 안전 - 항상 따옴표
ports:
- "80:80"
2. 불리언 환경 변수
# 잘못됨 - YAML이 불리언으로 변환
environment:
DEBUG: true # Python True가 됨, "true" 문자열이 아님
# 올바름 - 모든 env 값에 따옴표
environment:
DEBUG: "true"
3. depends_on 타이밍
depends_on은 컨테이너 시작만 기다리지 준비 상태는 아닙니다:
# 컨테이너는 시작되지만 DB가 준비되지 않았을 수 있음
depends_on:
- db
# 헬스 체크 대기
depends_on:
db:
condition: service_healthy
YAML 검증기로 Docker Compose 파일을 검증하세요.
FAQ
docker-compose.yml과 compose.yml의 차이점은?
두 파일 이름 모두 작동합니다. compose.yml은 Docker가 권장하는 새로운 관례입니다. docker-compose.yml은 레거시 이름입니다. Docker Compose v2+는 둘 다 찾으며, 둘 다 존재하면 compose.yml을 선호합니다. 새 프로젝트에는 compose.yml을 사용하세요.
프로덕션에서 Docker Compose를 사용해야 하나요?
Docker Compose는 개발과 간단한 배포에 뛰어납니다. 규모가 있는 프로덕션에는 Docker Swarm (Compose 파일을 네이티브로 사용) 또는 Kubernetes를 고려하세요. Compose의 장점은 개발 설정이 프로덕션에 직접 반영되어 환경 차이를 줄인다는 것입니다.
관련 리소스
- YAML 검증기 — Docker Compose YAML 검증
- YAML 앵커와 별칭 — DRY 설정 패턴
- YAML 구문 튜토리얼 — YAML 기초