Docker Compose 운영 심화
Docker Compose는 로컬 개발을 넘어 스테이징·CI/CD 환경에서도 활발히 사용됩니다. Profiles로 환경별 서비스를 분리하고, healthcheck 기반 의존성으로 안정적인 기동 순서를 보장하며, Secrets로 민감 정보를 안전하게 관리하는 심화 기법을 다룹니다.
Profiles: 환경별 서비스 분리
개발 환경에서만 필요한 서비스(디버거, 모니터링 UI)를 profiles로 분리합니다.
# docker-compose.yml
services:
api:
build: .
ports: ["3000:3000"]
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
# 개발 환경에서만 실행
adminer:
image: adminer
ports: ["8080:8080"]
profiles: ["dev"]
mailhog:
image: mailhog/mailhog
ports: ["1025:1025", "8025:8025"]
profiles: ["dev"]
# 모니터링 (운영 환경)
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
profiles: ["monitoring"]
grafana:
image: grafana/grafana
ports: ["3001:3000"]
profiles: ["monitoring"]
# 기본 서비스만 실행 (api + db)
docker compose up -d
# 개발 도구 포함
docker compose --profile dev up -d
# 모니터링 포함
docker compose --profile monitoring up -d
# 전부 실행
docker compose --profile dev --profile monitoring up -d
depends_on + healthcheck 의존성
단순 depends_on은 컨테이너 시작만 보장하고, 서비스 준비 완료를 보장하지 않습니다. condition: service_healthy를 사용해야 합니다.
services:
api:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
db:
image: mysql:8
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
start_period: 30s # 초기 부팅 대기
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 3s
timeout: 2s
retries: 5
kafka:
image: confluentinc/cp-kafka:7.5.0
healthcheck:
test: ["CMD-SHELL", "kafka-broker-api-versions --bootstrap-server localhost:9092"]
interval: 10s
timeout: 5s
retries: 10
start_period: 40s
| condition | 의미 | 사용 시점 |
|---|---|---|
| service_started | 컨테이너 시작됨 (기본) | 순서만 중요할 때 |
| service_healthy | healthcheck 통과 | DB, 메시지 큐 등 준비 필요 |
| service_completed_successfully | 종료 코드 0 | 마이그레이션, 초기화 작업 |
Secrets 관리
환경 변수로 비밀번호를 전달하면 docker inspect에 노출됩니다. Secrets를 사용하면 파일로 안전하게 주입됩니다.
services:
api:
build: .
secrets:
- db_password
- jwt_secret
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
JWT_SECRET_FILE: /run/secrets/jwt_secret
db:
image: postgres:16
secrets:
- db_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt # 로컬 파일
jwt_secret:
environment: JWT_SECRET_VALUE # 환경 변수에서 (Compose v2.23+)
// Node.js에서 secret 파일 읽기
import { readFileSync } from 'fs';
const dbPassword = process.env.DB_PASSWORD_FILE
? readFileSync(process.env.DB_PASSWORD_FILE, 'utf8').trim()
: process.env.DB_PASSWORD;
Multi-Stage Compose: extends와 include
공통 설정을 분리하고 환경별로 오버라이드합니다.
# docker-compose.yml (기본)
services:
api:
build:
context: .
target: production
restart: always
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
# docker-compose.override.yml (개발 환경, 자동 로드)
services:
api:
build:
target: development
volumes:
- .:/app
- /app/node_modules
environment:
NODE_ENV: development
DEBUG: "app:*"
ports:
- "3000:3000"
- "9229:9229" # 디버거 포트
command: npm run start:debug
db:
ports:
- "5432:5432" # 로컬 접근용
# docker-compose.prod.yml (운영)
services:
api:
image: registry.example.com/myapp:${TAG:-latest}
deploy:
replicas: 2
resources:
limits:
memory: 1G
# 실행: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
include (Compose v2.20+)
# docker-compose.yml
include:
- path: ./infra/docker-compose.db.yml
- path: ./infra/docker-compose.redis.yml
- path: ./infra/docker-compose.monitoring.yml
env_file: ./infra/.env
services:
api:
build: .
depends_on:
db:
condition: service_healthy
리소스 제한과 로깅
Docker Health Check 운영 심화와 함께 리소스 제한을 설정하면 안정적인 운영이 가능합니다.
services:
api:
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.5'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
tag: "{{.Name}}/{{.ID}}"
# OOM 방지: 메모리 초과 시 재시작
restart: unless-stopped
CI/CD에서 Compose 활용
# GitHub Actions 예시
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start services
run: docker compose --profile test up -d --wait
- name: Run tests
run: docker compose exec api npm run test:e2e
- name: Collect logs on failure
if: failure()
run: docker compose logs --tail=100 > compose-logs.txt
- name: Cleanup
if: always()
run: docker compose down -v
--wait 플래그는 모든 서비스의 healthcheck가 통과할 때까지 대기합니다. Docker BuildKit 캐시 최적화와 함께 사용하면 CI 빌드 시간도 단축할 수 있습니다.
정리
Docker Compose 심화 운영의 핵심은 Profiles로 환경별 서비스를 분리하고, healthcheck 기반 depends_on으로 안정적 기동 순서를 보장하며, Secrets로 민감 정보를 보호하는 것입니다. override 파일로 개발/운영 설정을 분리하고, CI에서는 –wait 플래그로 서비스 준비를 확인한 후 테스트를 실행하세요.