Home » Создание FastAPI приложения с помощью Docker Compose — пошагово
Создание FastAPI приложения с помощью Docker Compose — пошагово

Создание FastAPI приложения с помощью Docker Compose — пошагово

Сегодня разберём, как собрать и развернуть FastAPI приложение с Docker Compose. Если вы настраиваете серверы и ищете готовые решения для быстрого деплоя Python-приложений, эта статья для вас. Мы пройдём весь путь от создания простого FastAPI сервиса до его контейнеризации и оркестрации через Docker Compose.

Почему именно FastAPI + Docker Compose? Потому что это одна из самых быстрых и удобных связок для создания современных API. FastAPI даёт нам автоматическую генерацию OpenAPI документации, высокую производительность и отличную типизацию. Docker Compose позволяет легко управлять многоконтейнерными приложениями и их зависимостями.

Мы разберём три ключевых вопроса: как это всё работает под капотом, как быстро настроить всё с нуля, и какие подводные камни ждут в продакшене. Плюс покажу несколько нестандартных способов использования и автоматизации.

Как это работает: архитектура решения

Docker Compose позволяет описать всю инфраструктуру приложения в одном YAML-файле. Для FastAPI приложения типичная архитектура включает:

  • Контейнер с FastAPI приложением
  • База данных (PostgreSQL/Redis)
  • Reverse proxy (Nginx)
  • Мониторинг и логирование

Каждый сервис изолирован в своём контейнере, но они могут общаться через внутренние Docker сети. Это даёт нам масштабируемость, воспроизводимость и простоту деплоя.

Пошаговая настройка с нуля

Начнём с создания простого FastAPI приложения. Создайте директорию проекта и следующую структуру:

fastapi-docker/
├── app/
│   ├── __init__.py
│   ├── main.py
│   └── requirements.txt
├── docker-compose.yml
├── Dockerfile
└── .env

Сначала создадим само приложение. В файле app/main.py:

from fastapi import FastAPI
from fastapi.responses import JSONResponse
import asyncio
import os

app = FastAPI(title="FastAPI Docker Demo", version="1.0.0")

@app.get("/")
async def root():
    return {"message": "Hello from FastAPI in Docker!"}

@app.get("/health")
async def health_check():
    return JSONResponse(
        content={"status": "healthy", "environment": os.getenv("ENVIRONMENT", "development")}
    )

