Развертывание Python-приложения в production — это не просто python app.py. Когда твое приложение начинает получать реальный трафик, тебе нужен надежный, масштабируемый и производительный WSGI-сервер. Давай разберем, как правильно настроить Gunicorn, чтобы твое приложение работало стабильно под нагрузкой.
Что такое Gunicorn и зачем он нужен?
Gunicorn (Green Unicorn) — это WSGI HTTP-сервер для Python, написанный на чистом Python. Он работает как прокси между твоим веб-сервером (Nginx/Apache) и Python-приложением. Основные преимущества:
- Простота настройки: Минимальная конфигурация для старта
- Производительность: Использует pre-fork worker модель
- Совместимость: Работает с любым WSGI-совместимым фреймворком (Django, Flask, FastAPI через специальные воркеры)
- Надежность: Автоматическое перезапуск упавших воркеров
Установка и базовая настройка Gunicorn
Установка через pip
# Установка в виртуальное окружение
pip install gunicorn
# Или с указанием версии
pip install gunicorn==20.1.0
Базовый запуск приложения
Представь, что у тебя есть Flask-приложение в файле app.py:
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
Запуск Gunicorn с базовыми параметрами:
# Базовый запуск
# app:app — модуль:экземпляр приложения
gunicorn app:app
# С указанием хоста и порта
gunicorn --bind 0.0.0.0:8000 app:app
# С 4 воркерами
gunicorn --workers 4 --bind 0.0.0.0:8000 app:app
Конфигурационные файлы Gunicorn
Для production-развертывания используй конфигурационные файлы вместо передачи параметров через командную строку.
Python-конфигурация (gunicorn.conf.py)
# gunicorn.conf.py
import multiprocessing
# Базовые настройки
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
# Логирование
accesslog = "-" # stdout
errorlog = "-" # stdout
loglevel = "info"
# Таймауты
timeout = 30
keepalive = 2
# Безопасность
limit_request_line = 4096
limit_request_fields = 100
limit_request_field_size = 8190
# Перезагрузка при изменении кода (только для development!)
reload = False
Запуск с конфигурационным файлом
# Указание конфигурационного файла
gunicorn -c gunicorn.conf.py app:app
# Или если файл называется по-другому
gunicorn --config python:config.gunicorn app:app
Оптимизация воркеров Gunicorn
Выбор правильного типа и количества воркеров — ключ к производительности.
Типы воркеров
| Тип воркера | Описание | Когда использовать |
|---|---|---|
| sync | Синхронный (по умолчанию) | Быстрые, CPU-intensive задачи |
| gevent | Асинхронный на основе greenlets | Много I/O операций, WebSockets |
| eventlet | Асинхронный (альтернатива gevent) | Аналогично gevent |
| gthread | Потоковый воркер | Приложения с GIL-блокировками |
| uvicorn.workers.UvicornWorker | Для ASGI приложений (FastAPI) | FastAPI, Starlette, ASGI-приложения |
Расчет количества воркеров
# Оптимальная формула для CPU-bound задач
workers = (2 * cpu_cores) + 1
# Для I/O bound задач можно увеличить
# Пример для 4-ядерного процессора:
import multiprocessing
cpu_cores = multiprocessing.cpu_count() # 4
workers = cpu_cores * 2 + 1 # 9 воркеров
# Для gevent/eventlet устанавливаем большое количество соединений
worker_connections = 1000
Конфигурация для разных типов приложений
# Для Django (синхронный)
workers = 3
worker_class = "sync"
timeout = 30
# Для Flask с I/O операциями
workers = 2
worker_class = "gevent"
worker_connections = 1000
# Для FastAPI (ASGI)
workers = 4
worker_class = "uvicorn.workers.UvicornWorker"
# Для CPU-intensive приложений
workers = multiprocessing.cpu_count()
worker_class = "sync"
threads = 2 # если используешь gthread
Интеграция с systemd для автозапуска
Для production-сервера настрой автозапуск через systemd.
Создание systemd сервиса
# /etc/systemd/system/myapp.service
[Unit]
Description=Gunicorn instance for myapp
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment="PATH=/var/www/myapp/venv/bin"
ExecStart=/var/www/myapp/venv/bin/gunicorn \
--config /var/www/myapp/gunicorn.conf.py \
app:app
# Перезагрузка при сбое
Restart=always
RestartSec=3
# Лимиты ресурсов
LimitNOFILE=65535
LimitNPROC=65535
[Install]
WantedBy=multi-user.target
Управление сервисом
# Перезагрузка systemd
sudo systemctl daemon-reload
# Запуск сервиса
sudo systemctl start myapp
# Автозапуск при загрузке
sudo systemctl enable myapp
# Проверка статуса
sudo systemctl status myapp
# Просмотр логов
sudo journalctl -u myapp -f
Настройка Nginx как reverse proxy
Nginx будет принимать HTTP-запросы и проксировать их на Gunicorn.
# /etc/nginx/sites-available/myapp
server {
listen 80;
server_name example.com;
# Статические файлы
location /static/ {
alias /var/www/myapp/static/;
expires 30d;
}
location /media/ {
alias /var/www/myapp/media/;
expires 30d;
}
# Проксирование на Gunicorn
location / {
proxy_pass http://127.0.0.1:8000;
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;
# Таймауты
proxy_connect_timeout 75s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
}
# Запрет доступа к скрытым файлам
location ~ /\. {
deny all;
}
}
Мониторинг и логирование
Настройка логов Gunicorn
# В gunicorn.conf.py
import logging
import sys
# Файлы для логов
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
loglevel = "info"
# Формат логов
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
# Кастомный логгер для ошибок
logger_class = "myapp.logging.CustomLogger"
# Захват stdout/stderr
capture_output = True
enable_stdio_inheritance = False
Мониторинг метрик
Gunicorn предоставляет статистику через арбитр (arbiter):
# Отправка сигналов для получения статистики
# Получение информации о воркерах
kill -TTIN $(cat /var/run/gunicorn.pid)
# Graceful перезагрузка
kill -HUP $(cat /var/run/gunicorn.pid)
# Просмотр PID мастер-процесса
cat /var/run/gunicorn.pid
Продвинутые настройки и оптимизации
Настройка для высоких нагрузок
# gunicorn.conf.py для high-load
import multiprocessing
# Базовые настройки
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 3
worker_class = "gevent"
worker_connections = 2000
# Оптимизация производительности
max_requests = 1000
max_requests_jitter = 50
# Keep-alive
keepalive = 5
# Безопасность и лимиты
backlog = 2048
limit_request_line = 4096
limit_request_fields = 100
# Graceful shutdown
graceful_timeout = 30
timeout = 120
# Preload приложения для экономии памяти
preload_app = True
# Установка nice значения
# (только если запускаешь от root)
# pidfile = "/var/run/gunicorn.pid"
# umask = 0o007
# user = "www-data"
# group = "www-data"
Docker-конфигурация
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Создание пользователя для безопасности
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
# Запуск Gunicorn
CMD ["gunicorn", "--config", "gunicorn.conf.py", "app:app"]
Типичные проблемы и их решение
1. Воркеры умирают из-за таймаута
timeout в конфигурации. Для долгих операций (загрузка файлов, API-запросы) установи timeout = 120 или больше.
2. Высокое потребление памяти
Симптомы: воркеры постоянно перезапускаются, система использует swap.
# Решения:
# 1. Уменьши количество воркеров
workers = 2 # вместо workers = cpu_count * 2 + 1
# 2. Включи preload_app
preload_app = True
# 3. Используй max_requests для периодического перезапуска
max_requests = 1000
max_requests_jitter = 100
3. Медленная загрузка статических файлов
/static/ и /media/ путей.
4. 502 Bad Gateway от Nginx
Проверь:
- Запущен ли Gunicorn:
sudo systemctl status myapp - Слушает ли порт:
sudo netstat -tlnp | grep 8000 - Правильность proxy_pass в Nginx конфиге
- Достаточно ли памяти/CPU
Проверка и тестирование конфигурации
# Проверка синтаксиса конфигурационного файла
gunicorn --check-config -c gunicorn.conf.py app:app
# Тестовый запуск в foreground
gunicorn --config gunicorn.conf.py app:app
# Проверка количества воркеров после запуска
ps aux | grep gunicorn
# Проверка открытых портов
sudo ss -tlnp | grep :8000
# Тестирование под нагрузкой (установи ab или wrk)
ab -n 1000 -c 10 http://localhost:8000/
Безопасность Gunicorn
- Запуск от непривилегированного пользователя: Никогда не запускай Gunicorn от root
- Изоляция: Используй virtualenv или Docker для изоляции зависимостей
- Файловые permissions: Правильно настрой права на конфигурационные файлы и логи
- Биндинг: В production биндись только на localhost (127.0.0.1), а не на 0.0.0.0
- Лимиты запросов: Используй
limit_request_*параметры для защиты от больших запросов
# Безопасная конфигурация
# В gunicorn.conf.py
# Биндинг только на localhost
bind = "127.0.0.1:8000"
# Лимиты для защиты от DoS
limit_request_line = 4096
limit_request_fields = 100
limit_request_field_size = 8190
# Запуск от непривилегированного пользователя
# (указывается в systemd сервисе или при запуске)
# user = "www-data"
# group = "www-data"
Чеклист production-развертывания
- ✓ Настроен конфигурационный файл gunicorn.conf.py
- ✓ Оптимальное количество и тип воркеров
- ✓ Настроен systemd сервис для автозапуска
- ✓ Nginx настроен как reverse proxy
- ✓ Статические файлы обслуживаются Nginx
- ✓ Настроено логирование в файлы
- ✓ Реализован мониторинг (метрики, здоровье)
- ✓ Настроены параметры безопасности
Настройка Gunicorn — это баланс между производительностью, стабильностью и потреблением ресурсов. Начни с базовой конфигурации, мониторь метрики (CPU, память, response time) и постепенно оптимизируй под специфику твоего приложения. Помни: идеальной конфигурации для всех не существует — то, что работает для I/O-bound Flask-приложения, не подойдет для CPU-intensive Django-проекта.