MAATRIX / Блог / GitLab Runner на VPS: свой CI/CD-агент

GitLab Runner на VPS: свой CI/CD-агент

Блог MAATRIX · 2026-07-07

Свой GitLab Runner на VPS снимает лимиты бесплатных минут и даёт полный контроль над окружением сборки. Поставим агент с Docker-executor, зарегистрируем его и напишем пайплайн с деплоем.

Зачем свой раннер

['GitLab.com даёт ограниченный пул CI-минут, а на self-managed инсталляциях раннеров нет вовсе. Собственный агент на VPS решает обе проблемы: сборки идут без лимитов, а окружение вы контролируете полностью.', 'Executor определяет, где выполняется job. Самый практичный — docker: каждая job стартует в чистом контейнере, ничего не остаётся между запусками. Для этого нужен установленный Docker.', 'CI-нагрузка пульсирующая и требовательная к диску. NVMe у MAATRIX ускоряет docker pull и распаковку слоёв, а предсказуемое ядро AMD EPYC не даёт сборкам «плавать» по времени. На дешёвых виртуалках с оверселлингом одна и та же сборка то укладывается в минуту, то тянется пять — это убивает предсказуемость пайплайна.', 'Ещё один плюс своего раннера — приватность. Секреты, ключи подписи и внутренние пакеты не покидают ваш сервер и не проходят через чужую инфраструктуру. Для команд, работающих с закрытым кодом, это часто решающий аргумент.']

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK и США. Оплата картой РФ и по СБП.

Арендовать VPS для GitLab Runner

Установка Docker и раннера

['Ставим Docker из официального скрипта, затем репозиторий GitLab Runner и сам пакет.', '
curl -fsSL https://get.docker.com | sh\ncurl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash\nsudo apt install -y gitlab-runner
', 'После установки раннер уже работает как systemd-сервис под пользователем gitlab-runner. Проверить статус:', '
sudo systemctl status gitlab-runner\nsudo gitlab-runner --version
']

Регистрация раннера

['Токен регистрации возьмите в GitLab: Settings → CI/CD → Runners → New project runner. Регистрируем в неинтерактивном режиме сразу с docker-executor.', '
sudo gitlab-runner register \\\n  --non-interactive \\\n  --url "https://gitlab.com/" \\\n  --token "<RUNNER_TOKEN>" \\\n  --executor "docker" \\\n  --docker-image "alpine:latest"
', 'Проверьте, что раннер появился в списке и подхватывает jobs:', '
sudo gitlab-runner list\nsudo gitlab-runner verify
']

.gitlab-ci.yml с кэшем и деплоем

['Пайплайн из двух стадий: сборка с кэшированием зависимостей и деплой по SSH. Приватный ключ храните в Settings → CI/CD → Variables как защищённую переменную SSH_PRIVATE_KEY.', '
stages: [ build, deploy ]\n\nbuild:\n  stage: build\n  image: node:20\n  cache:\n    key: ${CI_COMMIT_REF_SLUG}\n    paths: [ node_modules/ ]\n  script:\n    - npm ci\n    - npm run build\n  artifacts:\n    paths: [ dist/ ]\n\ndeploy:\n  stage: deploy\n  image: alpine:latest\n  only: [ main ]\n  script:\n    - apk add --no-cache openssh-client rsync\n    - eval $(ssh-agent -s)\n    - echo "$SSH_PRIVATE_KEY" | ssh-add -\n    - rsync -az --delete dist/ deploy@$SERVER:/var/www/app/
', 'cache ускоряет повторные сборки (node_modules переиспользуется), а artifacts передаёт результат сборки в стадию деплоя. Разница принципиальная: cache — необязательная оптимизация, которая может отсутствовать, а artifacts гарантированно доезжают между стадиями. Никогда не полагайтесь на cache как на способ передать критичные файлы дальше по пайплайну.', 'Переменную SSH_PRIVATE_KEY обязательно пометьте как Protected и Masked. Protected закрывает её от веток и тегов без защиты, Masked прячет значение в логах. Иначе приватный ключ рискует утечь в вывод job при отладке.']

Обслуживание и очистка

['Docker-executor со временем забивает диск старыми образами и volume. Настройте регулярную очистку по cron:', '
docker system prune -af --volumes\n# в crontab -e:\n0 4 * * * /usr/bin/docker system prune -af --volumes
', 'Ограничить одновременные сборки можно в /etc/gitlab-runner/config.toml параметром concurrent — на маленьком VPS ставьте 1–2, чтобы сборки не конкурировали за CPU.']

Частые ошибки

['
  • Runner не берёт jobs — не совпадают теги. Либо снимите теги с job, либо включите «Run untagged jobs» в настройках раннера.
  • Cannot connect to Docker daemon — пользователь gitlab-runner не в группе docker: sudo usermod -aG docker gitlab-runner.
  • Диск переполнен — забыли prune, слои образов копятся бесконечно.
  • Permission denied (publickey) — забыли добавить публичный ключ деплоя в authorized_keys на целевом сервере.
']

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK и США. Оплата картой РФ и по СБП.

Арендовать VPS для GitLab Runner

Частые вопросы

Чем docker-executor лучше shell?

Docker-executor даёт чистое изолированное окружение на каждую job — никаких следов между сборками. Shell-executor выполняет всё прямо в системе и легко «загрязняется».

Один раннер на несколько проектов — можно?

Да, зарегистрируйте раннер как групповой или инстансный, и он будет обслуживать несколько проектов сразу.

Сколько RAM нужно раннеру?

Сам агент лёгкий, но сборкам нужна память. Для комфортных Node/Python-сборок берите VPS от 2 ГБ RAM, для тяжёлых образов — больше.