Docker Compose: Multi-Service Orchestration with FastAPI, PostgreSQL, and Traefik

Source: docker-compose-multi-service-orchestration Type: Article (Docker Official + TestDriven.io) Valid as of: 2026-04-26

핵심 Takeaway

상세 요약

Docker Compose란?

여러 컨테이너를 정의하고 실행하기 위한 도구.

Docker: 1개 서비스 = 1개 컨테이너 관리
Docker Compose: 여러 서비스를 YAML 파일로 정의 + 동시 관리

필요성: 머신러닝 API 프로덕션 배포 시 FastAPI, PostgreSQL, Traefik 등 3개 이상 서비스 필요 → 수동 실행 복잡, Compose로 자동화.

기본 템플릿 구조

version: '3.8'          # Compose 버전
services:               # 실행할 컨테이너
  api:
    image: myapi:1.0
    ports: ["8000:8000"]
    environment:        # 환경변수
      DATABASE_URL: postgresql://...
    depends_on:         # 의존성 (순서)
      db:
        condition: service_healthy
    networks:           # 네트워크 연결
      - ml_network
      
volumes:                # 데이터 영속성
  postgres_data:
  
networks:               # 네트워크 정의
  ml_network:
    driver: bridge

핵심 개념 1: depends_on (서비스 순서)

문제: API가 DB 연결 시도하는데 DB가 아직 준비 안 됨 → 크래시

해결책 1 - depends_on (기본):

api:
  depends_on:
    - db  # DB가 먼저 시작되도록 보장

단점: 컨테이너 프로세스만 시작했을 뿐, 실제로 요청 받을 준비는 아직 안 됨.

해결책 2 - healthcheck (권장):

api:
  depends_on:
    db:
      condition: service_healthy  # DB가 healthy 상태까지 대기
      
db:
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U user"]  # 스크립트로 준비 확인
    interval: 10s      # 10초마다 체크
    timeout: 5s        # 타임아웃
    retries: 5         # 5번 연속 실패 시 unhealthy

동작:

  1. DB 컨테이너 시작
  2. Healthcheck 명령 실행 (pg_isready) → 실패 → 10초 대기 → 재시도
  3. pg_isready 성공 (DB 준비됨) → API 컨테이너 시작
  4. API가 DB와 통신 성공

핵심 개념 2: 환경변수

방법 1 - 직접 작성 (위험):

environment:
  POSTGRES_PASSWORD: securepass123  # 비밀번호 노출!

방법 2 - .env 파일 (권장):

# .env
DB_NAME=ml_models
DB_USER=mluser
DB_PASSWORD=secure_password_12345
# docker-compose.yml
environment:
  POSTGRES_DB: ${DB_NAME}
  POSTGRES_USER: ${DB_USER}
  POSTGRES_PASSWORD: ${DB_PASSWORD}

실행: docker-compose --env-file .env up -d (또는 기본 .env 자동 사용)

핵심 개념 3: 볼륨 (데이터 영속성)

문제: docker-compose down → DB 데이터 모두 사라짐

해결책 - Named Volumes:

services:
  db:
    volumes:
      - postgres_data:/var/lib/postgresql/data  # 호스트:컨테이너
 
volumes:
  postgres_data:  # Named volume 정의
    driver: local

동작:

  1. docker-compose up → postgres_data 볼륨 생성 → DB 데이터 저장
  2. docker-compose down → 컨테이너 삭제, postgres_data 유지
  3. docker-compose up → 기존 볼륨 재사용 → 데이터 복원

핵심 개념 4: 네트워크

문제: 컨테이너 간 통신. 각 실행마다 IP 변함.

해결책 - Docker Compose 네트워크:

networks:
  ml_network:
    driver: bridge
 
services:
  api:
    networks:
      - ml_network
    environment:
      DATABASE_URL: postgresql://user:pass@db:5432/ml_models
      # "db"는 자동으로 IP로 해석됨
      
  db:
    networks:
      - ml_network

동작:

  1. Compose가 ml_network bridge 네트워크 생성
  2. api, db 컨테이너를 이 네트워크에 연결
  3. DNS 서버 실행 (컨테이너 이름 → IP 변환)
  4. api에서 curl http://db:5432 → db 컨테이너의 IP로 자동 변환

실전 예제: FastAPI + PostgreSQL + Traefik

완전한 구성:

  • docker-compose.yml: 서비스 정의 (api, db, traefik)
  • .env: 환경변수 (DB_NAME, DB_PASSWORD 등)
  • Dockerfile: FastAPI 이미지 빌드
  • main.py: FastAPI 애플리케이션 (healthcheck 엔드포인트 포함)

실행 & 관리

# 시작
docker-compose up -d
 
# 상태 확인
docker-compose ps
 
# 로그
docker-compose logs -f api
 
# 중지 (데이터 유지)
docker-compose down
 
# 완전 삭제
docker-compose down -v
 
# 재빌드
docker-compose up --build -d

문제 해결

문제진단해결책
컨테이너 시작 안 됨docker-compose logs apihealthcheck 확인, 기다렸다 재시도
데이터 영구 저장 안 됨docker inspect mounts 확인volumes 섹션에 추가
포트 충돌lsof -i :8000compose.yml에서 포트 변경

모범 사례 체크리스트

  • depends_on + healthcheck로 서비스 순서 관리
  • 환경변수를 .env로 분리 (git ignore)
  • 데이터 영속성을 위해 named volumes 사용
  • 헬스체크 타임아웃 충분히 설정
  • 개발/프로덕션용 별도 compose 파일
  • .dockerignore로 불필요한 파일 제외
  • 최종 배포 전 로컬에서 전체 테스트

연결되는 위키 페이지