CI / CD
Работал с доставкой проектов от простого ручного деплоя через ssh/rsync до более управляемой схемы с GitLab CI, Docker-образами и Deployer.
На практике использовал схему: CI выполняет проверки и сборку артефактов/образов, а production-deploy запускается отдельно и контролируемо.
Уровни опыта CI/CD
- Ручной деплой (
ssh,rsync, bash-скрипты) Deployerкак слойCD(release-based deploy, rollback, повторяемые задачи)GitLab CI+ Docker Registry + ручной запуск deploy в production
GitLab CI (pipeline, проверки, сборка образов)
Настраивал GitLab CI pipeline с разделением по стадиям (lint, test, build) и правилами запуска через workflow/rules.
Типичный pipeline для production-ветки включает:
lint:- проверка форматирования кода;
- запуск линтеров для backend- и frontend-части;
typecheckдля клиентского кода;- dependency audit для
composerиnpm;
test:- запуск автотестов приложения;
- проверка интеграционных сценариев с реальными сервисами;
- поднятие
PostgreSQLиRedisкак CI services; - ожидание готовности инфраструктуры перед стартом тестов;
build:- сборка production-образов приложения и
nginx; - тегирование образов immutable-тегами и служебными floating-тегами;
- push готовых образов в
Docker Registry; - публикация тегов и метаданных сборки для следующего шага deploy.
- сборка production-образов приложения и
GitLab Runner на VPS (установка и настройка)
Поднимал self-hosted gitlab-runner на VPS под проектный pipeline:
- установка
gitlab-runnerи регистрация runner в проект GitLab; - настройка runner под Docker-джобы (образы
CI_PHP_IMAGE,node, сервисыpostgres/redis); - привязка по тегу
recipes-deployдля целевого запуска pipeline; - настройка доступа к Docker на VPS (включая работу со сборкой и push образов в
GitLab Container Registry).
В результате pipeline для ветки production выполняется на своём раннере предсказуемо и без ручного вмешательства.
Кастомный CI runtime image (CI_PHP_IMAGE)
Использую отдельный CI-образ для PHP-задач (CI_PHP_IMAGE), чтобы:
- сократить время подготовки джоб;
- зафиксировать версию PHP и набор расширений;
- приблизить CI-окружение к production-стеку.
Обычно собираю такой образ на базе Ubuntu/Debian и заранее добавляю:
- нужную версию
PHP; - необходимые расширения (
pgsql,redis,intlи др.); composer;- CLI-инструменты для работы с БД (
postgresql-clientи т.п.).
При изменении Dockerfile CI-образ пересобирается и пушится вручную (пример):
docker build --no-cache -t <registry>/<group>/<project>/php-ci:<tag> -f docker/ci/php/Dockerfile.ci .
docker push <registry>/<group>/<project>/php-ci:<tag>В подобных схемах полезно использовать отдельный базовый CI runtime image для PHP-джоб.
Docker Registry и production-образы
В production-потоке использую prebuilt Docker-образы вместо сборки на сервере.
Что реализовано:
- сборка
app-образа (php-fpm) иnginx-образа в CI; - публикация в
GitLab Container Registry; - двойная стратегия тегов:
- immutable-теги с
commit sha; - плавающий
latest;
- immutable-теги с
- ручной выбор версии deploy через runtime/env-конфиг:
- образ приложения;
- образ веб-сервера.
Такой подход упрощает rollback и делает deploy предсказуемым: сервер только pull-ит готовые образы.
На практике production-образы полезно разделять по ролям:
php-fpmruntime приложения;nginximage со статикой и production-конфигом.
Deployer (release-based CD на VPS)
Использую Deployer как управляемый слой CD для ручного production-деплоя.
Типовые задачи, которые настраивал через Deployer:
- deploy через shell-обертку над
Deployer; - SSH precheck перед запуском deploy;
- release-структура (
releases / current / shared); - автоматическая загрузка локального production
.envвshared/.envна VPS; - валидация обязательных production-ключей (секреты/ключи приложения);
- загрузка runtime-файлов на VPS без
git cloneна сервере; docker loginв registry на VPS;docker compose pull+docker compose up -d --remove-orphans;- post-deploy шаги:
- миграции БД;
- прогрев кэшей приложения;
- подготовка симлинков/статических директорий;
- перезапуск очередей/воркеров;
- рестарт сервисов runtime (например, websocket/nginx);
- healthcheck URL.
Дополнительно:
- настройка и обновление cron-задачи для
Let's Encryptrenew; - настройка ежедневного backup
PostgreSQLв production:- запуск
pg_dump -Fcчерезdocker compose exec pgsql; - сжатие backup-артефактов (
gzip); - хранение в
shared/backups, чтобы backup не терялся при переключении release; - cleanup старых backup-файлов по retention policy;
- установка/обновление cron-задачи через deploy-процесс;
- запуск
- подготовка shared-storage директорий и прав;
- синхронизация
WWWUSER/WWWGROUPпод UID/GID deploy-пользователя.
Защитные проверки:
- precheck текущей ветки перед production deploy;
SSH-проверку доступности сервера с retry;- валидацию deploy/env-конфига до запуска основных шагов.
Типовой flow деплоя
- Переключиться на ветку
production, перенести изменения (обычно черезrebase), выполнитьpush. - Дождаться успешного pipeline в
GitLab(lint,test, сборка production-образов). - Запустить ручной deploy в production (через
Deployer/shell-обертку).
./deploy.sh deploy productionБаланс между автоматизацией и контролем: проверки и сборка выполняются в CI, а production-переключение запускается осознанно вручную.
Подготовка production-конфигов
Подготовка production-конфигурации под Docker-деплой:
Dockerfileдля production-образов (app,nginx);docker-compose.prod.yml;nginxproduction-конфиг;.env.production(runtime-переменные приложения);.env.deploy(параметры deploy-процесса и доступа к VPS/registry).