Déploiement d'un Runner GitLab dans Kubernetes avec Docker in Docker
GitLab permet l'automatisation de procédures sur vos dépôts Git grâce à sa solution d'intégration et de déploiement continue (CI/CD). Ces traitements sont exécutés sur des GitLab Runners, que vous pouvez déployer au sein de clusters Kubernetes chez SdV.
Le paramétrage décrit permettra de disposer d'un service Docker in Docker (dind) afin de builder des images Docker depuis vos pipelines. Cette procédure est valable pour une instance GitLab hébergée par SdV ou pour l'instance SaaS sur gitlab.com.
Prérequis
Avant de débuter l'installation, assurez-vous de disposer des éléments suivants :
| Ressource | Description |
|---|---|
| Helm 3 | Disponible sur votre poste de travail (Installation) |
| kubeconfig | Fichier de configuration valide pour accéder à votre cluster Kubernetes |
| Droits GitLab | Rôle Maintainer ou Owner dans votre projet GitLab |
| kubectl | CLI Kubernetes configurée et fonctionnelle |
| Namespace | Espace de noms dédié au runner (création possible lors du déploiement) |
Versions
La procédure d'installation d'un runner GitLab peut évoluer dans le temps selon les releases du projet. À l'heure de la rédaction de ce guide, les versions utilisées sont :
| Composant | Version |
|---|---|
| Chart Helm | 0.86.0 |
| GitLab Runner | 18.9.0 |
| Image dind | docker:dind (latest) |
| Kubernetes | 1.18+ minimum |
Installation
Préparation du dépôt GitLab
Avant tout, rendez-vous dans votre projet GitLab, dans le menu Settings > CI/CD, section Runners. Vous devriez visualiser un écran similaire à la capture ci-après.

Deux actions sont à réaliser :
- Désactiver les runners mutualisés (encadré orange) : permet d'utiliser exclusivement votre runner dédié
- Noter l'URL et le Token d'enregistrement de votre projet (encadré cyan) : nécessaires pour la configuration Helm
Préparation du chart Helm
Ajoutez le repository Helm officiel de GitLab :
helm repo add gitlab https://charts.gitlab.io
helm repo updateAfin de connaître toutes les options de configuration disponibles, vous pouvez télécharger le chart dans son ensemble pour visualiser le fichier values.yaml :
helm fetch gitlab/gitlab-runner --untar
cat gitlab-runner/values.yamlStratégies de déploiement
Deux approches sont possibles pour l'installation du service Docker in Docker :
| Méthode | Portée | Avantages | Inconvénients |
|---|---|---|---|
1. Service dans .gitlab-ci.yml | Par dépôt | Service lancé uniquement pour les jobs qui en ont besoin | Configuration dupliquée dans chaque dépôt, faible évolutivité |
| 2. Service dans le Runner | Globale | Configuration centralisée, .gitlab-ci.yml simplifiés | Service démarré pour tous les jobs, modification nécessite un redéploiement |
1. Déclaration du service dind dans les .gitlab-ci.yml
1.a. Déploiement
Dans ce cas de figure, le values.yaml que nous suggérons d'utiliser est le suivant :
# URL de votre instance GitLab
gitlabUrl: [URL_GITLAB]
# Token d'enregistrement du runner (depuis Settings > CI/CD > Runners)
runnerRegistrationToken: [TOKEN_GITLAB]
# Configuration RBAC pour le runner
rbac:
create: true
# Ressources Kubernetes accessibles par le runner
resources: ["pods", "pods/exec", "secrets"]
# Actions autorisées
verbs: ["get", "list", "watch", "create", "patch", "delete"]
# Limité au namespace de déploiement
clusterWideAccess: false
# Configuration du runner
runners:
executor: kubernetes
config: |
[[runners]]
[runners.kubernetes]
# Image par défaut pour les jobs
image = "ubuntu:20.04"
# Requis pour Docker in Docker
privileged = true
[runners.feature_flags]
# Active l'helper pour le GitLab Container Registry
FF_GITLAB_REGISTRY_HELPER_IMAGE = trueExplication des paramètres RBAC :
| Paramètre | Description | Impact |
|---|---|---|
create: true | Crée automatiquement les objets RBAC | Le runner dispose des permissions nécessaires |
clusterWideAccess: false | Limite les droits au namespace | Isolation et sécurité renforcée |
resources | Types de ressources accessibles | Permet de gérer les pods, secrets, etc. |
verbs | Actions autorisées | CRUD complet sur les ressources |
Déployez désormais votre runner à l'aide de la commande suivante :
# Installer le runner avec Helm 3
helm upgrade --install \
--namespace gitlab-runner \
--create-namespace \
-f values.yaml \
gitlab-runner \
gitlab/gitlab-runnerVérifier le déploiement :
# Vérifier le statut du runner
kubectl -n gitlab-runner get pods
kubectl -n gitlab-runner logs -l app=gitlab-runner
# Vérifier les ressources RBAC créées
kubectl -n gitlab-runner get role,rolebinding,serviceaccount1.b. Utilisation
Une fois déployé, patientez quelques instants et retournez sur l'écran Runners de votre projet GitLab. Le runner devrait apparaître avec un indicateur vert :

