실제 애플리케이션은 웹 서버, 데이터베이스, 캐시 등 여러 컨테이너가 협력해 동작한다. 컨테이너마다 docker run 명령을 손으로 입력하다 보면 옵션 누락이나 실행 순서 실수가 잦아진다. Docker Compose는 이 모든 컨테이너 설정을 단일 YAML 파일로 선언하고, 한 명령으로 전체 스택을 올리고 내리는 도구다.
컨테이너를 하나씩 실행할 때 발생하는 문제를 생각해보자.
# 수동으로 실행할 때
docker run -d --name db -e POSTGRES_PASSWORD=secret postgres:15
docker run -d --name cache redis:7
docker run -d --name app --link db --link cache -p 3000:3000 my-app
링크, 환경변수, 포트, 볼륨을 매번 타이핑해야 하고, 팀원과 동일한 환경을 공유하기 어렵다. Compose는 이 모든 정보를 버전 관리 가능한 파일로 만든다.
version: "3.9"
services:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:secret@db:5432/mydb
depends_on:
- db
- cache
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data
cache:
image: redis:7
volumes:
db-data:
services — 실행할 컨테이너 목록. 각 항목이 하나의 컨테이너가 된다.
depends_on — 서비스 시작 순서를 지정한다. 단, 컨테이너가 "준비됐는지"는 보장하지 않으므로 헬스체크와 함께 사용하는 것이 좋다.
docker compose up
|
v
[docker-compose.yml 파싱]
|
+---> db 컨테이너 생성 & 시작
|
+---> cache 컨테이너 생성 & 시작
|
+---> app 컨테이너 생성 & 시작
|
v
http://localhost:3000 접근 가능
| 명령어 | 동작 |
|---|---|
docker compose up -d | 모든 서비스를 백그라운드로 시작 |
docker compose down | 컨테이너와 네트워크 제거 (볼륨은 유지) |
docker compose down -v | 볼륨까지 함께 제거 |
docker compose ps | 실행 중인 서비스 목록과 상태 확인 |
docker compose logs -f app | 특정 서비스 로그 스트리밍 |
docker compose build | 이미지 빌드만 수행 |
Compose는 프로젝트별로 격리된 브리지 네트워크를 자동 생성한다. 같은 docker-compose.yml 안의 서비스끼리는 서비스 이름을 호스트명으로 바로 통신할 수 있다.
app 컨테이너 내부에서:
postgres://db:5432 <-- "db"가 곧 컨테이너 호스트명
redis://cache:6379 <-- "cache"가 곧 컨테이너 호스트명
브리지 네트워크(Bridge Network) — Docker가 호스트 안에 가상 스위치를 만들어 컨테이너들을 연결하는 기본 네트워크 드라이버.
운영/개발 환경을 나누려면 오버라이드 파일을 활용한다.
# 개발 환경
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# 운영 환경
docker compose -f docker-compose.yml -f docker-compose.prod.yml up
기본 파일에 공통 설정을 두고 환경별 파일에서 포트, 볼륨, 환경변수만 덮어쓰면 중복 없이 관리된다.