Docker Compose 실전 — 개발 환경에서 프로덕션 대비까지
개발할 때는 소스 코드를 마운트하고 핫 리로드를 쓰지만, 프로덕션에서는 이미지를 빌드해서 배포합니다. 같은 Compose 파일로 두 환경을 어떻게 관리할 수 있을까요?
profiles — 서비스 선택적 활성화
모든 서비스가 항상 필요한 것은 아닙니다. 디버깅 도구, 모니터링, 데이터 마이그레이션 등은 특정 상황에서만 실행하고 싶을 때 profiles를 사용합니다.
# compose.yaml
services:
api:
build: ./api
ports:
- "8080:8080"
db:
image: postgres:16-alpine
volumes:
- pg-data:/var/lib/postgresql/data
# 디버깅 프로파일
adminer:
image: adminer
ports:
- "8888:8080"
profiles:
- debug
# 모니터링 프로파일
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
profiles:
- monitoring
grafana:
image: grafana/grafana
ports:
- "3000:3000"
profiles:
- monitoring
# 데이터 시딩
seed:
build: ./api
command: npm run seed
depends_on:
db:
condition: service_healthy
profiles:
- seed
volumes:
pg-data:
# 기본 서비스만 시작 (api, db)
docker compose up -d
# 디버깅 도구 포함
docker compose --profile debug up -d
# 모니터링 포함
docker compose --profile monitoring up -d
# 여러 프로파일 동시
docker compose --profile debug --profile monitoring up -d
# 시드 데이터 실행 (한 번 실행 후 종료)
docker compose run --rm --profile seed seed
profiles가 없는 서비스는 항상 시작되고, profiles가 있는 서비스는 해당 프로파일이 활성화될 때만 시작됩니다.
override와 다중 Compose 파일
compose.override.yaml
docker compose up을 실행하면 compose.yaml과 compose.override.yaml이 자동으로 병합됩니다.
# compose.yaml — 공통 설정
services:
api:
build: ./api
environment:
NODE_ENV: production
restart: unless-stopped
db:
image: postgres:16-alpine
volumes:
- pg-data:/var/lib/postgresql/data
volumes:
pg-data:
# compose.override.yaml — 개발 환경 (자동 병합)
services:
api:
build:
context: ./api
target: development # 개발용 빌드 타겟
environment:
NODE_ENV: development
DEBUG: "true"
ports:
- "8080:8080"
- "9229:9229" # 디버거 포트
volumes:
- ./api/src:/app/src # 소스 코드 마운트
restart: "no"
db:
ports:
- "5432:5432" # 로컬에서 직접 접근 가능
environment:
POSTGRES_PASSWORD: devpassword
# 개발 환경 (compose.yaml + compose.override.yaml 자동 병합)
docker compose up -d
# 프로덕션 — override 무시하고 prod 파일 사용
docker compose -f compose.yaml -f compose.prod.yaml up -d
프로덕션 파일
# compose.prod.yaml
services:
api:
image: myregistry.com/myapi:${TAG:-latest}
# build 대신 이미지 사용
environment:
NODE_ENV: production
deploy:
resources:
limits:
cpus: "1"
memory: 1G
replicas: 2
db:
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
병합 규칙
- 단일 값 (image, command 등): 나중 파일이 덮어씀
- 리스트 (ports, volumes 등): 합쳐짐 (append)
- 맵 (environment 등): 키 단위로 병합, 같은 키는 덮어씀
extends — 서비스 설정 상속
# common-services.yaml
services:
base-api:
build:
context: .
environment:
LOG_LEVEL: info
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
# compose.yaml
services:
user-api:
extends:
file: common-services.yaml
service: base-api
build:
context: ./user-service
ports:
- "8081:8080"
environment:
SERVICE_NAME: user-api
# LOG_LEVEL: info는 상속됨
order-api:
extends:
file: common-services.yaml
service: base-api
build:
context: ./order-service
ports:
- "8082:8080"
environment:
SERVICE_NAME: order-api
watch 모드 — 파일 변경 자동 감지
Docker Compose V2.22+에서 지원하는 기능으로, 파일 변경을 감지하여 자동으로 반영합니다.
# compose.yaml
services:
api:
build: ./api
ports:
- "8080:8080"
develop:
watch:
# 소스 코드 변경 → 컨테이너에 동기화
- action: sync
path: ./api/src
target: /app/src
ignore:
- "**/*.test.ts"
# package.json 변경 → 이미지 재빌드
- action: rebuild
path: ./api/package.json
# 설정 파일 변경 → 동기화 후 재시작
- action: sync+restart
path: ./api/config
target: /app/config
# watch 모드 시작
docker compose watch
# 또는 up과 함께
docker compose up --watch
watch 액션 종류
| 액션 | 동작 | 사용 사례 |
|---|---|---|
sync | 파일을 컨테이너에 동기화 | 핫 리로드 지원 소스 코드 |
rebuild | 이미지를 다시 빌드하고 서비스 재시작 | 의존성 변경 (package.json) |
sync+restart | 파일 동기화 후 서비스 재시작 | 설정 파일 변경 |
개발 환경 핫 리로드 구성
Node.js (nodemon)
services:
api:
build:
context: ./api
target: development
command: npx nodemon --watch src src/server.ts
volumes:
- ./api/src:/app/src
- ./api/package.json:/app/package.json
- api-node-modules:/app/node_modules
ports:
- "8080:8080"
- "9229:9229"
environment:
NODE_ENV: development
volumes:
api-node-modules:
React (Vite)
services:
frontend:
build:
context: ./frontend
target: development
command: npm run dev -- --host 0.0.0.0
volumes:
- ./frontend/src:/app/src
- ./frontend/public:/app/public
- frontend-node-modules:/app/node_modules
ports:
- "5173:5173"
environment:
VITE_API_URL: http://localhost:8080
volumes:
frontend-node-modules:
Spring Boot (devtools)
services:
api:
build:
context: ./api
target: development
volumes:
- ./api/src:/app/src
- gradle-cache:/root/.gradle
ports:
- "8080:8080"
- "5005:5005"
environment:
SPRING_PROFILES_ACTIVE: dev
JAVA_TOOL_OPTIONS: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
volumes:
gradle-cache:
프로덕션 대비 체크리스트
# compose.prod.yaml
services:
api:
# 1. build 대신 이미지 사용
image: myregistry.com/myapi:${TAG}
# 2. 리소스 제한
deploy:
resources:
limits:
cpus: "1"
memory: 1G
reservations:
cpus: "0.25"
memory: 256M
# 3. 로그 드라이버 설정
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# 4. 재시작 정책
restart: unless-stopped
# 5. 읽기 전용 파일 시스템
read_only: true
tmpfs:
- /tmp
# 6. 보안 설정
security_opt:
- no-new-privileges:true
# 7. 헬스체크
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
개발 vs 프로덕션 차이 요약
| 항목 | 개발 | 프로덕션 |
|---|---|---|
| 이미지 소스 | build: | image: |
| 볼륨 | 소스 코드 바인드 마운트 | 데이터 볼륨만 |
| 포트 | 디버거, DB 포트 노출 | 최소한의 포트 |
| 리소스 제한 | 없음 | CPU/메모리 제한 |
| 재시작 | no | unless-stopped |
| 로그 | 콘솔 출력 | 로그 드라이버 설정 |
| 환경변수 | .env 파일 | Secrets |
유용한 팁
프로젝트 이름 지정
# 기본: 디렉토리 이름이 프로젝트 이름
docker compose up -d
# 프로젝트 이름 지정
docker compose -p myproject up -d
# 또는 .env에서
# COMPOSE_PROJECT_NAME=myproject
이미지 빌드와 관리
# 빌드만 (실행하지 않음)
docker compose build
# 캐시 없이 빌드
docker compose build --no-cache
# 특정 서비스만 빌드
docker compose build api
# 빌드 후 push
docker compose build && docker compose push
로그 관리
# 전체 서비스 로그
docker compose logs -f
# 특정 서비스, 최근 100줄
docker compose logs -f --tail 100 api
# 타임스탬프 포함
docker compose logs -f -t api
정리
profiles로 디버깅, 모니터링 등 선택적 서비스를 관리합니다.compose.override.yaml은 자동 병합되어 개발 환경 설정을 편리하게 추가합니다.extends로 공통 서비스 설정을 재사용하여 중복을 줄입니다.docker compose watch로 파일 변경 시 자동 동기화/재빌드를 구성합니다.- 개발과 프로덕션 환경은 기본 파일 + 환경별 파일로 분리하여 관리하는 것이 가장 깔끔합니다.
댓글 로딩 중...