Общие шаблоны GitLab
Сборка образов вынесена в общий шаблон, который поддерживается в репозитории meduza/infra. Деплой каждый сервис описывает у себя — он короткий и явный. Эта страница разбирает и то, и другое.
Подключение шаблона
.gitlab-ci.yml сервиса начинается с подключения шаблона сборки:
include:
- project: 'meduza/infra'
ref: main
file: '.gitlab/ci/docker-build.yml'Это делает скрытую задачу .docker_build доступной для наследования.
Шаблон nomad-deploy.yml не подключаем
В том же каталоге лежит .gitlab/ci/nomad-deploy.yml с задачей .nomad_deploy — она копирует файлы по SSH на старый KVM-хост и запускает Nomad там. Для нового кластера он не годится: деплой идёт прямым обращением к Nomad API.
Шаблон .docker_build
Расположение: .gitlab/ci/docker-build.yml
Собирает Docker-образ и отправляет его в registry.
Исходный код шаблона
.docker_build:
stage: build
image: docker:24
services:
- docker:24-dind
before_script:
- docker login $REGISTRY_HOST -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
# DUAL_PUSH: пока часть сервисов живёт на старом кластере, образ
# дублируется в старый registry. Переехавшие ставят DUAL_PUSH: "false".
script:
- cd ${SERVICE_DIR}
# Тег окружения определяется по ветке: main → prod, stage → stage,
# dev → dev. Любая другая ветка — выход без сборки.
- >-
docker build ${BUILD_ARGS}
--platform linux/amd64
-t $REGISTRY_IMAGE/${SERVICE_NAME}:${ENV_TAG} .
- docker push $REGISTRY_IMAGE/${SERVICE_NAME}:${ENV_TAG}
only:
- main
- stage
- devПеременные
| Переменная | Обязательна | Описание |
|---|---|---|
SERVICE_NAME | Да | Имя, используемое в пути образа (например, backend, frontend). |
SERVICE_DIR | Да | Подкаталог с Dockerfile относительно корня репозитория. |
BUILD_ARGS | Нет | Дополнительные аргументы для docker build (например, --build-arg VITE_API_URL=...). |
REGISTRY_HOST | Да | Задаётся в проекте: registry.amztop.io. |
REGISTRY_IMAGE | Да | Задаётся в проекте: $REGISTRY_HOST/$CI_PROJECT_PATH. |
DUAL_PUSH | Нет | По умолчанию "true" — копия образа уходит в старый registry. Для сервисов нового кластера ставьте "false". |
CI_REGISTRY_USER | Авто | gitlab-ci-token — подставляется GitLab. |
CI_REGISTRY_PASSWORD | Авто | Эфемерный токен джобы. Личные токены в переменные класть не нужно. |
Авторизация в registry
registry.amztop.io не имеет собственной базы учёток — токены ему подписывает GitLab. Поэтому в пайплайне работает штатная пара $CI_REGISTRY_USER / $CI_REGISTRY_PASSWORD, а для доступа извне пайплайна (ноды, ansible, локальная машина) берётся deploy-токен со скоупом read_registry или write_registry.
Как наследовать
build:backend:
extends: .docker_build
tags:
- new-server
variables:
SERVICE_NAME: backend
SERVICE_DIR: back
build:frontend:
extends: .docker_build
tags:
- new-server
variables:
SERVICE_NAME: frontend
SERVICE_DIR: front
BUILD_ARGS: "--build-arg VITE_API_URL=https://api.amzhub.ai"Каждый блок extends создаёт конкретную CI-задачу, наследующую image, services, before_script и script из шаблона. Вы переопределяете только variables и добавляете тег раннера.
Тег new-server обязателен
Без него задачу заберёт раннер старого сервера, который не ходит в новый кластер. Тег нужен и задачам сборки, и задачам деплоя.
Кавычки в BUILD_ARGS
При указании нескольких аргументов сборки оборачивайте всю строку в кавычки и разделяйте пробелами:
BUILD_ARGS: "--build-arg FOO=bar --build-arg BAZ=qux"Не используйте YAML-списки — BUILD_ARGS подставляется непосредственно в команду docker build как одна строка.
Поведение тегирования образов
Образ получает один тег — по имени ветки:
| Ветка | Тег образа |
|---|---|
main | :prod |
stage | :stage |
dev | :dev |
Пуш в любую другую ветку шаблон пропускает без сборки. Отдельного тега по commit SHA больше нет: за то, чтобы Nomad увидел новую сборку под неизменившимся тегом, отвечает переменная deploy_ts.
Задачи деплоя
Деплой описывается в самом сервисе: контейнер с Nomad CLI обращается к API кластера напрямую, без SSH и без копирования файлов на хост.
.nomad_new:
stage: deploy
tags:
- new-server
image:
name: hashicorp/nomad:1.11.3
entrypoint: [""]
before_script:
- export NOMAD_ADDR=$NEW_NOMAD_ADDR
- export NOMAD_TOKEN=$NEW_NOMAD_TOKENПеременные
| Переменная | Обязательна | Описание |
|---|---|---|
NEW_NOMAD_ADDR | Авто | Адрес Nomad API. Заведена на группу integrations. |
NEW_NOMAD_TOKEN | Авто | Токен деплоя. Заведена на группу integrations. |
CI_PIPELINE_ID | Авто | Передаётся в джобу как deploy_ts, чтобы Nomad увидел новую выкатку. |
Галка Protect у переменных
Protected-переменная видна только защищённым веткам, а dev обычно не защищена — деплой в dev тогда падает с пустым адресом Nomad. Переменные NEW_NOMAD_* держим без этой галки.
Как наследовать
deploy:dev:
extends: .nomad_new
script:
- 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
- sleep 5
- nomad job status -namespace=dev hub
only:
- dev
deploy:stage:
extends: .nomad_new
script:
- nomad job run -namespace=stage -var image_tag=stage
-var deploy_ts=$CI_PIPELINE_ID
-var-file=nomad/vars-stage.hcl nomad/hub.nomad.hcl
- sleep 5
- nomad job status -namespace=stage hub
only:
- stage
deploy:prod:
extends: .nomad_new
script:
- nomad job run -namespace=prod -var image_tag=prod
-var deploy_ts=$CI_PIPELINE_ID
-var-file=nomad/vars-prod.hcl nomad/hub.nomad.hcl
- sleep 5
- nomad job status -namespace=prod hub
only:
- main
when: manualПродакшн — только по кнопке
when: manual оставляет задачу deploy:prod ждать нажатия в пайплайне ветки main. Пуш в main сам по себе прод не выкатывает.
Соответствие веток и окружений
Ключевое слово only ограничивает каждую задачу деплоя одной веткой:
| Ветка | Окружение | Namespace | Задача деплоя |
|---|---|---|---|
dev | dev | dev | deploy:dev |
stage | stage | stage | deploy:stage |
main | prod | prod | deploy:prod (вручную) |
Retry не передеплоит
Повторный запуск задачи в том же пайплайне отдаёт прежний deploy_ts. Nomad не создаёт новый деплой и сразу возвращает прошлый результат. Нужен новый пайплайн — Run pipeline или пустой коммит.
Полный пример
Готовый .gitlab-ci.yml целиком, с переменными и обеими стадиями, собран на странице Новый сервис: от репозитория до прода. Рабочий образец в проде — репозиторий integrations/docs.