@app.get("/info")
async def app_info():
    return {
        "app_name": "FastAPI Docker Demo",
        "version": "1.0.0",
        "python_version": "3.11"
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Файл зависимостей app/requirements.txt:

fastapi==0.104.1
uvicorn[standard]==0.24.0
python-multipart==0.0.6
pydantic==2.5.0

Теперь создадим Dockerfile для нашего приложения:

FROM python:3.11-slim

WORKDIR /app

# Копируем файл зависимостей
COPY app/requirements.txt .

# Устанавливаем зависимости
RUN pip install --no-cache-dir -r requirements.txt

# Копируем код приложения
COPY app/ .

# Открываем порт
EXPOSE 8000

# Команда запуска
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

Создаём файл окружения .env:

ENVIRONMENT=development
DATABASE_URL=postgresql://user:password@postgres:5432/fastapi_db
REDIS_URL=redis://redis:6379

И наконец, главный файл docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "8000:8000"
    env_file:
      - .env
    depends_on:
      - postgres
      - redis
    volumes:
      - ./app:/app
    restart: unless-stopped

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: fastapi_db
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:

Для Nginx создадим простой конфиг nginx.conf:

events {
    worker_connections 1024;
}

http {
    upstream app {
        server app:8000;
    }

    server {
        listen 80;
        
        location / {
            proxy_pass http://app;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Запускаем всё одной командой:

docker-compose up -d

Проверяем статус сервисов:

docker-compose ps
docker-compose logs app

Практические кейсы и подводные камни

Рассмотрим типичные проблемы и их решения:

Проблема Симптом Решение
Медленный старт приложения Долгое время отклика после docker-compose up Добавить healthcheck в docker-compose.yml и использовать depends_on с condition
Потеря данных при рестарте БД пустая после пересоздания контейнеров Обязательно использовать volumes для PostgreSQL
Проблемы с сетью между контейнерами Ошибки подключения к БД Использовать service names вместо localhost в connection strings
Большой размер образа Долгая сборка и деплой Использовать alpine образы и multi-stage builds

Пример улучшенного Dockerfile с multi-stage build:

FROM python:3.11-slim as builder

WORKDIR /app
COPY app/requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

FROM python:3.11-slim

WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY app/ .

ENV PATH=/root/.local/bin:$PATH

EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Продвинутые возможности и автоматизация

Для продакшена добавим мониторинг и логирование. Расширенный docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "8000:8000"
    env_file:
      - .env
    depends_on:
      - postgres
      - redis
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: fastapi_db
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d fastapi_db"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana

volumes:
  postgres_data:
  redis_data:
  grafana_data:

Создадим скрипт для автоматического деплоя deploy.sh:

#!/bin/bash

echo "Pulling latest changes..."
git pull origin main

echo "Building and starting services..."
docker-compose down
docker-compose build --no-cache
docker-compose up -d

echo "Waiting for services to be ready..."
sleep 30

echo "Running health checks..."
curl -f http://localhost:8000/health || exit 1

echo "Deployment completed successfully!"

Для автоматизации CI/CD можно использовать GitHub Actions. Создайте .github/workflows/deploy.yml:

name: Deploy FastAPI App

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Deploy to server
      uses: appleboy/ssh-action@v0.1.5
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.SSH_KEY }}
        script: |
          cd /path/to/your/app
          git pull origin main
          docker-compose down
          docker-compose up -d --build

Альтернативные решения и сравнение

Существует несколько альтернатив Docker Compose для оркестрации:

  • Kubernetes — избыточен для простых приложений, но незаменим для больших кластеров
  • Docker Swarm — проще K8s, но менее функционален
  • Podman Compose — drop-in замена Docker Compose без демона
  • Vagrant — для виртуализации на уровне ОС

Статистика показывает, что Docker Compose используется в 73% проектов для локальной разработки и 41% для продакшена (согласно Docker State of Application Development Report 2023).

Полезные команды для работы

# Запуск в фоновом режиме
docker-compose up -d

# Просмотр логов конкретного сервиса
docker-compose logs -f app

# Перезапуск отдельного сервиса
docker-compose restart app

# Выполнение команды в контейнере
docker-compose exec app bash

# Просмотр используемых ресурсов
docker-compose top

# Остановка и удаление всех контейнеров
docker-compose down -v

# Пересборка образов
docker-compose build --no-cache

# Масштабирование сервиса
docker-compose up -d --scale app=3

Интересные факты и нестандартные применения

Docker Compose можно использовать не только для веб-приложений. Несколько креативных применений:

  • Тестирование — запуск тестовых сред с разными версиями зависимостей
  • Данные — ETL пайплайны с Apache Airflow и FastAPI
  • ML — развертывание ML моделей с Jupyter, MLflow и FastAPI
  • Микросервисы — связка FastAPI + RabbitMQ + Celery для фоновых задач

Для машинного обучения можно добавить в docker-compose.yml:

  jupyter:
    image: jupyter/tensorflow-notebook:latest
    ports:
      - "8888:8888"
    volumes:
      - ./notebooks:/home/jovyan/work
    environment:
      - JUPYTER_ENABLE_LAB=yes

  mlflow:
    image: python:3.11-slim
    ports:
      - "5000:5000"
    command: |
      bash -c "pip install mlflow && mlflow server --host 0.0.0.0 --port 5000"
    volumes:
      - mlflow_data:/mlflow

volumes:
  mlflow_data:

Деплой на продакшен

Для продакшена рекомендую использовать VPS или выделенный сервер. Основные изменения для продакшена:

  • Использование production-ready WSGI сервера (Gunicorn)
  • Настройка SSL через Let’s Encrypt
  • Логирование в centralized системы
  • Бэкапы БД
  • Мониторинг и алерты

Пример продакшен docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    environment:
      - ENVIRONMENT=production
    depends_on:
      - postgres
      - redis
    restart: unless-stopped
    
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx-prod.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - app
    restart: unless-stopped

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./backups:/backups
    restart: unless-stopped

volumes:
  postgres_data:

Заключение и рекомендации

Docker Compose + FastAPI — это мощная связка для создания современных API. Главные преимущества:

  • Быстрый старт — от идеи до работающего приложения за минуты
  • Воспроизводимость — одинаковое окружение на всех этапах
  • Масштабируемость — легко добавлять новые сервисы
  • Изоляция — каждый компонент в своём контейнере

Рекомендую использовать этот подход для:

  • Прототипирования API
  • Микросервисных архитектур
  • Локальной разработки
  • Небольших и средних продакшен приложений

Для крупных высоконагруженных проектов стоит рассмотреть переход на Kubernetes, но Docker Compose отлично покрывает 80% задач. Главное — не забывайте про бэкапы, мониторинг и security best practices.

Полезные ссылки:


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.

Leave a reply

Your email address will not be published. Required fields are marked