Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Docker и Деплой
docker_deploy

Docker и Деплой

Dockerfile, docker-compose, Gunicorn, Nginx, CI/CD, production settings

Docker и deployment Django

Статус: актуально для Django 5.2/6.0 и Python 3.12+. Конкретные patch-версии base image, server и системных библиотек нужно регулярно обновлять и фиксировать lock-файлом/digest.

Контейнер — способ доставить один и тот же собранный артефакт в staging и production. Он не делает приложение автоматически stateless, безопасным или отказоустойчивым. Эти свойства появляются из архитектуры и процесса deployment.

Хороший application container:

  • не хранит единственную копию данных в writable layer;
  • запускается с read-only конфигурацией и runtime secrets;
  • работает не от root;
  • пишет логи в stdout/stderr;
  • корректно получает SIGTERM и завершает запросы;
  • не выполняет непредсказуемые миграции при старте каждой реплики.

База, пользовательские файлы, cache и broker живут во внешних сервисах или управляемых volumes с отдельной политикой backup. «Вынесли из контейнера» ещё не означает «можно восстановить» — restore нужно проверять.

#Production stack бывает разным

Internet -> CDN/LB/Ingress -> WSGI или ASGI server -> Django | | workers PostgreSQL Redis storage

Nginx может завершать TLS, ограничивать тело запроса, буферизовать slow clients и раздавать static. В managed platform эти задачи часто выполняют load balancer, ingress и CDN; отдельный Nginx-контейнер не является обязательным признаком production.

Для синхронного приложения часто используют Gunicorn с WSGI. Для полностью async stack — Uvicorn/Daphne/Hypercorn или Gunicorn с актуальным ASGI worker. Выбор server и worker class должен соответствовать уроку про async.

Стандартный runserver — development server. Он многопоточный по умолчанию, но не проходил production security/performance review и прямо не предназначен для deployment. Причина отказа от него не в мифе «он всегда один поток».

#Multi-stage Dockerfile

Ниже учебный каркас, а не универсальный готовый образ. Системные runtime libraries зависят от используемых wheels, Pillow, database driver и других пакетов.

# syntax=docker/dockerfile:1 FROM python:3.12-slim AS builder ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \ PIP_NO_CACHE_DIR=1 RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:${PATH}" WORKDIR /build COPY requirements.lock ./ RUN python -m pip install --require-hashes -r requirements.lock FROM python:3.12-slim AS runtime ENV PATH="/opt/venv/bin:${PATH}" \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 RUN groupadd --gid 10001 app \ && useradd --uid 10001 --gid app --no-create-home app WORKDIR /app COPY --from=builder /opt/venv /opt/venv COPY --chown=app:app . /app USER 10001:10001 EXPOSE 8000 CMD ["gunicorn", "config.wsgi:application", "--bind=0.0.0.0:8000", "--access-logfile=-", "--error-logfile=-"]

Multi-stage build удаляет compiler/build headers из runtime image, но не гарантирует маленький или безопасный образ. Просмотрите слои, CVE scan и фактически импортируемые runtime libraries.

В реальном проекте:

  • фиксируйте Python base хотя бы patch-версией, а для строгой воспроизводимости — digest;
  • регулярно обновляйте этот digest, иначе «immutable» станет «навсегда уязвимым»;
  • устанавливайте зависимости из lock с hashes;
  • копируйте dependency-файлы раньше исходников для build cache;
  • не включайте dev tools и test data в runtime stage;
  • задавайте worker count/timeouts из окружения и нагрузочного теста, а не из магического 3.

Если dependency build требует compiler/system headers, установите их только в builder. Нужные shared libraries всё равно должны присутствовать в runtime stage.

#Build context и секреты

.git .env .venv __pycache__ *.pyc db.sqlite3 media .pytest_cache node_modules

.dockerignore уменьшает context и не даёт случайно скопировать локальные credentials. Но файл уже отправленный builder или записанный в слой не становится секретным после последующего RUN rm.

