코샵
끄적끄적 코딩 공방
코샵

인기 글

  • 분류 전체보기 (472) N
    • MongoDB (4)
    • 일기장 (4)
    • Unity (138)
      • Tip (41)
      • Project (1)
      • Design Pattern (8)
      • Firebase (6)
      • Asset (2)
    • 파이썬 (127) N
      • Basic (40) N
      • OpenCV (8)
      • Pandas (15)
      • PyQT (3)
      • SBC(Single Board Computer) (1)
      • 크롤링 (14) N
      • Fast API (29)
      • Package (6)
    • Linux (4)
    • C# (97)
      • Algorithm (11)
      • Window (7)
    • TypeScript (41) N
      • CSS (3) N
    • Git (11)
    • SQL (5)
    • Flutter (10)
      • Tip (1)
    • System (1)
    • BaekJoon (6)
    • Portfolio (2)
    • MacOS (1)
    • 유틸리티 (1)
    • 서비스 (6) N
    • 자동화 (3)
    • Hobby (10)
      • 물생활 (10)
      • 식집사 (0)
전체 방문자
오늘
어제

최근 댓글

최근 글

반응형
hELLO · Designed By 정상우.
코샵

끄적끄적 코딩 공방

파이썬/Fast API

FastAPI 애플리케이션 Docker로 배포하기

2024. 11. 27. 10:15
반응형

소개

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 : 병렬 처리로 API 성능 최적화  (1) 2024.12.04
FastAPI 애플리케이션 성능 최적화와 캐싱  (0) 2024.11.28
FastAPI 미들웨어와 CORS 설정  (0) 2024.11.26
JWT를 이용한 FastAPI 사용자 인증 구현하기  (0) 2024.11.24
FastAPI의 데이터베이스 연동 쉽게 이해하기  (5) 2024.11.23
    '파이썬/Fast API' 카테고리의 다른 글
    • FastAPI : 병렬 처리로 API 성능 최적화
    • FastAPI 애플리케이션 성능 최적화와 캐싱
    • FastAPI 미들웨어와 CORS 설정
    • JWT를 이용한 FastAPI 사용자 인증 구현하기
    코샵
    코샵
    나의 코딩 일기장

    티스토리툴바