Управление параллелизмом в GitLab Runner: лимиты, настройки и лучшие практики
Быстрые ссылки
- Увеличение числа Runner
- Повышение лимита параллелизма
- Управление request_concurrency
- Глобальный уровень concurrency
- Применение изменений
- Организация конвейеров для параллельных задач
- Вопросы по кэшу
- Критерии приёмки и тесты
- Сводка

Краткое введение
GitLab CI использует пайплайны, которые состоят из последовательных стадий, а каждая стадия может содержать несколько задач (jobs), выполняющихся параллельно. Конкурентность выполнения задач зависит от конфигурации ваших GitLab Runner’ов и параметров в их конфигурационном файле config.toml.
Ключевые термины (одно предложение каждое):
- Runner — процесс, который получает задачи от GitLab и запускает их в подпроцессах.
- limit — максимальное число одновременных подпроцессов (jobs) для конкретной регистрации runner.
- request_concurrency — число одновременно принимаемых запросов на запуск задач (очередь запросов).
- concurrency — глобальный лимит для всей установки GitLab Runner.
Важно: кешы по умолчанию привязаны к runner; чтобы сделать кеш разделяемым между разными экземплярами, используйте внешнее объектное хранилище.
Увеличение числа Runner
Добавление дополнительных экземпляров Runner — самый простой путь увеличить число задач, которые система может выполнять параллельно. Каждый установленный экземпляр GitLab Runner может зарегистрировать несколько регистраций. Регистрации действуют независимо.
Чтобы зарегистрировать новый runner, выполните:
gitlab-runner registerОбычно на Unix-системах команда запускается от root или через sudo:
sudo gitlab-runner registerПри регистрации вам понадобятся данные с интерфейса GitLab: токен и URL проекта/группы/инстанса. Для регистраций на уровне проекта или группы используйте Settings → CI/CD в проекте/группе. Для регистрации на уровне инстанса используйте Admin Area → Overview → Runners.

