GitLab CI/CD: пайплайн для деплоя на 50 серверов
Деплоить на один сервер умеет любой скрипт. Деплоить на 50 серверов одновременно, с контролем ошибок, роллбэком и без потери сна — это уже инженерная задача. Разберём как построить такой пайплайн на GitLab CI/CD.
GitLab Runner: shared vs specific
Прежде чем писать .gitlab-ci.yml, нужно понять где будут выполняться джобы.
Shared runners — предоставляются GitLab SaaS, подходят для сборок и тестов, но для деплоя в вашу инфраструктуру они не имеют доступа к вашим серверам. Используйте для CI-фазы.
Specific (self-hosted) runners — устанавливаете сами в своей сети. Именно они нужны для деплоя. Регистрация:
# Установка на Ubuntu
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
apt install gitlab-runner
# Регистрация
gitlab-runner register
--url https://gitlab.example.com
--registration-token $TOKEN
--executor shell
--tag-list deploy,production
Для деплоя используйте executor shell или docker — зависит от того, нужна ли изоляция окружения сборки.
Структура .gitlab-ci.yml
Базовая структура пайплайна с тремя стейджами:
stages:
- build
- test
- deploy
variables:
APP_NAME: myapp
DEPLOY_USER: deploy
ARTIFACT_PATH: dist/
build:
stage: build
script:
- make build
artifacts:
paths:
- dist/
expire_in: 1 hour
test:
stage: test
script:
- make test
dependencies:
- build
Артефакты (artifacts) — это то, что передаётся между джобами. Без явного указания dependencies джоба получает артефакты всех предыдущих.
Деплой через SSH: rsync + Ansible
Два основных подхода для деплоя на множество серверов:
rsync — быстрый, простой, минимум зависимостей:
deploy:
stage: deploy
script:
- eval $(ssh-agent -s)
- echo "$DEPLOY_SSH_KEY" | ssh-add -
- rsync -avz --delete dist/ $DEPLOY_USER@$SERVER:/opt/$APP_NAME/
- ssh $DEPLOY_USER@$SERVER "systemctl restart $APP_NAME"
Ansible — когда нужна идемпотентность и сложная логика:
deploy:
stage: deploy
script:
- ansible-playbook -i inventory/production deploy.yml
--extra-vars "version=$CI_COMMIT_SHORT_SHA"
SSH-ключ деплоя храните в CI/CD Variables (Settings → CI/CD → Variables), тип File для приватного ключа.
Parallel matrix: деплой на 50 серверов
Ключевая фича для масштабирования — parallel:matrix. Вместо последовательного деплоя запускаем джобы параллельно по группам серверов:
deploy:
stage: deploy
parallel:
matrix:
- SERVER_GROUP:
- web-01..10
- web-11..20
- web-21..30
- app-01..10
- app-11..20
script:
- ansible-playbook -i inventory/$SERVER_GROUP deploy.yml
GitLab создаст 5 параллельных джоб, каждая деплоит свою группу серверов. Время деплоя сокращается пропорционально числу параллельных потоков.
Максимум параллельных джоб на instance задаётся конкурентностью раннера (concurrent в /etc/gitlab-runner/config.toml).
Environments: staging → production
GitLab Environments позволяют отслеживать что и куда задеплоено:
deploy_staging:
stage: deploy
environment:
name: staging
url: https://staging.example.com
script:
- ansible-playbook -i inventory/staging deploy.yml
only:
- develop
deploy_production:
stage: deploy
environment:
name: production
url: https://example.com
script:
- ansible-playbook -i inventory/production deploy.yml
when: manual
only:
- main
when: manual для продакшена — обязательно. Автодеплой в прод без подтверждения человека допустим только если у вас идеальное тестовое покрытие (и то я бы поспорил).
Rollback через git revert + auto-deploy
Быстрый роллбэк через GitLab UI: в разделе Deployments → Environments нажмите Re-deploy на предыдущий деплой. GitLab запустит пайплайн с тем же коммитом.
Для автоматического роллбэка при падении healthcheck:
deploy_production:
stage: deploy
script:
- ansible-playbook -i inventory/production deploy.yml
- sleep 30
- curl -f https://example.com/health || (
ansible-playbook -i inventory/production rollback.yml &&
exit 1
)
В rollback.yml — переключение симлинка на предыдущую версию или откат через пакетный менеджер.
Secrets через CI/CD Variables
Никогда не храните секреты в репозитории. GitLab CI/CD Variables — правильное место:
- Protected: доступны только в защищённых ветках/тегах
- Masked: скрываются в логах джоб
- File: сохраняются как временный файл, путь передаётся в переменной
deploy:
script:
- ansible-playbook deploy.yml
--vault-password-file $ANSIBLE_VAULT_PASSWORD_FILE
Для особо критичных секретов — интеграция с HashiCorp Vault через secrets: синтаксис GitLab.
Кэширование зависимостей
Кэш ускоряет сборку, но требует правильной настройки ключа:
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
policy: pull-push
Ключ на основе package-lock.json означает: кэш обновляется только когда меняются зависимости. Используйте policy: pull в тестовых джобах чтобы не перезаписывать кэш.
Мониторинг пайплайнов
Несколько практик для поддержания здоровья пайплайнов:
- Badges в README репозитория — моментальный статус
- Slack/Telegram уведомления через webhook в настройках проекта
- Pipeline schedules — регулярные smoke-тесты на продакшене
- Failed jobs — настройте алерты через GitLab API или интеграцию с PagerDuty
Метрики пайплайнов доступны через GitLab API: время выполнения, процент успешных запусков, самые частые точки отказа.
Итог
50 серверов — не предел для GitLab CI/CD. Правильная архитектура с parallel matrix, self-hosted runners и Ansible позволяет масштабироваться и до 500. Главное — вложите время в правильную структуру с самого начала: environments, secrets management, rollback стратегию. Переделывать пайплайн под нагрузкой значительно болезненнее.
Хорошая статья, но у нас в итоге ушли с GitLab на GitHub Actions — там маркетплейс экшенов куда богаче, и secrets management через OIDC с облачными провайдерами работает прямо из коробки. Для GitLab это всё тоже можно, но больше ручной работы.