GitLab CI/CD

Каноническая схема delivery pipeline проекта. Pipeline оптимизирован под быстрые итерации на main, но сохраняет fail-closed зависимости артефактов и production deploy.

Платформа

  • SCM и CI/CD: GitLab.
  • Web-документация: GitLab Pages.
  • Release notes: GitLab Release + git-cliff.
  • Build runner: ci-build.
  • Deploy runner: ci-deploy.
  • E2E runner: ci-e2e.
  • DB BuildKit runner: ci-build-db, выключен по умолчанию через CI_DB_BUILDER_ENABLED=0.

Критический путь default pipeline

flowchart LR
    HB["disk-hygiene-build"]
    HD["disk-hygiene-deploy<br/>needs: []"]
    HE["disk-hygiene-e2e<br/>needs: []"]

    subgraph verify["verify"]
        DOCS["docs gates"]
        COMPOSE["compose-validate"]
        BACKEND["backend-checks<br/>ordinary go test"]
        ARCH["backend-archlint"]
        PROVIDERS["backend-provider-contract"]
        FRONT["frontend / landing gates"]
    end

    subgraph build["build"]
        PAGES["pages / docs-build"]
        WORKER["build-workers"]
        AUTH["build-auth"]
        UI["build-frontends"]
    end

    subgraph deploy["deploy"]
        DB["deploy-db-vps<br/>migrations unchanged"]
        APP["deploy-production"]
        EDGE["edge-deploy"]
    end

    RACE["backend-race<br/>hygiene, non-blocking"]
    QA["qa:e2e<br/>manual"]

    HB --> DOCS
    HB --> BACKEND
    DOCS --> PAGES
    COMPOSE --> WORKER
    BACKEND --> WORKER
    ARCH --> WORKER
    PROVIDERS --> WORKER
    WORKER --> AUTH --> UI
    FRONT --> UI
    HD --> DB
    WORKER --> DB
    HD --> APP
    PAGES --> APP
    UI --> APP
    DB --> APP
    HD --> EDGE
    UI --> EDGE
    HE --> QA
    APP -. "не блокирует deploy" .-> RACE

needs заменяет общий stage barrier только там, где зависимости доказаны. Падение существующего relevant gate по-прежнему блокирует его artifact consumer. optional: true означает только, что path-based job может отсутствовать; если такой job создан и упал, consumer не стартует.

Стадии

СтадияНазначение
prepareHygiene только build-runner перед его verify/build jobs.
verifyФорматирование, lint, compose, быстрые backend и frontend gates.
testРучные integration/E2E jobs и независимый hygiene E2E-runner.
buildDocs и production images; docs могут идти параллельно с worker path.
deployНезависимый deploy hygiene, DB-VPS deploy, App-VPS и edge deploy.
releaseRelease notes и GitLab Release для semver tags.
hygienePost-deploy cleanup и полный non-blocking backend race.

Тяжёлые Docker builds не запускаются параллельно: worker, auth и frontend сохраняют общий resource_group: ci-build-docker. Параллельность используется для docs, проверок и runner-specific hygiene, которые не конкурируют за этот Docker daemon.

Backend gates

Blocking backend-checks

Обязательный backend gate выполняет:

  1. gofmt check;
  2. go vet ./...;
  3. errorlint, layerlint, openapilint;
  4. go test -p 3 ./....

vet и ordinary tests используют один job-local GOCACHE. Между ними нельзя добавлять go clean -cache -testcache: это уничтожит уже оплаченный compile cache. Значение -p 3 использует половину 6-core runner и оставляет запас для параллельного verify job; на production runner при таком профиле доступно около 4 GiB RAM. GOCACHE не переносится между jobs, потому что race artifacts ранее занимали несколько гигабайт и заполняли runner disk.

Non-blocking backend-race

Полный прогон выполняет:

go test -race -p 2 ./... -coverprofile=coverage.out
go tool cover -func=coverage.out | tail -n 1

На main, в MR и scheduled pipeline job доступен вручную с allow_failure: true и interruptible: true. Поэтому обычный push не занимает один из двух слотов build-runner ещё на 7–9 минут. Перед ручным запуском ci-main-freshness.sh завершает устаревший pipeline без компиляции.