Не передавайте секрет через ARG/ENV Dockerfile и не встраивайте production .env. Если приватный registry нужен во время build, используйте BuildKit secret/SSH mount так, чтобы credential не попал в слой. Runtime secrets получает deployment platform: secret manager, mounted secret file или защищённое окружение.

Build logs и provenance тоже могут раскрыть аргументы. Не выводите credentials диагностическими командами.

#Static files: выберите одну стратегию

collectstatic собирает static всех apps в STATIC_ROOT; при ManifestStaticFilesStorage создаёт content-hashed names. Запускать его можно при build, если для build settings не нужны production secrets и database.

Распространённые стратегии:

  1. собрать static в application image и отдавать через WhiteNoise;
  2. собрать отдельный Nginx/static image из того же build stage;
  3. загрузить versioned assets в object storage/CDN как release step.

Named volume между Nginx и web не заполняется магически содержимым image. Если каждый web container запускает collectstatic в общий volume, появляются гонки и mutable release artifact.

Пользовательские media не относятся к collectstatic. Их хранят отдельно; application replicas не должны полагаться на локальный /app/media.

Современная настройка:

STORAGES = { "default": { "BACKEND": "myproject.storage.MediaStorage", }, "staticfiles": { "BACKEND": ( "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" ), }, }

После сборки проверьте, что HTML и image действительно ссылаются на существующие manifest assets. CDN rollout должен учитывать, что старые replicas ещё возвращают старые имена.

#Миграции — отдельный deployment step

Миграция не выполняется при docker build: сборка не должна зависеть от конкретной production database. Также не запускайте migrate в entrypoint каждой web replica. Несколько replicas начнут один DDL одновременно, а startup приложения будет зависеть от долгой блокировки schema.

Типовая последовательность:

build once -> tests/scan -> push immutable image -> one-off migration job -> rolling/blue-green application rollout -> post-deploy checks

Для zero-downtime миграции должны быть совместимы с прежним и новым кодом. Используйте expand/contract:

  1. добавить nullable column/table/index без удаления прежнего;
  2. deploy код, умеющий жить с обеими схемами;
  3. выполнить backfill небольшими батчами;
  4. переключить чтение и проверить;
  5. в следующем release удалить старую схему.

Переименование или NOT NULL на большой таблице может получить долгую блокировку. Изучите SQL через sqlmigrate, особенности вашей СУБД и план rollback. Откат application image после несовместимой schema migration может быть уже невозможен.

Если migration job успешна, а rollout провалился, возвращайте только код, совместимый с расширенной схемой. Не применяйте обратную destructive migration автоматически.

#Health: startup, readiness и liveness

Один /health/ редко отвечает на все вопросы.

  • liveness: процесс способен обслуживать event loop/request; провал приводит к restart;
  • readiness: replica может получать пользовательский трафик;
  • startup: медленно стартующий процесс ещё не нужно перезапускать.

Liveness должна быть дешёвой и не падать из-за краткого сбоя необязательного upstream, иначе platform перезапустит все здоровые processes. Readiness может проверить критическую database/cache зависимость с коротким timeout, но не должна изменять данные, раскрывать версии/секреты или выполнять тяжёлый запрос.

Health endpoint не заменяет миграционный контроль. Если старый код несовместим со schema, лучше остановить rollout раньше.

#Docker Compose: полезен, но не оркестратор сам по себе

services: web: build: context: . target: runtime env_file: .env command: gunicorn config.wsgi:application --bind=0.0.0.0:8000 depends_on: db: condition: service_healthy init: true db: image: postgres:17 environment: POSTGRES_DB: app POSTGRES_USER: app POSTGRES_PASSWORD: local-only-password volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U app -d app"] interval: 5s timeout: 3s retries: 10 volumes: pgdata:

Это local example: пароль не годится для production, порт базы не публикуется наружу. depends_on с service_healthy помогает startup order в Compose, но не делает приложение устойчивым к перезапуску базы через час. Django и workers должны иметь ограниченные retries/backoff и корректно восстанавливать connections.

