반응형
소개
FastAPI 애플리케이션을 실제 운영 환경에 배포하는 것은 개발만큼 중요한 과정입니다. 이번 글에서는 Docker를 사용하여 FastAPI 애플리케이션을 안전하고 효율적으로 배포하는 방법을 알아보겠습니다.
Docker 기본 설정
Dockerfile 작성
# Dockerfile
# Python 3.9 이미지를 기본으로 사용
FROM python:3.9-slim
# 작업 디렉토리 설정
WORKDIR /app
# Poetry 설치 (의존성 관리 도구)
RUN pip install poetry
# 프로젝트 메타데이터 복사
COPY pyproject.toml poetry.lock ./
# Poetry 설정: 가상환경 생성하지 않음
RUN poetry config virtualenvs.create false
# 의존성 설치
RUN poetry install --no-dev
# 소스 코드 복사
COPY ./app ./app
# 환경변수 설정
ENV PORT=8000
# FastAPI 애플리케이션 실행
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Docker Compose 설정
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/dbname
- SECRET_KEY=your-secret-key
depends_on:
- db
volumes:
- ./app:/app/app
networks:
- app-network
db:
image: postgres:13
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=dbname
networks:
- app-network
volumes:
postgres_data:
networks:
app-network:
driver: bridge
환경 설정 관리
환경변수 설정
# app/config.py
from pydantic import BaseSettings
class Settings(BaseSettings):
"""애플리케이션 설정"""
# 데이터베이스
DATABASE_URL: str
# 보안
SECRET_KEY: str
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
# 서버
HOST: str = "0.0.0.0"
PORT: int = 8000
# 환경
ENVIRONMENT: str = "production"
DEBUG: bool = False
class Config:
env_file = ".env"
settings = Settings()
환경별 설정 파일
# .env.example
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
SECRET_KEY=your-secret-key
ENVIRONMENT=development
DEBUG=True
# .env.production
DATABASE_URL=postgresql://user:password@db:5432/dbname
SECRET_KEY=your-production-secret-key
ENVIRONMENT=production
DEBUG=False
데이터베이스 마이그레이션
Alembic 설정
# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from alembic import context
from app.config import settings
from app.models import Base
config = context.config
# Alembic 설정 수정
config.set_main_option("sqlalchemy.url", settings.DATABASE_URL)
target_metadata = Base.metadata
def run_migrations_offline():
"""오프라인 마이그레이션 실행"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""온라인 마이그레이션 실행"""
configuration = config.get_section(config.config_ini_section)
configuration["sqlalchemy.url"] = settings.DATABASE_URL
connectable = engine_from_config(
configuration,
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
배포 스크립트
Docker 배포 스크립트
#!/bin/bash
# deploy.sh
# 환경 변수 로드
set -a
source .env.production
set +a
# 이전 컨테이너 정리
docker-compose down
# 이미지 빌드
docker-compose build
# 컨테이너 시작
docker-compose up -d
# 데이터베이스 마이그레이션
docker-compose exec web alembic upgrade head
echo "Deployment completed successfully!"
로깅 설정
# app/logger.py
import logging
from logging.handlers import RotatingFileHandler
def setup_logger():
"""로깅 설정"""
logger = logging.getLogger("fastapi_app")
logger.setLevel(logging.INFO)
# 파일 핸들러
file_handler = RotatingFileHandler(
"logs/app.log",
maxBytes=1024 * 1024, # 1MB
backupCount=5
)
file_handler.setFormatter(
logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
)
logger.addHandler(file_handler)
# 콘솔 핸들러
console_handler = logging.StreamHandler()
console_handler.setFormatter(
logging.Formatter(
'%(levelname)s: %(message)s'
)
)
logger.addHandler(console_handler)
return logger
모니터링 설정
Prometheus 메트릭 설정
# app/monitoring.py
from prometheus_client import Counter, Histogram
from fastapi import FastAPI
from starlette_prometheus import PrometheusMiddleware, metrics
def setup_monitoring(app: FastAPI):
"""모니터링 설정"""
# Prometheus 미들웨어 추가
app.add_middleware(PrometheusMiddleware)
app.add_route("/metrics", metrics)
# 사용자 정의 메트릭
REQUEST_COUNT = Counter(
'http_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
)
REQUEST_LATENCY = Histogram(
'http_request_duration_seconds',
'HTTP request latency',
['method', 'endpoint']
)
return REQUEST_COUNT, REQUEST_LATENCY
보안 설정
HTTPS 설정 (Nginx)
# nginx/conf.d/fastapi.conf
server {
listen 80;
server_name yourdomain.com;
# HTTP to HTTPS redirect
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://web:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
CI/CD 파이프라인
GitHub Actions 설정
# .github/workflows/deploy.yml
name: Deploy FastAPI Application
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push Docker images
run: |
docker-compose build
docker-compose push
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /path/to/your/app
git pull
docker-compose down
docker-compose pull
docker-compose up -d
성능 최적화
Gunicorn 설정
# gunicorn.conf.py
from multiprocessing import cpu_count
# Gunicorn 설정
bind = "0.0.0.0:8000"
workers = cpu_count() * 2 + 1
worker_class = "uvicorn.workers.UvicornWorker"
keepalive = 5
timeout = 120
graceful_timeout = 30
# 로깅 설정
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
loglevel = "info"
마치며
FastAPI 애플리케이션을 Docker를 사용하여 배포하는 것은 처음에는 복잡해 보일 수 있지만, 위의 설정들을 차근차근 따라하면 안정적이고 확장 가능한 배포가 가능합니다. 실제 운영 환경에서는 보안, 모니터링, 로깅 등 추가적인 고려사항들이 있으니 프로젝트의 요구사항에 맞게 적절히 조정하시기 바랍니다.
'파이썬 > Fast API' 카테고리의 다른 글
FastAPI 미들웨어와 CORS 설정 (0) | 2024.11.26 |
---|---|
JWT를 이용한 FastAPI 사용자 인증 구현하기 (0) | 2024.11.24 |
FastAPI의 데이터베이스 연동 쉽게 이해하기 (2) | 2024.11.23 |
FastAPI 시작하기 - 설치부터 첫 API 만들기까지 (2) | 2024.11.21 |