Автоматизация развертывания Django‑приложений снижает число ручных ошибок, ускоряет релизы и делает инфраструктуру воспроизводимой. На практике сочетание GitLab CI и Docker‑Compose позволяет построить понятный пайплайн: сборка артефактов (при необходимости), подготовка миграций, обновление образов и запуск сервисов в целевой среде.
Ниже — архитектурный подход, пример структуры репозитория и развернутый сценарий CI/CD, с учетом актуальных требований и лучших практик безопасности, применимых в РФ (включая вопросы защиты персональных данных, секретов и контроль доступа).
Цели и требования к автоматизации
Для промышленного проекта важно заранее сформулировать:
- Повторяемость: развертывание должно быть идентичным между окружениями (dev/stage/prod).
- Безопасность: секреты (SECRET_KEY, пароли БД, токены) не должны попадать в репозиторий или логи.
- Управление миграциями: миграции Django должны выполняться предсказуемо и только там, где это нужно.
- Наблюдаемость: логи и коды возврата должны корректно обрабатываться пайплайном.
- Минимальные простои: по возможности выполнять плавные обновления (или хотя бы контролируемое перезапуск/пересоздание).
Если в приложении обрабатываются персональные данные, проект должен соответствовать требованиям законодательства РФ и локальным политикам по защите информации (включая режимы доступа, учет и минимизацию данных). Автоматизация деплоя должна поддерживать эти процессы: изолировать окружения, ограничивать доступ к инфраструктуре и секретам, обеспечивать аудит действий.
Архитектура: Docker‑Compose как единица окружения
Docker‑Compose удобен тем, что описывает окружение декларативно. Обычно Django‑приложение раскладывают на:
- web — контейнер приложения (gunicorn/uwsgi);
- db — PostgreSQL (или другая СУБД);
- redis — очередь/кэш (опционально);
- nginx — веб‑сервер и TLS (опционально, часто выносится отдельно);
- worker — фоновые задачи (Celery, опционально).
Хорошая практика — не смешивать “build” и “runtime” логики. Например, Dockerfile формирует образ приложения, а docker‑compose определяет, как он запускается и как подключаются зависимости.
Подготовка репозитория
Пример структуры (минимально необходимое):
repo/
.gitlab-ci.yml
docker/
Dockerfile
docker-compose.yml
docker-compose.prod.yml
manage.py
requirements.txt
mysite/
settings.py
urls.py
app/
models.py
scripts/
wait-for-db.sh
migrate.sh
Важно: конфигурацию следует разделять. Например, для prod можно держать отдельный compose-файл или переменные окружения, чтобы не смешивать dev и production параметры.
Dockerfile для Django (под gunicorn)
Обычно Django запускают через gunicorn. Пример Dockerfile (упрощенный):
# docker/Dockerfile
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1
PYTHONUNBUFFERED=1
WORKDIR /app
# Установка зависимостей
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копирование проекта
COPY . .
# Сбор статики (если используется WhiteNoise/или nginx)
# Можно выполнять в CI на этапе сборки или здесь, если статика версионируется.
# RUN python manage.py collectstatic --noinput
# Порт
EXPOSE 8000
CMD ["gunicorn", "mysite.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]
В проде желательно вынести сборку статических файлов в отдельный шаг (либо в CI, либо в образ). Это уменьшает расхождения и ускоряет деплой.
docker-compose.yml и профили окружений
Пример базового compose (development/общий):
# docker-compose.yml
version: "3.9"
services:
web:
build:
context: .
dockerfile: docker/Dockerfile
env_file:
- .env
depends_on:
- db
ports:
- "8000:8000"
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: change-me
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Для прод‑сценария чаще добавляют отдельный файл (или используют override):
# docker-compose.prod.yml
version: "3.9"
services:
web:
image: registry.example.com/group/project/web:${CI_COMMIT_SHORT_SHA}
env_file:
- .env.prod
depends_on:
- db
db:
# Для prod лучше не пересоздавать DB без необходимости.
# Имя томов и параметры должны быть стабильны.
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Ключевой момент: .env и особенно .env.prod не должны храниться в git. Их нужно подставлять на сервере безопасно (через CI, secret store, переменные GitLab и т.п.).
Управление миграциями Django
В проде важно выполнить миграции Django в контролируемом порядке. Типовой сценарий: поднять/обновить БД‑контейнеры (если нужно), затем запустить миграции в отдельном одноразовом контейнере или через команду в существующем web‑контейнере.
Пример скрипта для миграций:
# scripts/migrate.sh
#!/usr/bin/env sh
set -eu
python manage.py migrate --noinput
# При необходимости: python manage.py collectstatic --noinput
В CI это можно выполнить так (через docker-compose run/exec). Однако предпочтительнее одноразовый контейнер с командой, чтобы не зависеть от текущего процесса web.
GitLab CI: общая схема пайплайна
Схема обычно включает стадии:
- build: сборка Docker‑образа и публикация в registry GitLab (или внешний).
- deploy: подключение к серверу, pull образа, запуск docker‑compose с обновлением сервисов.
- migrations (часто внутри deploy): выполнение миграций до запуска обновленного web или сразу после.
Важная рекомендация: разделяйте деплой на разные окружения через protected branches и environment в GitLab, чтобы исключить случайные релизы в prod.
Пример .gitlab-ci.yml (build + deploy)
Ниже — пример концептуального .gitlab-ci.yml. Точные параметры зависят от вашей инфраструктуры (ssh, runner, доступов к registry, структуру серверов).
stages:
- build
- deploy
variables:
DOCKER_TLS_CERTDIR: ""
IMAGE_TAG: "${CI_COMMIT_SHORT_SHA}"
WEB_IMAGE: "${CI_REGISTRY_IMAGE}/web:${IMAGE_TAG}"
build:web:
stage: build
image: docker:27
services:
- name: docker:27-dind
command: ["--tls=false"]
script:
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"
- docker build -f docker/Dockerfile -t "${WEB_IMAGE}" .
- docker push "${WEB_IMAGE}"
only:
- main
deploy:stage:
stage: deploy
image: alpine:3.20
variables:
GIT_STRATEGY: none
environment:
name: stage
only:
- main
before_script:
- apk add --no-cache openssh-client docker-cli
# Пример: ключ для доступа по SSH хранится в GitLab CI/CD variables как protected secret.
# Не выводите приватные ключи в логи.
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" | tr -d '
' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H "$STAGE_HOST" >> ~/.ssh/known_hosts
script:
- ssh "$STAGE_USER@$STAGE_HOST" "
set -eu;
cd /opt/myapp;
export WEB_IMAGE='${WEB_IMAGE}';
# На сервере должны существовать docker-compose.prod.yml (или stage override) и шаблон env.
# Обновление образа
docker login -u '${CI_REGISTRY_USER}' -p '${CI_REGISTRY_PASSWORD}' '${CI_REGISTRY}';
docker pull ${WEB_IMAGE};
# Перед поднятием можно прогнать миграции отдельной командой.
docker compose -f docker-compose.prod.yml --env-file .env.stage run --rm web sh -c 'python manage.py migrate --noinput';
# Обновление сервисов
docker compose -f docker-compose.prod.yml --env-file .env.stage up -d --remove-orphans;
"
Для prod добавьте отдельный job deploy:prod, включите только по необходимости (например, по тегам или ручному подтверждению). Пример:
deploy:prod:
stage: deploy
image: alpine:3.20
environment:
name: production
when: manual
only:
- tags
# Далее аналогично deploy:stage, но с PROD_HOST/PROD_USER и env-файлом .env.prod
Секреты и соответствие требованиям безопасности
Секреты (SECRET_KEY, пароль БД, токены) нужно хранить в:
- GitLab CI/CD Variables (masked, protected);
- Vault/secret store (если используете);
- или на сервере — через защищенные механизмы доступа.
Критично избегать следующих ошибок:
- Хранить пароли в репозитории (включая .env файлы).
- Выводить env в лог (например, случайно сделать
set -xили echo секретов). - Давать неограниченный доступ к runner’у или SSH‑ключам.
Если система обрабатывает персональные данные, то автоматизация деплоя должна быть частью общего контура ИБ: ограничение доступа, аудит действий, учет изменений, изоляция окружений и минимизация распространения данных (например, не передавать PII в CI).
Сетевая доступность, TLS и reverse proxy
Часто Django за nginx с TLS. В docker‑compose можно держать nginx отдельно либо использовать внешний ingress. Для прод‑настроек:
- Храните сертификаты защищенно (например, на сервере через ограниченный доступ).
- Логи nginx и приложения должны попадать в систему мониторинга (ELK/Graylog/Loki и т.д.).
- Ограничьте доступ к admin/health endpoints по требованиям проекта.
Надежность: таймауты, healthchecks и порядок операций
В CI и compose добавляйте:
- wait-for-db / healthcheck для БД, чтобы миграции не падали из‑за гонок старта.
- Проверки кода возврата: если миграции не прошли — деплой должен быть остановлен.
- Политику повторов только на уровне, где это допустимо (например, retry для pull образов или сетевых операций).
Пример wait script (упрощенный):
# scripts/wait-for-db.sh
#!/usr/bin/env sh
set -eu
HOST="${1:?db host required}"
PORT="${2:?db port required}"
until nc -z "$HOST" "$PORT"; do
echo "Waiting for db at $HOST:$PORT..."
sleep 2
done
Работа с версиями и миграциями в команде
Чтобы избежать конфликтов, применяйте подход:
- Каждый merge в main приводит к сборке образа с конкретным тегом.
- Миграции выполняются на том же уровне, что и деплой (в stage/prod по согласованному порядку).
- Командой поддерживается практика: миграции должны быть совместимыми (особенно при наличии нескольких инстансов приложения).
При необходимости масштабирования учитывайте, что при запуске нескольких web‑процессов миграции не должны выполняться параллельно. Обычно решается тем, что миграции запускаются отдельным одноразовым контейнером до up -d.
Рекомендации по масштабированию процесса релизов
Чтобы сделать процесс зрелым:
- Используйте GitLab Environments и deployment approvals (manual approval для prod).
- Включите требования к доступам: только определенные роли могут запускать pipeline на прод.
- Добавьте статусные проверки: health endpoint, readiness/liveness (на уровне контейнера или orchestration).
- Следите за политикой удаления старых образов в registry.
Заключение
Автоматизация деплоя Django‑приложений через GitLab CI и Docker‑Compose — практичный путь к воспроизводимым релизам. Ключевые элементы успешной реализации:
- Декларативное описание окружений в compose.
- Строгая дисциплина с секретами и доступами.
- Контролируемое выполнение миграций Django.
- Стабильность пайплайна: healthchecks, таймауты, корректные коды возврата.
- Учет требований по защите информации, включая случаи обработки персональных данных.
Такой подход особенно ценен в реальной эксплуатации: меньше ручных действий, прозрачный аудит изменений и предсказуемость результата.
Услуги РыбинскЛАБ
Если хотите внедрить CI/CD для Django «под ключ» (архитектура, Dockerfile/compose, GitLab CI, безопасное хранение секретов, миграции, деплой на ваши окружения) — обращайтесь в РыбинскЛАБ. Мы поможем спроектировать и разработать решение с учетом требований РФ и ваших эксплуатационных задач.