실제 애플리케이션은 단 하나의 컨테이너만으로 동작하지 않는다. 웹 서버, 데이터베이스, 캐시 서버가 서로 통신하며 하나의 서비스를 이룬다. Docker Compose는 이런 다중 컨테이너 환경을 하나의 파일로 정의하고, 단일 명령으로 전체를 실행·종료할 수 있게 해주는 도구다.
docker run 명령어 하나로 컨테이너를 실행하는 것은 간단하다. 하지만 서비스가 커질수록 문제가 생긴다.
# 단일 컨테이너 실행 예시 — 명령어가 점점 길어진다
docker run -d \
--name my-api \
-p 3000:3000 \
-e DATABASE_URL=postgres://... \
--network my-net \
my-api-image
데이터베이스, Redis, API 서버를 각각 docker run으로 띄우면 네트워크 연결, 환경 변수, 실행 순서를 모두 수동으로 관리해야 한다. 컨테이너가 세 개만 되어도 명령어 관리가 번거로워진다.
Docker Compose는 docker-compose.yml 파일 하나에 모든 서비스를 선언한다.
services:
api:
image: my-api-image
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://db:5432/mydb
depends_on:
- db
db:
image: postgres:16
environment:
- POSTGRES_PASSWORD=secret
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
services — 실행할 컨테이너 목록. 각 항목이 하나의 컨테이너에 대응한다.
depends_on — 서비스 시작 순서를 지정한다. api는 db가 먼저 실행된 뒤 시작된다.
volumes — 컨테이너가 종료되어도 데이터가 유지되는 영구 저장소를 선언한다.
docker-compose.yml
|
v
+-------+--------+
| Docker Compose |
+-------+--------+
|
+---------+---------+
| |
+--+--+ +----+----+
| api | <---> | db |
| :3000 | | :5432 |
+-------+ +---------+
(my-api-image) (postgres:16)
같은 네트워크 안에서 서비스 이름으로 통신
api → "db:5432" 로 접근 가능
Docker Compose는 선언된 서비스들을 자동으로 같은 네트워크에 연결한다. 별도의 --network 옵션 없이도 서비스 이름(db)을 호스트명처럼 사용할 수 있다.
| 명령어 | 동작 |
|---|---|
docker compose up | 모든 서비스를 빌드하고 실행 |
docker compose up -d | 백그라운드(detached)로 실행 |
docker compose down | 컨테이너와 네트워크를 종료·삭제 |
docker compose logs -f | 전체 서비스 로그를 실시간으로 확인 |
docker compose ps | 실행 중인 서비스 상태 확인 |
docker compose up 한 번으로 docker-compose.yml에 정의된 모든 컨테이너가 올라온다. docker compose down은 컨테이너와 함께 Compose가 생성한 네트워크도 함께 정리한다. --volumes 플래그를 붙이면 볼륨까지 삭제된다.
Docker Compose는 로컬 개발 환경과 소규모 배포에 가장 잘 맞는다. 팀원 누구나 docker compose up 하나로 동일한 환경을 재현할 수 있어 "내 컴퓨터에서는 되는데" 문제를 줄인다. 대규모 프로덕션 오케스트레이션이 필요하다면 Kubernetes가 적합하지만, 그 전 단계의 복잡도에서는 Docker Compose가 충분하다.