GitLab Runner в Kubernetes
Published: 2026-02-24
При запуске джоб GitLab CI внутри Kubernetes каждая джоба получает свежий под, ресурсы ограничиваются на уровне джобы, а хост раннера не нужно чистить. Разберём деплой через Helm, настройку executor-а Docker-in-Docker, лимиты ресурсов, кэш и типичные проблемы.
HelmRelease
yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: gitlab-runner
namespace: gitlab-runner
spec:
chart:
spec:
chart: gitlab-runner
version: "0.63.*"
sourceRef:
kind: HelmRepository
name: gitlab
namespace: flux-system
values:
gitlabUrl: "https://gitlab.example.com"
runnerRegistrationToken: "${RUNNER_TOKEN}"
concurrent: 10
rbac:
create: true
clusterWideAccess: false
runners:
tags: "k8s,dev"
locked: false
config: |
[[runners]]
[runners.kubernetes]
namespace = "gitlab-runner"
image = "alpine:3.19"
privileged = true
[[runners.kubernetes.volumes.empty_dir]]
name = "docker-certs"
mount_path = "/certs/client"
medium = "Memory"
privileged: true обязателен для Docker-in-Docker. В окружениях, где DinD не нужен, ставьте privileged: false и используйте kaniko или buildah.
concurrent: 10 — максимум параллельных джоб на все поды раннера. Если джобы встают в очередь, увеличьте значение — и заодно добавьте ресурсов узлам.
Токен регистрации через ESO
yamlapiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: gitlab-runner-token
namespace: gitlab-runner
spec:
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: gitlab-runner-secret
template:
data:
runner-registration-token: "{{ .token }}"
data:
- secretKey: token
remoteRef:
key: secret/infra/gitlab-runner
property: registration_token
Затем ссылаемся на этот Secret в HelmRelease:
yamlvalues:
existingRunnerSecret: gitlab-runner-secret
Никогда не вставляйте токен регистрации в values-файл или CI-переменные открытым текстом.
Лимиты ресурсов на джобу
toml[[runners]]
[runners.kubernetes]
[runners.kubernetes.pod_annotations]
"cluster-autoscaler.kubernetes.io/safe-to-evict" = "false"
[runners.kubernetes.build_container_resources]
[runners.kubernetes.build_container_resources.requests]
cpu = "500m"
memory = "512Mi"
[runners.kubernetes.build_container_resources.limits]
cpu = "2"
memory = "2Gi"
[runners.kubernetes.helper_container_resources]
[runners.kubernetes.helper_container_resources.requests]
cpu = "100m"
memory = "128Mi"
[runners.kubernetes.helper_container_resources.limits]
cpu = "500m"
memory = "256Mi"
Requests без limits приводят к OOM kill. Слишком низкие limits замедляют сборки. cpu: "2" — разумный потолок для docker build.
safe-to-evict: "false" не даёт cluster autoscaler вытеснять поды с активными джобами при уменьшении числа узлов.
Сервис Docker-in-Docker
yaml# .gitlab-ci.yml
build:
image: docker:24
services:
- name: docker:24-dind
alias: docker
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: /certs
DOCKER_TLS_VERIFY: 1
DOCKER_CERT_PATH: /certs/client
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
Том docker-certs типа emptyDir общий для сервиса dind и build-контейнера — это обеспечивает mutual TLS без --privileged на сервисном контейнере.
Альтернативы DinD
| Инструмент | Privileged | Скорость | Примечание |
|---|---|---|---|
| Docker-in-Docker | Да | Быстро | Требует privileged |
| Kaniko | Нет | Средне | Медленнее, но без прав |
| Buildah | Нет | Средне | Rootless |
Кэш
toml[[runners]]
[runners.cache]
Type = "s3"
Shared = true
[runners.cache.s3]
ServerAddress = "minio.infra.svc.cluster.local:9000"
BucketName = "gitlab-runner-cache"
Insecure = true
В .gitlab-ci.yml:
yamlcache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm/
- vendor/
Без кэша каждая CI-джоба заново скачивает все зависимости. С S3-кэшем повторные джобы выполняются в 3–5 раз быстрее.
Отладка
bash# Логи раннера
kubectl logs -n gitlab-runner deploy/gitlab-runner -f
# Поды с активными джобами
kubectl get pods -n gitlab-runner --field-selector=status.phase=Running
# Зайти в под джобы (пока она работает)
kubectl exec -n gitlab-runner <job-pod-name> -c build -- /bin/sh
# Список зарегистрированных раннеров
kubectl exec -n gitlab-runner deploy/gitlab-runner -- \
gitlab-runner list
Типичные проблемы:
- Под джобы завис в Pending — недостаточно ресурсов на узлах
- Docker socket not found — убедитесь, что задан
DOCKER_HOST=tcp://docker:2376, а не unix-сокет - TLS handshake failed — том
docker-certsдолжен монтироваться по одному и тому же пути в build- и dind-контейнерах