Не включайте automatic GitLab schedule на main только ради race: production build и deploy rules тоже совпадут с default branch, поэтому такой schedule может повторно выкатить production. Пока schedule не изолирован отдельным pipeline config, запускайте backend-race вручную из нужного pipeline.

Параллельные docs и build

pages и docs-build находятся в стадии build и ждут только:

  • disk-hygiene-build;
  • markdownlint;
  • docs-governance;
  • docs-mermaid;
  • plans-lint.

Worker producer независимо ждёт compose, backend-checks, architecture и provider-contract gates. Поэтому Quartz build больше не создаёт минутный барьер перед worker image build. При этом deploy-production явно ждёт pages, и сломанная документация не попадает в production deploy.

Runner-specific disk hygiene

Один hidden template .disk-hygiene содержит прежние prune-команды и пороги. Его используют три именованных job:

JobRunnerПоведение
disk-hygiene-buildci-buildprepare; gate для build-runner jobs.
disk-hygiene-deployci-deploydeploy, needs: []; gate только deploy consumers.
disk-hygiene-e2eci-e2etest, needs: []; gate только qa:e2e.

Очередь или длинная job на ci-deploy больше не держит backend checks, docs и worker build в created. Prune policy не стала агрессивнее: изменены только DAG edges.

Auth image reuse

build-auth клонирует AUTH_REF и вычисляет точный commit внешнего репозитория. Source cache tag имеет вид:

auth-source-v1-<AUTH_COMMIT>-<UTC_YEAR>-W<UTC_WEEK>

Если tag существует в 192.168.1.85:5001/tracium/auth, helper scripts/ci-registry-retag.sh читает schema-2/OCI manifest через Registry V2 API и записывает тот же manifest в $CI_COMMIT_SHA и latest. Слои не скачиваются, DinD не делает docker pull, Go toolchain не собирается.

При 404, сетевой ошибке, неизвестном Content-Type или failed target PUT job переходит к полному Docker build. Fallback публикует immutable Tracium SHA, source cache tag и только затем latest. Недельный epoch принудительно обновляет mutable base images хотя бы раз в неделю.

Next.js image reuse

landing-ui и admin-ui нельзя переиспользовать только по git diff: NEXT_PUBLIC_* встраиваются в browser bundle и могут быть переопределены GitLab variables. scripts/ci-frontend-source-tag.sh поэтому вычисляет content-addressed tag из Git object ID всех Docker inputs, хэшей фактических build args и недельного UTC epoch.

При совпадении build-frontends копирует manifest source-tag в текущий SHA и latest через Registry V2, не скачивая слои и не выполняя next build. Cache miss или любая ошибка registry остаётся fail-safe fallback: полный Docker build публикует SHA, source-tag и затем latest. Значения build args в лог не выводятся.

Миграции и большая production DB

Эта оптимизация не изменяет migration image, команды, timeout или порядок. deploy-db-vps по-прежнему:

  1. ждёт готовый worker image и hygiene ci-deploy;
  2. применяет миграции на DB-VPS;
  3. завершает worker rollout;
  4. только после успеха разрешает deploy-production.

Длинная миграция остаётся fail-closed и не прерывается ради ускорения. Тяжёлые production health queries также не распараллеливаются, чтобы не увеличивать I/O contention большой базы.

Триггеры

Merge Request

Path-based verify jobs запускаются для изменённых компонентов. Full race, integration и E2E доступны вручную и не блокируют обычную итерацию.

Default branch

Relevant verify gates, production images, Pages и deploy запускаются автоматически. Stale checks не дают старому pipeline перезаписать более новый release.

Tag

Semver tags vX.Y.Z валидируют VERSION, создают release notes и GitLab Release. Production image builders сохраняют immutable tag/commit artifacts.

Требования к runners

  • ci-build: Docker/DinD и доступ к LAN registry 192.168.1.85:5001.
  • ci-deploy: Docker socket, host mounts production runtime и SSH-доступ к DB-VPS через RUNNER_DEPLOY_SSH_KEY.
  • ci-e2e: изолированный DinD для compose/Playwright.
  • Git history без shallow limit (GIT_DEPTH=0) для freshness/release checks.
  • git и curl в auth/deploy jobs.

Rollback

Один revert CI-коммитов возвращает прежние race rules и stage barriers. Immutable SHA images в LAN registry остаются доступны; rollback CI не требует rollback production runtime или базы. Миграции нельзя откатывать как часть этого CI rollback.

Связано