Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

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 :

RessourceDescription
Helm 3Disponible sur votre poste de travail (Installation)
kubeconfigFichier de configuration valide pour accéder à votre cluster Kubernetes
Droits GitLabRôle Maintainer ou Owner dans votre projet GitLab
kubectlCLI Kubernetes configurée et fonctionnelle
NamespaceEspace 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 :

ComposantVersion
Chart Helm0.86.0
GitLab Runner18.9.0
Image dinddocker:dind (latest)
Kubernetes1.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.

Runners

Deux actions sont à réaliser :

  1. Désactiver les runners mutualisés (encadré orange) : permet d'utiliser exclusivement votre runner dédié
  2. 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 :

Terminal
helm repo add gitlab https://charts.gitlab.io
helm repo update

Afin 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 :

Terminal
helm fetch gitlab/gitlab-runner --untar
cat gitlab-runner/values.yaml

Stratégies de déploiement

Deux approches sont possibles pour l'installation du service Docker in Docker :

MéthodePortéeAvantagesInconvénients
1. Service dans .gitlab-ci.ymlPar dépôtService lancé uniquement pour les jobs qui en ont besoinConfiguration dupliquée dans chaque dépôt, faible évolutivité
2. Service dans le RunnerGlobaleConfiguration centralisée, .gitlab-ci.yml simplifiésService 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 :

values.yaml
# 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 = true

Explication des paramètres RBAC :

ParamètreDescriptionImpact
create: trueCrée automatiquement les objets RBACLe runner dispose des permissions nécessaires
clusterWideAccess: falseLimite les droits au namespaceIsolation et sécurité renforcée
resourcesTypes de ressources accessiblesPermet de gérer les pods, secrets, etc.
verbsActions autoriséesCRUD complet sur les ressources

Déployez désormais votre runner à l'aide de la commande suivante :

Terminal
# Installer le runner avec Helm 3
helm upgrade --install \
  --namespace gitlab-runner \
  --create-namespace \
  -f values.yaml \
  gitlab-runner \
  gitlab/gitlab-runner

Vérifier le déploiement :

Terminal
# 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,serviceaccount

1.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 :

Runners

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 :

.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_image

Explication des paramètres critiques :

ParamètreValeurRaison
--mtu=1400MTU réduitL'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_HOSTtcp://docker:2375Nom DNS du service dind (correspond au name dans services)
sleep 30Délai d'attenteL'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 :

values.yaml
# 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 = true

Différences clés avec la méthode 1 :

ÉlémentMéthode 1 (service dans CI)Méthode 2 (service dans runner)
Localisation config dind.gitlab-ci.ymlvalues.yaml du runner
Variables d'environnementÀ déclarer dans chaque dépôtInjectées automatiquement
MaintenanceDifficile (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 :

Terminal
# Installer le runner avec Helm 3
helm update --install \
  --namespace gitlab-runner \
  --create-namespace \
  -f values.yaml \
  gitlab-runner \
  gitlab/gitlab-runner

Vérifier le déploiement :

Terminal
# 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 -f

2.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 :

Runners

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 :

.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:
    - main

Avantages 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 :

Terminal
# 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 pod

Configuration avancée

Limitation des ressources

Pour éviter la surconsommation de ressources, ajoutez des limites dans values.yaml :

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 :

values.yaml
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 :

values.yaml
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 Secret Kubernetes 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
values.yaml
# 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 PVC pour réutiliser les dépendances
  • Concurrent jobs : Ajustez le nombre de jobs simultanés selon votre cluster
values.yaml
runners:
  config: |
    concurrent = 10    # Nombre max de jobs simultanés
    [[runners]]
      limit = 5        # Limite pour ce runner spécifique

Maintenance

  • 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
Terminal
# 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=Failed

Observabilité

Activez les métriques Prometheus du runner :

values.yaml
metrics:
  enabled: true
  portName: metrics
  port: 9252
  serviceMonitor:
    enabled: true

Dé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 :

Terminal
kubectl -n gitlab-runner logs -l app=gitlab-runner

Causes possibles :

ProblèmeSolution
Token invalideVérifiez le token dans GitLab (Settings > CI/CD > Runners)
URL incorrecteVérifiez gitlabUrl dans values.yaml (avec https://)
Problème réseauTestez la connectivité : kubectl exec -it <pod> -- curl -I <gitlab-url>
Certificat SSLAjoutez certsSecretName si certificat auto-signé

Les jobs restent en statut "pending"

Symptômes : Les jobs CI/CD ne démarrent jamais.

Diagnostic :

Terminal
# 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 limitrange

Causes possibles :

ProblèmeSolution
Quota dépasséAugmentez les quotas du namespace ou réduisez les requests
Pas de nodes disponiblesVérifiez kubectl get nodes et les ressources disponibles
Image inaccessibleVérifiez imagePullSecrets et les credentials registry
RBAC insuffisantVé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 :

Terminal
# 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 DOCKER

Solutions :

  1. Vérifiez que DOCKER_HOST=tcp://localhost:2375 (méthode 2) ou tcp://docker:2375 (méthode 1)
  2. Vérifiez que DOCKER_TLS_CERTDIR="" est bien défini
  3. Augmentez le sleep dans before_script (essayez 60 secondes)
  4. Vérifiez que privileged: true est activé

Le build échoue avec des erreurs réseau

Symptômes : Timeouts lors du pull d'images ou de dépendances.

Solutions :

  1. MTU : Vérifiez que --mtu=1400 est bien configuré
  2. DNS : Testez la résolution DNS :
.gitlab-ci.yml
before_script:
  - nslookup google.com
  - ping -c 3 8.8.8.8
  1. Proxy : Si un proxy est nécessaire, configurez-le :
values.yaml
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 :

Terminal
# 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 -h

Optimisations :

  1. Cache : Activez le cache S3 ou PVC
  2. Image layers : Optimisez vos Dockerfiles (multi-stage builds)
  3. Ressources : Augmentez les cpu_limit et memory_limit
  4. Node local storage : Utilisez des nodes avec SSD

Maintenance et mise à jour

Mise à jour du runner

Terminal
# 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

Terminal
# 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.yaml

Désinstallation

Terminal
# 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 all

Considérations de sécurité

Mode privileged

Isolation des workloads

Pour renforcer la sécurité, isolez les runners par namespace et appliquez des NetworkPolicies :

network-policy.yaml
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

Références