Compose может применяться на одном production host, если команда сознательно принимает ограничения. Для нескольких hosts нужны platform primitives для rollout, placement, secrets, readiness, autoscaling и recovery.

#HTTPS и trusted proxy

DEBUG = False SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] ALLOWED_HOSTS = ["app.example.com"] SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True

SECURE_PROXY_SSL_HEADER добавляют только если контролируемый proxy удаляет пользовательский заголовок и сам выставляет протокол:

SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

Проверьте, что прямой доступ к application container закрыт, proxy задаёт Host/protocol однозначно, а body/header/timeouts ограничены до Django. HSTS вводите постепенно, как описано в security-уроке.

#Graceful shutdown

При rolling deployment platform отправляет SIGTERM, убирает replica из балансировки и ждёт grace period. Web server должен перестать принимать новые запросы и дать текущим завершиться. Timeout load balancer, server graceful timeout и platform termination grace согласуют между собой.

PID 1 в container обязан получать signals и собирать дочерние процессы. Exec-form CMD и init: true в Compose помогают. Shell entrypoint в конце должен использовать exec "$@", иначе signal может остаться у shell.

Длинную работу не держите в HTTP request. Celery worker при shutdown требует отдельной настройки: soft shutdown, task acknowledgment и visibility timeout связаны с delivery semantics.

#CI/CD: собрать один раз, продвигать по digest

Надёжный pipeline обычно выполняет:

  1. lint/type checks, unit/integration tests и проверку миграций;
  2. сборку одного image;
  3. SBOM и vulnerability/secret scan;
  4. подпись/attestation согласно требованиям платформы;
  5. push в registry с git SHA и immutable digest;
  6. deployment того же digest в staging, затем production;
  7. migration job, rollout, smoke tests и наблюдение метрик.

Не пересобирайте «тот же release» отдельно для production: получите другой набор пакетов. Тег latest можно оставить удобным указателем, но deployment должен знать digest/SHA.

CI credentials получают минимальные permissions и короткий срок жизни, предпочтительно через workload identity/OIDC. SSH-команда из одного YAML-примера не является полноценной безопасной delivery system.

#Zero-downtime состоит из нескольких свойств

Blue-green или rolling rollout — только механизм переключения. Нужны также:

  • backward-compatible schema и API;
  • readiness до включения replica в traffic;
  • connection draining и graceful shutdown;
  • capacity для старой и новой версии одновременно;
  • versioned static assets;
  • rollback-план, учитывающий database migration;
  • canary/метрики ошибок, latency и бизнес-операций.

«Быстро перезапустить один server» не является zero-downtime. Blue-green без совместимой базы тоже не гарантирует откат.

#Production checklist

  • образ воспроизводим, обновляем, сканируется и запускается non-root;
  • .dockerignore и BuildKit secrets не пропускают credentials в layers;
  • static strategy протестирована, media вынесены во внешний storage;
  • migration выполняет одна release job, используется expand/contract;
  • readiness/liveness различены, endpoint не раскрывает данные;
  • proxy headers, HTTPS, request limits и source IP настроены по реальной цепочке;
  • процессы завершаются graceful и не теряют задачи;
  • один digest проходит staging и production;
  • есть backup, проверенный restore и rollback runbook;
  • manage.py check --deploy запускается с production settings.

#Legacy и исправления

  • Образы python:3.11-slim из прежнего урока заменены целевой линией Python 3.12+.
  • runserver удалён из production-сценария, но причина сформулирована корректно: это dev server, а не обязательно «один поток».
  • migrate в entrypoint каждой replica признан опасным; используется one-off release job.
  • Общий пустой static volume между Nginx и web не считается рабочей стратегией без явного шага наполнения.
  • Nginx и Docker Compose — возможные инструменты, а не обязательные слои любого Django deployment.

#Официальная документация

  • Django: deployment checklist
  • Django: WSGI deployment
  • Django: ASGI deployment
  • Docker: multi-stage builds
  • Docker: build secrets

Далее: Мониторинг и Логирование