Почему CI/CD-конвейерам нужны предсказуемые ресурсы сервера
Jenkins и GitLab Runner автоматизируют сборку программного обеспечения, тесты, создание образов контейнеров, развертывания и проверки инфраструктуры. Их потребление ресурсов часто носит всплесковый характер: отправка изменений разработчиком может одновременно запустить компиляцию, загрузку зависимостей, браузерные тесты, сборки Docker, сканирование безопасности и выгрузку артефактов.
Медленный CI-сервер отнимает время у инженеров. Если сборка, которая должна завершаться за 8 минут, занимает 25 минут из-за нехватки CPU у runner'ов или насыщения дискового I/O, разработчики дольше ждут обратной связи, а очереди релизов растут. Выделенные серверы полезны для CI/CD, поскольку предоставляют эксклюзивные ядра CPU, память, NVMe-хранилище и сетевую пропускную способность без конкуренции с «шумными соседями».
Jenkins обычно используется как центральный контроллер автоматизации с динамическими агентами, тогда как GitLab Runner выполняет задачи, определенные в .gitlab-ci.yml. Оба могут работать непосредственно в Linux, в Docker-контейнерах или через Kubernetes. Для большинства небольших и средних команд Linux-хост с runner'ами на базе Docker проще в обслуживании, чем полноценный кластер Kubernetes.
VPS или выделенный сервер для Jenkins и GitLab Runner
Используйте VPS для легких CI-нагрузок
VPS достаточно, когда CI-платформа запускает ограниченное число легких задач, а время сборки не слишком критично. VPS с 4 vCPU, 8 ГБ RAM и NVMe-хранилищем может поддерживать контроллер Jenkins и 2-4 умеренных исполнителя сборок либо GitLab Runner, обрабатывающий несколько задач Node.js, Python, Go, линтинга и модульного тестирования.
- Небольшие команды с менее чем 10 активными разработчиками.
- 2-10 одновременных задач с коротким временем сборки.
- Статические сайты, API, публикация пакетов и базовые тестовые конвейеры.
- Внешние реестры контейнеров и хранилища артефактов снижают потребность в локальном диске.
- Автоматизация вне production, развертывания в staging или запланированные задачи обслуживания.
Выбирайте VPS только в том случае, если его производительность CPU, лимиты I/O и выделенная пропускная способность документированы. Системы сборки могут быстро выявить перепроданные CPU или слабое общее хранилище, особенно во время сборки образов Docker.
Переходите на выделенное bare metal для постоянных сборок
Выделенный сервер — лучший выбор для постоянной компиляции, параллельного выполнения тестов, крупных сборок Docker, кроссплатформенных сборок Android или iOS, браузерного тестирования, баз данных для интеграционных тестов и собственных реестров контейнеров. Эксклюзивное оборудование не позволяет всплескам дисковой или CPU-нагрузки одного арендатора задерживать релизные конвейеры.
- Более 15-20 одновременных CPU-интенсивных задач.
- Частые сборки образов Docker с многоуровневыми кэшами.
- Компиляция Java, .NET, Rust, C++, Android или крупных монорепозиториев.
- Нагрузки браузерного тестирования Playwright, Cypress, Selenium или других инструментов.
- Приватные артефакты сборки, секреты, ключи подписи или регулируемый исходный код, требующие более строгой изоляции.
- Пулы автомасштабирования GitLab Runner, агенты Jenkins или несколько команд проектов, совместно использующих одну платформу.
Для CI/CD количество ядер CPU и быстрое локальное NVMe-хранилище обычно важнее очень высокой пропускной способности сети. Сетевая емкость становится важнее, когда конвейеры регулярно загружают большие базовые образы, выгружают многогигабайтные артефакты, зеркалируют репозитории или публикуют релизы ПО.
Подбор CI/CD-сервера по числу одновременных задач сборки
Для до 10 одновременных легких задач достаточно VPS с 4 vCPU / 8 ГБ / 160 ГБ NVMe; при более чем 30 одновременных задачах или постоянных сборках контейнеров используйте выделенный сервер минимум с 16 физическими или высокопроизводительными ядрами CPU, 64 ГБ RAM и 1 ТБ NVMe.
| Одновременные задачи сборки | vCPU / ядра CPU | RAM | Диск | Месячный трафик |
|---|---|---|---|---|
| До 10 легких задач | 4 vCPU | 8 ГБ | 160 ГБ NVMe | 5 ТБ |
| 10-30 смешанных сборок | 8 vCPU или 8 выделенных ядер | 32 ГБ | 500 ГБ NVMe | 10 ТБ |
| 30-80 CPU-интенсивных задач | 16 выделенных ядер CPU | 64 ГБ | 1 ТБ NVMe | 20 ТБ |
| 80-150 крупных сборок и наборов тестов | 24-32 выделенных ядра CPU | 128 ГБ | 2 x 1,92 ТБ NVMe RAID 1 | 30 ТБ |
Эти показатели предполагают задачи на базе Linux с Docker-исполнителями и локально хранимыми кэшами сборки. Конвейер, компилирующий крупный монорепозиторий Java или запускающий браузерные тесты, может потреблять 2-4 ядра CPU и 4-8 ГБ RAM на задачу. Настраивайте параллелизм на основе измеренных показателей CPU, памяти и времени ожидания диска, а не только количества репозиториев.
Рекомендуемая архитектура
Отделяйте плоскость управления от тяжелых агентов сборки
Для небольших установок Jenkins или GitLab Runner могут работать на одном хосте. Для production-конвейеров по возможности размещайте контроллер Jenkins или экземпляр GitLab отдельно от высокорисковых исполнителей сборок. Скрипты сборки выполняют код репозитория, поэтому недоверенная ветка может потреблять дисковое пространство, пытаться получить доступ к сети или использовать слабые разрешения runner'а.
Практичная схема включает небольшой контроллер, один или несколько выделенных серверов сборки, объектное хранилище или удаленный репозиторий артефактов и приватный реестр контейнеров. Jenkins может распределять работу на SSH-, Docker- или входящие агенты. GitLab Runner может использовать исполнители Docker, shell, Kubernetes или виртуальных машин. Docker обычно является наиболее простым компромиссом между изоляцией и скоростью.
Используйте локальный NVMe для кэшей, но не как единственную копию релизных артефактов
Храните слои Docker, кэши менеджеров пакетов, кэши компиляторов и временные тестовые данные на локальном NVMe. Храните релизные артефакты, резервные копии и долгосрочные логи во внешнем хранилище. Это сохраняет скорость CI-хоста и предотвращает удаление критически важных результатов сборки из-за отказа оборудования или случайной задачи очистки.
Тщательно планируйте дисковое пространство. Слои образов Docker, checkout'ы Git, результаты сборки и отчеты тестов могут заполнить диски быстрее, чем ожидается. Резервируйте не менее 25% свободного пространства для временных файлов, производительности файловой системы и безопасной очистки образов.
Пошаговые рекомендации по настройке
1. Подготовьте защищенный Linux-хост
Ubuntu Server 24.04 LTS или Debian 12 — практичные варианты, поскольку пакеты Docker, Jenkins и GitLab Runner хорошо поддерживаются. Создайте администратора без прав root, используйте SSH-ключи, отключите аутентификацию по паролю, включите firewall и применяйте обновления безопасности.
sudo apt update && sudo apt -y upgrade && sudo apt install -y ufw curl ca-certificates gnupgРазрешайте только необходимый доступ. Например, открывайте SSH только из доверенных административных сетей и публикуйте Jenkins через обратный прокси с TLS, а не оставляйте порт 8080 открытым в интернет.
2. Установите Docker и настройте хранилище
Docker изолирует большинство сборок и упрощает очистку. Размещайте данные Docker на самом быстром NVMe-томе. Если доступен отдельный смонтированный том, настройте data-root Docker до использования в production.
curl -fsSL https://get.docker.com | sudo sh && sudo systemctl enable --now dockerПроверяйте свободное пространство с помощью df -h, а использование слоев контейнеров — с помощью docker system df. Не запускайте регулярно docker system prune -a без правил хранения, поскольку команда может удалить кэши, необходимые активным или часто запускаемым конвейерам.
3. Установите GitLab Runner с Docker executor
GitLab Runner обычно должен использовать Docker executor для задач репозитория. Регистрируйте каждый runner на уровне проекта, группы или экземпляра в соответствии с тем, кому разрешено его использовать. Используйте защищенные runner'ы для учетных данных развертывания и задач production-релизов.
sudo apt install -y gitlab-runner && sudo gitlab-runner register --url https://gitlab.example.com --token YOUR_RUNNER_TOKEN --executor docker --docker-image alpine:3.20Установите разумный лимит одновременных задач в /etc/gitlab-runner/config.toml. Начните с одной задачи на каждые 2 ядра CPU для конвейеров с интенсивной компиляцией, затем увеличивайте его только после наблюдения за загрузкой CPU, использованием памяти и ожиданием I/O.
4. Устанавливайте Jenkins, только если он подходит рабочему процессу
Jenkins полезен, когда командам нужны обширные интеграции с плагинами, сложные multibranch-конвейеры, пользовательские согласования или гибридные среды. Для крупных развертываний запускайте контроллер отдельно от исполнителей и поддерживайте плагины в актуальном состоянии, поскольку плагины расширяют поверхность атаки.
docker run -d --name jenkins -p 127.0.0.1:8080:8080 -v jenkins_home:/var/jenkins_home --restart unless-stopped jenkins/jenkins:lts-jdk17Разместите Nginx или другой обратный прокси перед Jenkins, завершайте TLS на нем и создавайте резервную копию тома домашнего каталога Jenkins. Не предоставляйте прямой доступ к контроллеру без аутентификации, TLS и контроля доступа.
5. Добавляйте кэширование осознанно
Кэширование часто сокращает время конвейера сильнее, чем добавление ядер CPU. Кэшируйте каталоги зависимостей, такие как кэш npm, репозиторий Maven .m2, кэши Gradle, wheels pip и загрузки модулей Go. Используйте ключи кэша на основе lockfile-файлов, чтобы изменения зависимостей инвалидировали устаревшие кэши.
ccache --set-config=max_size=20G && ccache --set-config=compression=trueДля сборок Docker включайте BuildKit и при необходимости используйте экспорт кэша в реестр или локальное хранилище. Не допускайте попадания секретов в слои образов, логи сборки и архивы кэша.
6. Настройте политики хранения и очистки
Устанавливайте даты истечения срока хранения артефактов для каждого проекта. Храните релизные артефакты дольше отчетов тестов, а логи — достаточно долго для устранения неполадок и выполнения требований аудита. Очищайте заброшенные рабочие пространства и старые образы Docker по расписанию, убедившись, что от них не зависят активные задачи.
sudo docker image prune -af --filter until=168hВыполняйте очистку в периоды низкой активности. Отслеживайте свободное место на диске до того, как оно опустится ниже 20%; полностью заполненный Docker-хост может привести к сбоям сборок, повреждению временных операций и невозможности перезапуска сервисов.
7. Отслеживайте хост и очередь конвейеров
Отслеживайте нагрузку CPU, давление на память, задержку диска, свободное дисковое пространство, использование сети, длительность очереди runner'ов, процент неудачных задач и коэффициент попадания в кэш. Prometheus с node_exporter и Grafana — распространенное сочетание для самостоятельного хостинга. Как минимум используйте iostat, vmstat и docker stats в периоды пиковых сборок.
sudo apt install -y sysstat && iostat -xz 1Советы по оптимизации производительности
- Соотносите параллелизм с ядрами: Начинайте параллелизм CPU-нагруженных сборок примерно с одной задачи на 2 ядра. Выделенный сервер с 16 ядрами часто работает лучше с 8 тяжелыми параллельными сборками, чем с 20 конкурирующими сборками.
- Используйте NVMe-хранилище: Checkout'ы Git, распаковка зависимостей, слои Docker и тестовые базы данных создают случайный I/O. NVMe обеспечивает значительно меньшую задержку, чем HDD-хранилище.
- Выборочно используйте поверхностные клоны: Устанавливайте глубину Git для задач, которым не нужна полная история. Не используйте поверхностные клоны для рабочих процессов версионирования, которым требуются теги или история коммитов.
- Размещайте runner'ы рядом с Git и реестрами: Меньшая задержка улучшает время клонирования, загрузки образов и выгрузки артефактов. Измеряйте скорость передачи, прежде чем считать CPU узким местом.
- Разделяйте независимые этапы: Запускайте линтинг, модульные тесты, сборки пакетов и сканирования безопасности параллельно, только если емкость сервера это поддерживает.
- Используйте выделенные runner'ы для дорогостоящих задач: Назначайте браузерные тесты, интеграционные тесты с базами данных и подпись релизов runner'ам с тегами, чтобы легкие задачи не блокировались.
- Ограничивайте объем логов: Подробный отладочный вывод потребляет дисковое пространство и замедляет обработку логов. Включайте отладочное логирование только при расследовании сбоя.
Практики безопасности и надежности
CI-runner'ы выполняют код из репозиториев, включая merge request'ы и ветки функций. Считайте каждую сборку потенциально недоверенной. Избегайте привилегированных задач Docker, если они не являются строго необходимыми; привилегированные контейнеры могут существенно ослабить изоляцию хоста. Используйте защищенные ветки, защищенные теги runner'ов, маскированные переменные, краткоживущие учетные данные и отдельные runner'ы для публичных или недоверенных проектов.
Создавайте резервные копии конфигурации Jenkins, конфигурации GitLab Runner, манифестов развертывания, материалов подписи и критических метаданных артефактов. Проверяйте восстановление, а не только создание резервных копий. Используйте NVMe RAID 1 для серверов, где важна доступность кэша сборки, но помните, что RAID не является резервной копией.
Обновляйте операционную систему, ПО runner'ов, Docker Engine, ядро Jenkins и плагины по определенному расписанию. Фиксируйте версии или digest образов сборки вместо постоянного использования latest, который может неожиданно изменить поведение сборки.
Распространенные ошибки CI/CD-серверов
- Перегрузка runner'ов: Высокий параллелизм может увеличить общее время сборки из-за конкуренции за CPU, свопинга и очередей диска.
- Использование одного runner'а для всего: Смешивание задач развертывания, недоверенных merge request'ов и дорогостоящих браузерных тестов увеличивает проблемы безопасности и планирования.
- Игнорирование роста использования диска: Слои Docker, артефакты и рабочие пространства могут занять сотни гигабайт за несколько недель.
- Хранение секретов в файлах репозитория: Используйте переменные CI, менеджер секретов или краткоживущие токены идентификации вместо сохраненных в репозитории учетных данных.
- Запуск привилегированных контейнеров по умолчанию: Используйте минимальные разрешения, необходимые для каждой задачи.
- Отсутствие резервных копий состояния Jenkins: Определения конвейеров могут находиться в Git, но учетные данные, конфигурация плагинов, история задач и настройки контроллера часто там не хранятся.
- Выбор HDD-хранилища для тяжелых сборок: Медленный случайный I/O влияет на сборки Docker, установку зависимостей и параллельные тесты сильнее, чем ожидают многие команды.
Выбор сервера Valebyte для CI/CD
Тарифы Valebyte VPS подходят для небольшого контроллера Jenkins, GitLab Runner для легких проектов или автоматизации разработки. Для общей инженерной платформы с постоянными сборками выделенные серверы обеспечивают стабильность CPU, запас RAM, емкость NVMe и изоляцию, необходимые для предсказуемой длительности конвейеров.
Начните с измерения среднего числа одновременных задач, пиковой загрузки CPU, памяти на задачу, размера репозитория, срока хранения артефактов и месячного трафика. Выберите достаточную емкость для пиковой активности с запасом 25-30%, затем добавляйте выделенные узлы runner'ов по мере роста очередей сборки.