FastAPI + Docker + Traefik — 프로덕션 배포 (TestDriven.io)

Source: https://testdriven.io/blog/fastapi-docker-traefik/ Type: Article By: Amal Shaji Published: 2023-02-02 Valid as of: 2026-04-26

핵심 Takeaway

  • Traefik: 자동 라우팅 + Let’s Encrypt SSL/TLS 인증서 자동 갱신 기능의 경량 리버스 프록시
  • 개발 vs 프로덕션: traefik.dev.toml (HTTP, 대시보드 공개) vs traefik.prod.toml (HTTPS, 기본 인증)
  • Docker 레이블: 서비스별 라우팅 규칙을 Traefik이 자동 발견 (예: traefik.http.routers.fastapi.rule=Host(fastapi.localhost))
  • 포트 80 → 443 자동 리다이렉트: 프로덕션 설정에서 http → https로 강제 (보안)
  • Let’s Encrypt HTTP Challenge: 도메인 소유권 검증으로 인증서 자동 발급·갱신
  • 프로덕션 필수 사항: 등록된 도메인 + EC2/DigitalOcean 등 공인 IP + DNS A 레코드 설정
  • 프로덕션 베스트 프랙티스: 관리형 DB 서비스 사용, non-root 사용자 실행

상세 요약

FastAPI 기본 설정 (개발 환경)

의존성:

  • fastapi==0.89.1
  • uvicorn==0.20.0

최소 엔드포인트:

# main.py
from fastapi import FastAPI
 
app = FastAPI()
 
@app.get("/")
def read_root():
    return {"hello": "world"}

서버: uvicorn main:app --host 0.0.0.0 --port 8000

개발 환경 Docker 설정

기본 Dockerfile:

FROM python:3.11.1-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

환경변수:

  • PYTHONDONTWRITEBYTECODE=1: .pyc 파일 생성 방지 (이미지 크기 절감)
  • PYTHONUNBUFFERED=1: 버퍼링 비활성화 (실시간 로그 출력)

Docker Compose (개발):

version: '3'
services:
  web:
    build: .
    ports:
      - "8008:8000"    # 호스트 8008 → 컨테이너 8000
    container_name: fastapi_dev

실행: docker-compose uphttp://localhost:8008

PostgreSQL 통합 (개발)

Docker Compose에 DB 추가:

services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: fastapi_db
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    container_name: fastapi_db
  
  web:
    build: .
    depends_on:
      - db
    environment:
      DATABASE_URL: postgresql://postgres:password@db:5432/fastapi_db
 
volumes:
  postgres_data:

애플리케이션 라이브러리:

  • ormar: async mini-ORM (SQLAlchemy 기반)
  • asyncpg: PostgreSQL 비동기 드라이버
  • databases: 비동기 쿼리 실행 라이브러리

Traefik: 개발 모드 설정

traefik.dev.toml:

[api]
  dashboard = true
  insecure = true
 
[entryPoints]
  [entryPoints.http]
    address = ":80"
 
[providers.docker]
  endpoint = "unix:///var/run/docker.sock"
  exposedByDefault = false

기능:

Docker 레이블 (FastAPI 서비스에 추가):

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.fastapi.rule=Host(`fastapi.localhost`)"
  - "traefik.http.services.fastapi.loadbalancer.server.port=8000"

hosts 파일 설정 (로컬):

127.0.0.1 fastapi.localhost

접근: http://fastapi.localhost (포트 생략)

Traefik: 프로덕션 모드 설정

traefik.prod.toml:

[api]
  dashboard = true
  address = ":8081"
 
[entryPoints]
  [entryPoints.http]
    address = ":80"
    [entryPoints.http.http.redirections.entryPoint]
      to = "https"       # 80 → 443 자동 리다이렉트
      scheme = "https"
  
  [entryPoints.https]
    address = ":443"
    [entryPoints.https.http.tls]
      certResolver = "letsencrypt"
 
[certificatesResolvers.letsencrypt]
  [certificatesResolvers.letsencrypt.acme]
    email = "your-email@example.com"
    storage = "acme.json"
    [certificatesResolvers.letsencrypt.acme.httpChallenge]
      entryPoint = "http"
 
[providers.docker]
  endpoint = "unix:///var/run/docker.sock"
  exposedByDefault = false
 
[providers.file]
  filename = "basicauth.toml"

기능:

  • HTTP 자동 HTTPS 리다이렉트 (포트 80 → 443)
  • Let’s Encrypt로 자동 인증서 발급·갱신
  • 대시보드 기본 인증 보호

Docker 레이블 (프로덕션):

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.fastapi.rule=Host(`yourdomain.com`)"
  - "traefik.http.routers.fastapi.tls=true"
  - "traefik.http.routers.fastapi.tls.certresolver=letsencrypt"
  - "traefik.http.services.fastapi.loadbalancer.server.port=8000"

Let’s Encrypt SSL/TLS 자동화

동작 원리:

  1. 클라이언트가 yourdomain.com 방문
  2. Traefik이 Let’s Encrypt에 인증서 신청
  3. Let’s Encrypt: HTTP Challenge (.well-known/acme-challenge/<token>) 검증
  4. Traefik이 토큰 응답 → 도메인 소유권 증명
  5. 인증서 발급 (90일 유효)
  6. Traefik 자동 갱신 (만료 30일 전)

필수 사항:

  • 등록된 도메인 (예: example.com)
  • 공인 IP 주소 (EC2, DigitalOcean, Linode 등)
  • DNS A 레코드: example.com → 공인 IP
  • 포트 80/443 개방 (방화벽)

프로덕션 Dockerfile.prod

계층화 빌드 (Pre-built 이미지 활용):

FROM tiangolo/uvicorn-gunicorn:python3.11
 
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
 
COPY requirements.txt .
RUN pip install -r requirements.txt
 
COPY ./app /app
COPY ./prestart.sh /app/
RUN chmod +x /app/prestart.sh
 
ENV APP_MODULE=main:app
ENV PRE_START_PATH=/app/prestart.sh

tiangolo/uvicorn-gunicorn의 장점:

  • Gunicorn (다중 워커) 자동 설정
  • Uvicorn 워커로 비동기 처리
  • 수동 구성 불필요

prestart.sh (DB 준비 확인):

#!/bin/bash
set -e
 
# PostgreSQL 준비 대기
until psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -c '\q'; do
  echo "Postgres is unavailable - sleeping"
  sleep 1
done
 
echo "Postgres is available"
 
# 마이그레이션 실행 (옵션)
# alembic upgrade head
 
exec "$@"

프로덕션 모범 사례

항목개발프로덕션
데이터베이스컨테이너 (sqlite)관리형 서비스 (RDS, CloudSQL)
사용자 권한rootnon-root 사용자
SSL/TLSHTTP onlyHTTPS (Let’s Encrypt)
인증서 관리수동Traefik 자동 갱신
로깅단순구조화·중앙 수집
모니터링없음Prometheus, Datadog 등

연결되는 위키 페이지