Docker Compose를 단일 docker-compose.yml 하나로만 운용하면 개발·스테이징·프로덕션 환경 차이를 코드 안에 if처럼 주석으로 관리하게 된다. 파일을 역할별로 나누면 각 환경의 관심사가 분리되고, CI/CD 파이프라인에서 원하는 조합만 골라 쓸 수 있다.
project/
├── docker-compose.yml # 공통 베이스
├── docker-compose.override.yml # 로컬 개발 오버라이드 (자동 병합)
├── docker-compose.prod.yml # 프로덕션 전용 설정
├── .env # 공통 환경 변수
├── .env.prod # 프로덕션 전용 환경 변수
├── Makefile # 명령어 자동화
└── services/
├── api/
│ └── Dockerfile
└── worker/
└── Dockerfile
docker-compose.override.yml은 docker up 시 자동으로 병합되므로 별도 -f 플래그 없이 로컬 개발 설정이 적용된다. 프로덕션에서는 이 파일을 마운트하지 않고 .prod.yml을 명시적으로 지정한다.
docker-compose.yml (베이스)
services:
api:
build:
context: ./services/api
env_file: .env
networks:
- app-net
db:
image: postgres:16
env_file: .env
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-net
networks:
app-net:
volumes:
db-data:
docker-compose.override.yml (로컬 개발)
services:
api:
build:
target: dev # 멀티스테이지 dev 레이어
volumes:
- ./services/api:/app # 핫리로드용 바인드 마운트
ports:
- "8080:8080"
environment:
- DEBUG=true
docker-compose.prod.yml (프로덕션)
services:
api:
image: registry.example.com/api:${IMAGE_TAG}
restart: always
deploy:
replicas: 2
ports:
- "80:8080"
오버라이드 병합(override merge): Compose는 같은 서비스 키를 발견하면 딥 머지한다. 배열(ports, volumes)은 추가, 스칼라(image, restart)는 덮어쓴다.
# .env (공통, 저장소에 커밋)
POSTGRES_DB=myapp
POSTGRES_USER=app
# .env.prod (프로덕션 시크릿, .gitignore 필수)
POSTGRES_PASSWORD=s3cr3t
IMAGE_TAG=v1.4.2
.env는 커밋하고, 시크릿이 담긴 .env.prod는 반드시 .gitignore에 추가한다. CI에서는 시크릿 매니저에서 주입한다.
| 타깃 | 실행 명령 |
|---|---|
make up | 로컬 개발 스택 실행 |
make down | 컨테이너·네트워크 정리 |
make prod-up | 프로덕션 설정으로 실행 |
make logs | 전체 서비스 로그 팔로우 |
COMPOSE_PROD = docker compose -f docker-compose.yml -f docker-compose.prod.yml --env-file .env.prod
up:
docker compose up --build -d
down:
docker compose down
prod-up:
$(COMPOSE_PROD) up -d
logs:
docker compose logs -f
--env-file: Compose v2.x에서 .env 외 다른 파일을 지정할 때 사용한다. env_file 서비스 키와는 다르며, 이 플래그는 Compose 변수 치환에만 영향을 준다.
Dockerfile은 해당 서비스 디렉터리(services/api/)에 두고, build.context를 그 경로로 지정한다. 루트에 모든 Dockerfile을 모아두면 COPY 경로가 복잡해지고 빌드 컨텍스트가 불필요하게 커진다.
환경이 늘어날수록 파일 하나에 모든 설정을 넣는 비용이 선형으로 증가한다. 베이스·오버라이드·환경별 파일로 나누는 패턴을 초기부터 적용하면 그 비용을 상수에 가깝게 유지할 수 있다.