Désormais, vous pouvez déclarer un service Docker in Docker dans vos dépôts GitLab. Voici un exemple de fichier .gitlab-ci.yml :
# Image de base pour tous les jobs
image: docker:latest
# Service Docker in Docker
services:
- name: docker:dind
# MTU réduit pour compatibilité réseau cluster
command: ["--mtu=1400"]
# Variables d'environnement globales
variables:
REGISTRY_IMAGE_PATH: registry.gitlab.com/group/project:latest
# Désactive TLS pour communication avec dind
DOCKER_TLS_CERTDIR: ""
# Adresse du daemon Docker
DOCKER_HOST: tcp://docker:2375
# Script exécuté avant chaque job
before_script:
# Attente démarrage du service dind
- sleep 30
- docker info
stages:
- build
- test
build_image:
stage: build
script:
- echo "Building image ${REGISTRY_IMAGE_PATH}"
- docker build --pull -t ${REGISTRY_IMAGE_PATH} .
- docker push ${REGISTRY_IMAGE_PATH}
only:
- main
- develop
test_image:
stage: test
script:
- docker pull ${REGISTRY_IMAGE_PATH}
- docker run --rm ${REGISTRY_IMAGE_PATH} /bin/sh -c "echo Test OK"
dependencies:
- build_imageExplication des paramètres critiques :
| Paramètre | Valeur | Raison |
|---|---|---|
--mtu=1400 | MTU réduit | L'image Docker officielle utilise MTU 1500 par défaut, incompatible avec certains réseaux overlay Kubernetes |
DOCKER_TLS_CERTDIR="" | TLS désactivé | Force la communication HTTP non chiffrée avec le service dind (communication intra-pod) |
DOCKER_HOST | tcp://docker:2375 | Nom DNS du service dind (correspond au name dans services) |
sleep 30 | Délai d'attente | L'image dind ne fournit pas de healthcheck, ce délai garantit que le daemon est prêt |
2. Déclaration du service dind dans le Runner
2.a. Déploiement
Voici le fichier values.yaml recommandé qui intègre le service dind directement dans la configuration du runner :
# URL de votre instance GitLab
gitlabUrl: [URL_GITLAB]
# Token d'enregistrement du runner
runnerRegistrationToken: [TOKEN_GITLAB]
# Configuration RBAC
rbac:
create: true
resources: ["pods", "pods/exec", "secrets"]
verbs: ["get", "list", "watch", "create", "patch", "delete"]
clusterWideAccess: false
# Configuration avancée du runner
runners:
executor: kubernetes
config: |
[[runners]]
# Variables d'environnement injectées dans tous les jobs
environment = [
"DOCKER_TLS_CERTDIR=",
"DOCKER_HOST=tcp://127.0.0.1:2375"
]
[runners.kubernetes]
# Image par défaut
image = "ubuntu:20.04"
# Mode privileged requis pour Docker in Docker
privileged = true
# Service dind démarré automatiquement avec chaque job
[[runners.kubernetes.services]]
name = "docker:dind"
command = [
"--mtu=1400"
]
[runners.feature_flags]
# Support GitLab Container Registry
FF_GITLAB_REGISTRY_HELPER_IMAGE = trueDifférences clés avec la méthode 1 :
| Élément | Méthode 1 (service dans CI) | Méthode 2 (service dans runner) |
|---|---|---|
| Localisation config dind | .gitlab-ci.yml | values.yaml du runner |
| Variables d'environnement | À déclarer dans chaque dépôt | Injectées automatiquement |
| Maintenance | Difficile (multiples dépôts) | Centralisée |
| Flexibilité | Haute (par dépôt) | Moyenne (nécessite redéploiement) |
Déployez le runner avec la commande suivante :
# Installer le runner avec Helm 3
helm update --install \
--namespace gitlab-runner \
--create-namespace \
-f values.yaml \
gitlab-runner \
gitlab/gitlab-runnerVérifier le déploiement :
# Statut du runner
kubectl -n gitlab-runner get pods
# Logs du runner
kubectl -n gitlab-runner logs -l app=gitlab-runner
# Inspecter la configuration
kubectl -n gitlab-runner get cm
kubectl -n gitlab-runner describe cm gitlab-runner
# Tester un job
kubectl -n gitlab-runner logs -l app=gitlab-runner --tail=100 -f2.b. Utilisation
Une fois déployé, patientez quelques instants et retournez sur l'écran Runners de votre projet GitLab. Le runner devrait apparaître avec un indicateur vert :

