GitLab Runner на VPS: свой CI/CD-агент
Свой 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, для тяжёлых образов — больше.