Поток пайплайна
Эта страница описывает полный жизненный цикл CI/CD-пайплайна — от git push до работающего сервиса на ноде своего окружения.
Общая схема
flowchart TD
A[Разработчик пушит в ветку] --> B{Какая ветка?}
B -->|dev| C[Цель: dev]
B -->|stage| D[Цель: stage]
B -->|main| E[Цель: prod]
C --> F[Этап сборки]
D --> F
E --> F
F --> G[docker build с --platform linux/amd64]
G --> H[Тегирование образа именем окружения]
H --> I[Отправка в registry.amztop.io]
I --> J[Этап деплоя]
J --> K[Контейнер hashicorp/nomad на раннере]
K --> L["nomad job run по HTTP API"]
L --> M[Nomad тянет образ и катит канарейку]
M --> N[Сервис работает с новым образом]
style A fill:#4a6fa5,stroke:#2d4a7a,color:#fff
style N fill:#4a9a5c,stroke:#2d7a3a,color:#fff
style F fill:#c9a24e,stroke:#a68232,color:#fff
style J fill:#c9a24e,stroke:#a68232,color:#fffЭтап 1: Сборка
Этап сборки запускается при каждом пуше в dev, stage или main. Каждый сервис в репозитории получает собственную параллельную задачу сборки. Все задачи идут на раннере new-server-builder — по тегу new-server.
Что происходит
- Раннер запускает контейнер
docker:24с Docker-in-Docker (docker:24-dind) в качестве вспомогательного сервиса. - Авторизация в registry штатной учёткой джобы:bash
docker login registry.amztop.io -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD - Переход в каталог сервиса (
$SERVICE_DIR). - Определение тега по ветке:
main→prod,stage→stage,dev→dev. - Сборка образа с фиксацией платформы
linux/amd64:bashdocker build ${BUILD_ARGS} \ --platform linux/amd64 \ -t registry.amztop.io/integrations/hub/backend:dev . - Отправка образа в registry. Если у проекта не выставлен
DUAL_PUSH: "false", следом уходит копия в старый registry.
Кеш базовых образов
На раннере поднят pull-through кеш Docker Hub, поэтому повторные сборки не упираются в лимиты Hub и тянут базовые слои локально.
Параллельные сборки
Когда репозиторий содержит несколько сервисов (например, Hub включает backend и frontend), задачи сборки выполняются параллельно:
gantt
title Выполнение этапа сборки
dateFormat X
axisFormat %s
section Сборка
build:backend :0, 90
build:frontend :0, 70
section Деплой
deploy (ожидает все сборки) :90, 30Этап деплоя не начинается, пока все задачи сборки не завершатся успешно. Если любая сборка падает, пайплайн останавливается.
Ошибки сборки
Неудачная сборка полностью блокирует деплой. Типичные причины сбоев:
- Синтаксические ошибки в
Dockerfile - Отсутствующие зависимости сборки
BUILD_ARGSссылаются на неопределённые ARG в Dockerfile- Сетевые проблемы при загрузке базовых образов
Проверьте логи CI-задачи, чтобы увидеть конкретную ошибку docker build.
Этап 2: Деплой
После успешного завершения всех сборок запускается задача деплоя для соответствующего окружения.
Что происходит
- Запускается контейнер
hashicorp/nomad:1.11.3— в нём уже есть нужный CLI. - Выставляются адрес и токен кластера из переменных группы:bash
export NOMAD_ADDR=$NEW_NOMAD_ADDR export NOMAD_TOKEN=$NEW_NOMAD_TOKEN - Джоба отправляется в нужный namespace прямо из репозитория — файлы никуда не копируются:bash
nomad job run -namespace=dev \ -var image_tag=dev \ -var deploy_ts=$CI_PIPELINE_ID \ -var-file=nomad/vars-dev.hcl nomad/hub.nomad.hcl - Nomad планирует аллокацию на ноду своего окружения — за это отвечает
constraintпоmeta.envвнутри джобы. - Нода тянет образ из registry и поднимает канареечную копию рядом со старой.
- После успешных health-чеков трафик переключается, старая копия гасится.
Диаграмма последовательности деплоя
sequenceDiagram
participant GL as GitLab Runner
participant NM as Nomad API
participant ND as Нода окружения
participant REG as registry.amztop.io
GL->>NM: nomad job run (namespace, image_tag, deploy_ts)
NM->>NM: Планирование аллокации по meta.env
NM->>ND: Разместить задачу
ND->>REG: Pull образа :dev
REG-->>ND: Слои образа
ND->>ND: Старт канареечной копии
ND-->>NM: Health-чеки зелёные
NM->>ND: Промоут канарейки, стоп старой
NM-->>GL: Exit 0 (success)Соответствие веток и окружений
Весь пайплайн управляется тем, в какую ветку выполнен пуш:
| Ветка | Тег сборки | Цель деплоя | Namespace | Nomad var-файл |
|---|---|---|---|---|
dev | :dev | dev-окружение | dev | nomad/vars-dev.hcl |
stage | :stage | stage-окружение | stage | nomad/vars-stage.hcl |
main | :prod | prod-окружение | prod | nomad/vars-prod.hcl |
Feature-ветки
Пуши в ветки, отличные от dev, stage или main, не запускают никаких задач пайплайна. Чтобы протестировать feature-ветку в CI, сначала влейте её в dev.
Прод — по кнопке
Задача deploy:prod описывается с when: manual. Пуш в main собирает образ :prod, но выкатку запускает человек нажатием в пайплайне.
Полный пример пайплайна
Как выглядит полный пайплайн для сервиса Hub при пуше в ветку dev:
# Triggered by: git push origin dev
# Job 1: build:backend
# - extends: .docker_build, tags: [new-server]
# - Builds back/Dockerfile
# - Pushes: registry.amztop.io/integrations/hub/backend:dev
# Job 2: build:frontend (runs in parallel with Job 1)
# - extends: .docker_build, tags: [new-server]
# - Builds front/Dockerfile with --build-arg VITE_API_URL=...
# - Pushes: registry.amztop.io/integrations/hub/frontend:dev
# Job 3: deploy:dev (runs after Jobs 1 & 2 succeed)
# - extends: .nomad_new, tags: [new-server]
# - Runs: nomad job run -namespace=dev -var image_tag=dev
# -var deploy_ts=$CI_PIPELINE_ID
# -var-file=nomad/vars-dev.hcl nomad/hub.nomad.hclВременная шкала
flowchart LR
A["git push origin dev"] --> B["build:backend<br/>(~90 сек)"]
A --> C["build:frontend<br/>(~70 сек)"]
B --> D["deploy:dev<br/>(~30 сек)"]
C --> D
D --> E["Сервис доступен на dev"]
style A fill:#4a6fa5,stroke:#2d4a7a,color:#fff
style E fill:#4a9a5c,stroke:#2d7a3a,color:#fffТипичное общее время пайплайна: 2--3 минуты от пуша до работающего сервиса.
Решение проблем
Ошибки на этапе сборки
Образ не собирается
Проверьте вывод docker build в логах CI-задачи. Типичные причины:
- Базовый образ не найден (сетевая проблема или неверный тег)
COPYссылается на файлы, исключённые.dockerignore- Аргумент сборки требуется, но не передан через
BUILD_ARGS
Отправка в registry не удалась
Проверьте, что в проекте заданы REGISTRY_HOST: registry.amztop.io и REGISTRY_IMAGE: $REGISTRY_HOST/$CI_PROJECT_PATH. Если push падает с denied, а pull работает — дело в скоупе токена: у deploy-токена должна стоять галка write_registry, а не только read_registry.
Задача ушла не на тот раннер
Если в логе видно, что джобу подобрал раннер старого сервера — забыт тег new-server. Он нужен и сборке, и деплою.
Ошибки на этапе деплоя
Пустой NOMAD_ADDR или 403 от API
Скорее всего у переменных NEW_NOMAD_ADDR / NEW_NOMAD_TOKEN стоит галка Protect, а ветка не защищена. Снимите галку — на группе integrations они заведены без неё.
Отправка Nomad-задачи не удалась
Типичные причины:
- Некорректный HCL-синтаксис в
nomad/<job>.nomad.hcl - В var-файле отсутствует обязательная переменная
- Джоба отправлена в namespace, которого нет
Проверьте локально под VPN, до пуша:
export NOMAD_ADDR=http://192.168.100.1:4646
export NOMAD_TOKEN=<ваш токен>
nomad job validate -var image_tag=dev -var deploy_ts=1 \
-var-file=nomad/vars-dev.hcl nomad/hub.nomad.hclПайплайн зелёный, но версия старая
Повторный запуск задачи в том же пайплайне отдаёт прежний deploy_ts, и Nomad не считает это новой выкаткой. Запустите новый пайплайн.
Ошибки загрузки образа во время выполнения
Если Nomad принял задачу, но аллокация упала, наиболее вероятная причина — ошибка загрузки образа. Проверьте:
- Тег образа существует в registry
- Нода может достучаться до
registry.amztop.io - Учётные данные Docker на ноде не истекли
Docker на ноде хранит одну учётку на registry — сейчас это deploy-токен группы integrations. Проект из другой группы потребует обновления логина на нодах.
# На ноде окружения:
docker pull registry.amztop.io/integrations/hub/backend:dev