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, 대시보드 공개) vstraefik.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.1uvicorn==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 up → http://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기능:
- 대시보드: http://localhost:8081
- Docker 서비스 자동 발견 (레이블 기반)
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 자동화
동작 원리:
- 클라이언트가 yourdomain.com 방문
- Traefik이 Let’s Encrypt에 인증서 신청
- Let’s Encrypt: HTTP Challenge (
.well-known/acme-challenge/<token>) 검증 - Traefik이 토큰 응답 → 도메인 소유권 증명
- 인증서 발급 (90일 유효)
- 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.shtiangolo/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) |
| 사용자 권한 | root | non-root 사용자 |
| SSL/TLS | HTTP only | HTTPS (Let’s Encrypt) |
| 인증서 관리 | 수동 | Traefik 자동 갱신 |
| 로깅 | 단순 | 구조화·중앙 수집 |
| 모니터링 | 없음 | Prometheus, Datadog 등 |
연결되는 위키 페이지
- reverse-proxy — 리버스 프록시 개념 및 Traefik
- traefik — Traefik 설정 및 Docker 레이블
- let-s-encrypt — Let’s Encrypt 자동 인증서 발급
- containerization — 컨테이너화 및 오케스트레이션
- docker-compose — Docker Compose 다중 서비스 관리
- postgresql — PostgreSQL 데이터베이스 운영
- https-ssl-tls — HTTPS 보안 프로토콜