Désormais, vous pouvez utiliser le service Docker in Docker démarré automatiquement par votre runner. Voici un exemple simplifié de fichier .gitlab-ci.yml :
# Image de base
image: docker:latest
# Variables personnalisées
variables:
REGISTRY_IMAGE_PATH: registry.gitlab.com/group/project:latest
# Les variables DOCKER_TLS_CERTDIR et DOCKER_HOST
# sont déjà définies par le runner
# Attente démarrage du service dind
before_script:
- sleep 30
- docker info
stages:
- build
- push
build_image:
stage: build
script:
- echo "Building ${REGISTRY_IMAGE_PATH}"
- docker build --pull -t ${REGISTRY_IMAGE_PATH} .
only:
- main
- develop
push_image:
stage: push
before_script:
- sleep 30
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker push ${REGISTRY_IMAGE_PATH}
dependencies:
- build_image
only:
- mainAvantages de cette configuration :
- Pas besoin de déclarer le service dind dans
.gitlab-ci.yml - Variables d'environnement Docker automatiquement disponibles
- Configuration homogène sur tous les dépôts
- Maintenance centralisée sur le runner
Commandes kubectl utiles
Voici les commandes essentielles pour exploiter et diagnostiquer votre runner GitLab :
# Lister les ressources du namespace
kubectl -n gitlab-runner get all
# Détails du pod runner
kubectl -n gitlab-runner describe pod -l app=gitlab-runner
# Logs en temps réel
kubectl -n gitlab-runner logs -l app=gitlab-runner -f
# Logs des jobs (pods temporaires)
kubectl -n gitlab-runner get pods --watch
kubectl -n gitlab-runner logs runner-xxxxx-project-xxxxx-concurrent-x
# Vérifier les secrets
kubectl -n gitlab-runner get secrets
kubectl -n gitlab-runner describe secret
# Redémarrer le runner
kubectl -n gitlab-runner rollout restart deployment gitlab-runner
# Inspecter la configuration RBAC
kubectl -n gitlab-runner get role,rolebinding,serviceaccount
kubectl -n gitlab-runner describe role
# Vérifier les ressources consommées
kubectl -n gitlab-runner top podConfiguration avancée
Limitation des ressources
Pour éviter la surconsommation de ressources, ajoutez des limites dans values.yaml :
runners:
config: |
[[runners]]
[runners.kubernetes]
# Ressources pour le build container
cpu_request = "100m"
cpu_limit = "2"
memory_request = "256Mi"
memory_limit = "2Gi"
# Ressources pour le service dind
service_cpu_request = "100m"
service_cpu_limit = "1"
service_memory_request = "256Mi"
service_memory_limit = "1Gi"
# Helpers
helper_cpu_request = "50m"
helper_cpu_limit = "500m"
helper_memory_request = "64Mi"
helper_memory_limit = "256Mi"Node selection
Pour déployer le runner sur des nodes spécifiques :
runners:
config: |
[[runners]]
[runners.kubernetes]
# NodeSelector
[runners.kubernetes.node_selector]
"workload" = "ci-cd"
"environment" = "production"
# Tolerations pour taints
[[runners.kubernetes.node_tolerations]]
key = "ci-workload"
operator = "Equal"
value = "true"
effect = "NoSchedule"Cache et artifacts
Pour améliorer les performances avec un cache persistant :
runners:
config: |
[[runners]]
[runners.cache]
Type = "s3"
Shared = true
[runners.cache.s3]
ServerAddress = "s3.amazonaws.com"
BucketName = "gitlab-runner-cache"
BucketLocation = "eu-west-1"
[runners.kubernetes]
# Volume pour cache local
[[runners.kubernetes.volumes.empty_dir]]
name = "docker-cache"
mount_path = "/cache"
medium = "Memory"Bonnes pratiques
Sécurité
- Isolation : Utilisez un namespace dédié pour chaque runner ou équipe
- RBAC minimal : Ne donnez que les permissions strictement nécessaires (
clusterWideAccess: false) - Secrets : Stockez les credentials dans des
SecretKubernetes ou GitLab CI/CD Variables - Images : Utilisez des images de base maîtrisées et scannées (pas
latest) - Registry privé : Configurez l'accès aux registries privés via
imagePullSecrets - Network Policies : Limitez le trafic réseau des pods runner si possible
# Image pull secret pour registry privé
imagePullSecrets:
- name: gitlab-registry-credentials
# Configuration pour registry privé
runners:
config: |
[[runners]]
[runners.kubernetes]
image_pull_secrets = ["gitlab-registry-credentials"]Performance
- Ressources : Définissez des limites adaptées à vos workloads
- Cache : Activez le cache S3 ou
PVCpour réutiliser les dépendances - Concurrent jobs : Ajustez le nombre de jobs simultanés selon votre cluster
runners:
config: |
concurrent = 10 # Nombre max de jobs simultanés
[[runners]]
limit = 5 # Limite pour ce runner spécifiqueMaintenance
- Logs : Configurez la rotation et l'archivage des logs
- Monitoring : Intégrez Prometheus pour suivre les métriques du runner
- Mises à jour : Planifiez les mises à jour du chart Helm et de l'image runner
- Nettoyage : Surveillez les pods terminés et les volumes orphelins
# Nettoyer les pods terminés
kubectl -n gitlab-runner delete pods --field-selector=status.phase=Succeeded
kubectl -n gitlab-runner delete pods --field-selector=status.phase=FailedObservabilité
Activez les métriques Prometheus du runner :
metrics:
enabled: true
portName: metrics
port: 9252
serviceMonitor:
enabled: trueDépannage
Le runner n'apparaît pas dans GitLab
Symptômes : Le pod runner est en cours d'exécution mais n'apparaît pas dans l'interface GitLab.
Diagnostic :
kubectl -n gitlab-runner logs -l app=gitlab-runnerCauses possibles :
| Problème | Solution |
|---|---|
| Token invalide | Vérifiez le token dans GitLab (Settings > CI/CD > Runners) |
| URL incorrecte | Vérifiez gitlabUrl dans values.yaml (avec https://) |
| Problème réseau | Testez la connectivité : kubectl exec -it <pod> -- curl -I <gitlab-url> |
| Certificat SSL | Ajoutez certsSecretName si certificat auto-signé |
Les jobs restent en statut "pending"
Symptômes : Les jobs CI/CD ne démarrent jamais.
Diagnostic :
# Vérifier les événements du namespace
kubectl -n gitlab-runner get events --sort-by='.lastTimestamp'
# Vérifier les quotas et limites
kubectl -n gitlab-runner describe resourcequota
kubectl -n gitlab-runner describe limitrangeCauses possibles :
| Problème | Solution |
|---|---|
| Quota dépassé | Augmentez les quotas du namespace ou réduisez les requests |
| Pas de nodes disponibles | Vérifiez kubectl get nodes et les ressources disponibles |
| Image inaccessible | Vérifiez imagePullSecrets et les credentials registry |
| RBAC insuffisant | Vérifiez les permissions avec kubectl auth can-i --list --as=system:serviceaccount:gitlab-runner:<sa-name> |
Erreur "Cannot connect to the Docker daemon"
Symptômes : Les jobs échouent avec l'erreur de connexion au daemon Docker.
Diagnostic :
# Vérifier les logs du service dind
kubectl -n gitlab-runner logs <job-pod> -c svc-0
# Vérifier les variables d'environnement
kubectl -n gitlab-runner exec <job-pod> -c build -- env | grep DOCKERSolutions :
- Vérifiez que
DOCKER_HOST=tcp://localhost:2375(méthode 2) outcp://docker:2375(méthode 1) - Vérifiez que
DOCKER_TLS_CERTDIR=""est bien défini - Augmentez le
sleepdansbefore_script(essayez 60 secondes) - Vérifiez que
privileged: trueest activé
Le build échoue avec des erreurs réseau
Symptômes : Timeouts lors du pull d'images ou de dépendances.
Solutions :
- MTU : Vérifiez que
--mtu=1400est bien configuré - DNS : Testez la résolution DNS :
before_script:
- nslookup google.com
- ping -c 3 8.8.8.8- Proxy : Si un proxy est nécessaire, configurez-le :
runners:
config: |
[[runners]]
environment = [
"HTTP_PROXY=http://proxy.entreprise.fr:8080",
"HTTPS_PROXY=http://proxy.entreprise.fr:8080",
"NO_PROXY=localhost,127.0.0.1,.cluster.local"
]Les jobs sont très lents
Diagnostic :
# Vérifier les ressources CPU/Mémoire
kubectl -n gitlab-runner top pod
# Vérifier les I/O disque
kubectl -n gitlab-runner exec<pod> -- df -hOptimisations :
- Cache : Activez le cache S3 ou PVC
- Image layers : Optimisez vos Dockerfiles (multi-stage builds)
- Ressources : Augmentez les
cpu_limitetmemory_limit - Node local storage : Utilisez des nodes avec SSD
Maintenance et mise à jour
Mise à jour du runner
# Lister les versions disponibles
helm search repo gitlab/gitlab-runner --versions
# Mettre à jour le repository
helm repo update
# Upgrader le runner
helm upgrade --install \
--namespace gitlab-runner \
--create-namespace \
-f values.yaml \
gitlab-runner \
gitlab/gitlab-runner
# Vérifier la nouvelle version
kubectl -n gitlab-runner get pods
kubectl -n gitlab-runner logs -l app=gitlab-runner | grep "version"Sauvegarde de la configuration
# Exporter la configuration Helm
helm -n gitlab-runner get values gitlab-runner > gitlab-runner-values-backup.yaml
# Exporter tous les manifestes Kubernetes
kubectl -n gitlab-runner get all,secrets,cm,role,rolebinding,sa -o yaml > gitlab-runner-backup.yamlDésinstallation
# Désinstaller le runner
helm -n gitlab-runner uninstall gitlab-runner
# Nettoyer les ressources résiduelles
kubectl delete namespace gitlab-runner
# Vérifier qu'il ne reste rien
kubectl -n gitlab-runner get allConsidérations de sécurité
Mode privileged
Isolation des workloads
Pour renforcer la sécurité, isolez les runners par namespace et appliquez des NetworkPolicies :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: gitlab-runner-isolation
namespace: gitlab-runner
spec:
podSelector:
matchLabels:
app: gitlab-runner
policyTypes:
- Ingress
- Egress
egress:
# Autoriser vers API Kubernetes
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 443
# Autoriser vers GitLab
- to:
- podSelector: {}
ports:
- protocol: TCP
port: 443
# Autoriser DNS
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53