После регистрации каждая регистрация получает свою секцию в /etc/gitlab-runner/config.toml:
# Runner 1
[[runners]]
executor = "shell"
...
# Runner 2
[[runners]]
executor = "shell"
...
# Runner 3
[[runners]]
executor = "shell"
...Если все три регистрации привязаны к одному серверу GitLab, вы сможете одновременно запускать до трёх задач (по одной на каждый runner), при прочих равных.
Когда лучше добавлять новые Runner
- Когда задачи требуют разной среды исполнения (например, один runner для Docker, другой для macOS/iOS сборок).
- Когда нужно географическое распределение или изоляция от сетевого окружения.
- Когда нужен отдельный набор секретов/маутов/таймаутов.
Повышение лимита параллелизма (limit)
Для каждой регистрации вы можете задать поле limit в её блоке конфигурации, чтобы указать, сколько подпроцессов этот runner может одновременно создавать:
# Runner 1
[[runners]]
executor = "shell"
limit = 4Это позволит данному runner запускать до четырёх задач одновременно. Если другой runner зарегистрирован с limit = 2, и оба связаны с тем же инстансом GitLab, суммарная конфигурация позволит до шести параллельных задач (при отсутствии глобального ограничения).
Совет по ресурсам: Перед увеличением limit убедитесь, что узел(ы), на которых работают runner’ы, имеют достаточно CPU, RAM и I/O, иначе многозадачность приведёт к деградации производительности отдельных job-ов.
Управление request_concurrency
Параллельность выполнения — это не только число активных подпроцессов. GitLab Runner отдельно контролирует, сколько запросов на выполнение задач он готов принять в очередь, через параметр request_concurrency.
# Runner 1
[[runners]]
executor = "shell"
limit = 2
request_concurrency = 4В этом примере runner будет принимать до четырёх одновременных запросов от GitLab (по сути, держать до четырёх задач в состоянии “ожидания”), но запускать одновременно только два подпроцесса. Дополнительные запросы не будут приняты, если число ожидающих уже достигает request_concurrency.
Практическая польза: request_concurrency помогает предотвратить всплески сетевых подключений или чрезмерного давления на систему обработки очереди.
Глобальный уровень concurrency
В начале config.toml вы можете задать глобальный параметр concurrency, который накладывает верхний предел на суммарное число подпроцессов, создаваемых всеми регистрациями данного GitLab Runner’а:
concurrency = 4
# Runner 1
[[runners]]
executor = "shell"
limit = 4
# Runner 2
[[runners]]
executor = "shell"
limit = 2Хотя сумма limit-ов равна 6, глобальный concurrency = 4 означает, что одновременно будут запущены не более четырёх подпроцессов на всей установке.
Рекомендация: устанавливайте глобальный concurrency исходя из суммарной доступной вычислительной мощности и характеристик I/O. Часто полезно задать conservative значение и повышать его по мере мониторинга.
Применение изменений
Изменения в config.toml автоматически обнаруживаются GitLab Runner и применяются почти сразу. Если вы сомневаетесь, можно перезапустить сервис:
sudo gitlab-runner restartЭто аккуратно остановит и запустит сервис, перезагрузив конфигурацию.
Важно: при перезапуске все выполняющиеся задачи будут завершены согласно политикам вашего executor. Для избежания прерывания длительных задач планируйте изменения в окнах обслуживания.
Организация конвейеров для параллельных задач
По умолчанию параллелизм в GitLab CI реализуется на уровне задач, а не стадий. Сначала стадии выполняются последовательно, а внутри стадии задачи выполняются параллельно (при наличии достаточных ресурсов).
Пример простого .gitlab-ci.yml с тремя стадиями и двумя задачами в стадии build и deploy:
stages:
test:
build:
deploy:
test:
stage: test
# ...
build_ios:
stage: build
# ...
build_android:
stage: build
# ...
deploy_ios:
stage: deploy
# ...
deploy_android:
stage: deploy
# ...Если вы хотите разрешить задачам запускаться раньше, чем завершится вся предыдущая стадия, используйте ключ needs для построения DAG (ориентированного ациклического графа):
stages:
test:
build:
deploy:
test:
stage: test
# ...
build_ios:
stage: build
# ...
build_android:
stage: build
# ...
deploy_ios:
stage: deploy
needs: ["test", "build_ios"]
# ...
deploy_android:
stage: deploy
needs: ["test", "build_android"]
# ...Плюсы needs: уменьшение общего времени выполнения пайплайна за счёт раннего запуска зависимых задач. Минусы: усложнение графа зависимостей и потенциальные трудности с отладкой.
Совет: используйте needs:job:artifacts только если действительно нужно передать артефакты между задачами без ожидания всей стадии.
Что с кэшем?
Когда задачи распределены по разным runner’ам, локальные кеши могут не совпадать. По умолчанию runner хранит кеш локально, поэтому второй запуск может не увидеть кеш, созданный первым, если они выполнились на разных машинах.
Решение: использовать общую систему хранения кеша, например S3-совместимое объектное хранилище. В .gitlab-ci.yml вы указываете ключ кеша, а в настройках GitLab Runner конфигурируете провайдер кеша.
Преимущества общего кеша:
- Увеличивает вероятность попадания в кеш.
- Снижает объём повторной работы при сборке зависимостей.
Ограничения:
- Сетевая задержка и пропускная способность влияют на время скачивания/загрузки кеша.
- Кеши по-прежнему используются по принципу best-effort — пайплайны должны работать корректно при их отсутствии.
Практические сценарии и примеры конфигурации
- Масштабирование на одном хосте (много подпроцессов):
- Подходит, если у вас многопроцессорный сервер и задачи короткие по времени.
- Установите
limitвыше (например, 8–16), настройтеconcurrencyв пределах ресурсов.
- Масштабирование горизонтально (несколько хостов):
- Регистрация нескольких runner с низким
limit(1–2) на разных машинах. - Хорошо для изоляции, когда задачи используют много памяти или требуют разных сред.
- Комбинированный подход:
- На мощных машинах давать высокий
limitдля CPU-интенсивных задач. - На слабых узлах ставить
limit = 1и использовать их для специфичных задач (например, Android эмуляция).
Пример расширенной секции config.toml с общим кешем S3 (фрагмент):
concurrent = 4
check_interval = 0
[[runners]]
name = "runner-1"
url = "https://gitlab.example.com/"
token = "TOKEN1"
executor = "docker"
limit = 4
[runners.cache]
Type = "s3"
Path = "gitlab-runner-cache"
Shared = true
[runners.cache.s3]
ServerAddress = "s3.example.com"
AccessKey = "AKIA..."
SecretKey = "secret"
BucketName = "gitlab-runner"
BucketLocation = "eu-central-1"(Настройка S3-секции зависит от версии GitLab Runner; проверьте документацию вашей версии.)
Критерии приёмки
- Изменения
limit/request_concurrencyкорректно применяются после сохранения config.toml или перезапуска. - Набор runner’ов обеспечивает желаемое число одновременных job-ов без деградации их времени выполнения.
- CI-пайплайн проходит успешно и корректно обрабатывает кейсы с пропущенным кешем.
- При изменении конфигурации не потеряны важные токены/секреты и доступы.
Тесты и сценарии приёмки
- Функциональный тест: запустите 10 однотипных job-ов, измерьте пиковое число одновременно выполняемых подпроцессов.
- Нагрузочный тест: постепенно увеличивайте количество запущенных задач и мониторьте CPU, RAM, I/O.
- Тест отказоустойчивости: перезапустите один runner во время выполнения задач и проверьте, что задачи либо корректно перепланируются, либо завершаются ожидаемо.
- Тест кеша: запустите job, создающий кеш, затем другой job на другом runner и проверьте, что кеш скачивается из общего хранилища.
Роль-ориентированные чек-листы
DevOps / SRE:
- Оценить требуемые ресурсы перед повышением limit.
- Настроить мониторинг (CPU, RAM, диск, network I/O) для runner-хостов.
- Настроить общий кеш и убедиться в его доступности.
- Проводить изменения в нерабочее время для долгих job-ов.
Разработчик:
- Структурировать .gitlab-ci.yml с учётом параллелизма.
- Использовать
needsдля ускорения критичных конвейеров. - Держать скрипты idempotent и резилиентными к пропускам кеша.
QA:
- Добавлять тесты, которые можно выполнять параллельно.
- Проверять, что тестовые данные не конфликтуют при параллельном запуске.
SOP: Применение изменений в production
- Создать задачу в системe трекинга с перечнем изменений (limit, request_concurrency, concurrency).
- Выполнить изменения в ветке конфигурации и применить на тестовом стенде.
- Провести нагрузочное тестирование и получить одобрение SRE.
- Применить изменения в конфиге production, сохранить
config.tomlи перезапустить runner при необходимости. - Мониторить метрики в течение 24–72 часов и откатить при ухудшении SLA.
Критерии отката:
- Увеличение средней латентности задач > 30% относительно baseline.
- Резкое падение успешности job-ов (например, рост ошибок > 5%).
Инцидентный план и откат настроек
Если после изменения конфигурации наблюдаются проблемы с производительностью или стабильностью:
- Временно уменьшите
limitиconcurrencyдо предыдущих значений. - Перезапустите GitLab Runner:
sudo gitlab-runner restart. - Если используются отдельные узлы, выведите проблемный хост из пула и распределите задачи на другие runner’ы.
- Проведите post-mortem и внесите исправления в процесс CI/CD.
Безопасность и приватность
- Токены и секреты, используемые в
config.toml, должны храниться с минимально необходимыми правами доступа и в безопасных местах. - При использовании S3-совместимого кеша убедитесь, что передача данных защищена (TLS) и доступ к бакету ограничен.
- Логи runner’ов могут содержать чувствительные фрагменты; настройте ротацию и контроль доступа.
Совместимость и миграция
- Перед миграцией убедитесь, что версия GitLab Runner поддерживает нужные опции кеша и параметры конфигурации.
- При обновлении GitLab Runner читайте release notes — синтаксис секций в
config.tomlиногда меняется. - При переходе на облачные runner’ы (например, autoscaling Docker executor) настройте параметры автоскейлинга и мониторинг затрат.
Частые ошибки и как их избежать
Ошибка: поднять
limitбез оценки ресурсов — результат: все job-ы замедляются. Решение: нагрузочное тестирование и мониторинг.Ошибка: настроить общий кеш, но не задать корректные права доступа — результат: ошибки при загрузке/сохранении кеша. Решение: проверить права и сетевую доступность.
Ошибка: ожидание, что
limitсуммируется бесконечно — на практике есть глобальныйconcurrency. Решение: планируйте оба параметра совместно.
Ментальные модели и эвристики
- “Горизонталь прежде чем вертикаль”: если у вас много однотипных коротких задач, лучше добавить больше runner с небольшим limit, чем давать одному runner огромный limit.
- “Пиковая нагрузка ≠ средняя нагрузка”: оптимизируйте под среднюю загрузку и оставьте запас на пики.
Decision tree для выбора стратегии (Mermaid)
flowchart TD
A[Нужен ли параллелизм?] -->|Да| B{Задачи одинаковы по среде исполнения}
B -->|Да| C[Добавить больше runner или увеличить limit]
B -->|Нет| D[Добавить отдельные runner для каждой среды]
C --> E{Есть общий кеш?}
E -->|Да| F[Настроить S3-совместимый кеш]
E -->|Нет| G[Оставить локальный кеш, учесть промахи]
D --> H[Настроить отдельные конфигурации и limits]
A -->|Нет| I[Оставить текущую конфигурацию]Шаблоны и чек-листы (скелет .gitlab-ci.yml)
Простой шаблон параллельного pipeline с needs и кешем:
stages:
- test
- build
- deploy
variables:
CACHE_DIR: "build_cache"
test_job:
stage: test
script:
- echo "Running tests"
artifacts:
paths:
- ${CACHE_DIR}
build_job_ios:
stage: build
needs: [test_job]
script:
- echo "Building iOS"
build_job_android:
stage: build
needs: [test_job]
script:
- echo "Building Android"
deploy_job:
stage: deploy
needs: [build_job_ios, build_job_android]
script:
- echo "Deploying"Глоссарий (1 строка для каждого)
- Runner: агент, который выполняет CI job-ы.
- Limit: число подпроцессов на регистрацию runner.
- Request_concurrency: число принятых запросов на запуск задач в очереди runner.
- Concurrency: глобальный лимит подпроцессов для всей установки runner.
- Cache: временное хранение артефактов и зависимостей между прогоном job-ов.
Короткое резюме
GitLab Runner предоставляет гибкие инструменты для управления параллелизмом: масштабирование через число runner, тонкая настройка через limit и request_concurrency, и глобальный предел concurrency. Для эффективной работы важно сочетать конфигурацию runner с архитектурой .gitlab-ci.yml, использовать общий кеш при необходимости и тестировать изменения под реальной нагрузкой.
Важно
- Всегда тестируйте изменения на стенде прежде чем вносить в production.
- Мониторьте ресурсы и реакцию пайплайнов после изменений.
Сводка
- Три главных контроля: limit, request_concurrency, concurrency.
- Добавление runner помогает масштабировать горизонтально.
- Использование
needsувеличивает возможности параллелизации внутри pipeline. - Общий кеш (S3) повышает вероятность попадания в кеш при распределённых runner.