2단계
2단계 — docker-compose 패턴
30 분
2단계 — docker-compose 패턴
진짜 서비스는 컨테이너 한 개 가 아니에요. 앱 + DB + Redis + 작업 큐 — docker-compose 가 이 묶음을 한 줄로 띄워 줍니다.
첫 docker-compose.yml
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: secret
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 5s
timeout: 3s
retries: 5
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
app:
build: .
depends_on:
postgres: { condition: service_healthy }
redis: { condition: service_started }
environment:
DB_URL: postgresql://user:secret@postgres:5432/myapp
REDIS_URL: redis://redis:6379
ports:
- "127.0.0.1:3000:3000" # 외부 직접 노출 X — Caddy 만 받음
restart: unless-stopped
volumes:
pg-data:
redis-data:
docker compose up -d # 백그라운드 띄우기
docker compose ps # 상태
docker compose logs -f app # 로그
docker compose down # 종료 (volume 보존)
docker compose down -v # volume 까지 삭제 (위험)
핵심 패턴 6
- healthcheck — DB 가 준비되기 전에 앱이 뜨면 connect 실패.
condition: service_healthy로 동기화 - 127.0.0.1 바인딩 — 외부에서 직접
:3000접근 불가, Caddy 만 통과 (4단계) - named volume —
pg-data같은 이름 지정 volume 이 운영 표준 - environment vs .env 파일 — 비밀번호는 .env 파일 (gitignore)
- depends_on — 시작 순서 조절
- restart: unless-stopped — 재부팅 시 자동 재시작
.env 분리
services:
app:
env_file:
- .env.prod
# .env.prod (gitignore)
DB_PASSWORD=real-secret
JWT_SECRET=very-long-random-string
DEV 와 PROD 분리
infra/
├── dev/docker-compose.yml
└── prod/docker-compose.yml
DEV 는 hot-reload·외부 직접 노출, PROD 는 Caddy 뒤·loopback 만.
직접 해 보기
위 yml 을 그대로 복사해 PostgreSQL + Redis + 앱 한 묶음을 띄워 보세요. docker compose ps 가 모두 healthy 면 성공.
더 깊이
다음 단계
3단계에서는 외부 트래픽을 받는 Caddy 를 만나요.