Aller au contenu

CI/CD : runner GitLab dans votre namespace

Héberger votre runner GitLab dans votre namespace a deux vertus : vos jobs tournent au plus près de vos applications, et le gestionnaire du runner s’authentifie via le ServiceAccount bs-namespace-member pré-provisionné — aucun credential à créer pour faire tourner l’infrastructure de CI elle-même.

Un runner GitLab sur Kubernetes, ce sont deux étages :

Étage Rôle ServiceAccount
Le gestionnaire (pod permanent) Crée et supervise un pod par job CI bs-namespace-member — il a besoin de l’API
Les pods de jobs (éphémères) Exécutent vos scripts (build, tests…) default — aucun droit API

C’est le moindre privilège : un job de build compromis (dépendance malveillante, script tiers…) ne peut rien faire sur le cluster. Vos jobs de déploiement, qui ont légitimement besoin de l’API, s’authentifient explicitement — voir plus bas.

Avec le chart Helm officiel (Helm sur Kontainers) :

values-runner.yaml
gitlabUrl: https://gitlab.com/ # ou votre instance (Froggit…)
rbac:
create: false # on n'a pas les droits de créer des rôles…
serviceAccount:
create: false
name: bs-namespace-member # …et pas besoin : celui-ci est fourni
# (gestionnaire uniquement — les pods de
# jobs restent sur le SA default)
concurrent: 2
runners:
config: |
[[runners]]
[runners.kubernetes]
namespace = "{{ .Release.Namespace }}"
cpu_request = "100m"
memory_request = "256Mi"
memory_limit = "256Mi"
ephemeral_storage_request = "1Gi"
ephemeral_storage_limit = "2Gi"
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {memory: 128Mi}
Fenêtre de terminal
# Le token vient de GitLab : Settings › CI/CD › Runners › New project runner
kubectl create secret generic gitlab-runner-secret -n <namespace> \
--from-literal=runner-token='glrt-…' --from-literal=runner-registration-token=''
helm repo add gitlab https://charts.gitlab.io
helm upgrade --install runner gitlab/gitlab-runner \
-n <namespace> -f values-runner.yaml \
--set runners.secret=gitlab-runner-secret

Le runner apparaît dans GitLab, et chaque job CI devient un pod dans votre namespace — soumis aux mêmes quotas que le reste (comptez-les dans votre budget de 20 pods).

Les pods de jobs n’ayant aucun droit API, le job de déploiement s’authentifie avec un kubeconfig permanent stocké en variable CI (type File, masquée et protégée) :

deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- export KUBECONFIG=$KUBE_CONFIG_FILE
- kubectl set image deploy/boutique app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
- kubectl rollout status deploy/boutique --timeout=120s
environment: production
rules:
- if: $CI_COMMIT_TAG

Seul ce job reçoit la variable : les jobs de build et de test du même pipeline restent sans accès au cluster.

  • Pas de Docker-in-Docker privilégié : la politique de sécurité interdit les pods privilégiés. Pour construire des images dans la CI, utilisez kaniko, qui build sans privilèges :

    build:
    stage: build
    image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
    script:
    - /kaniko/executor --context $CI_PROJECT_DIR
    --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  • Stockage éphémère limité à 2 Gi par conteneur : les gros builds (caches npm/gradle…) peuvent le dépasser — montez un PVC de cache via [runners.kubernetes.volumes.pvc] si besoin ;

  • Runner d’équipe multi-environnements : hébergez-le dans un namespace tooling — le réseau intra-organisation permet à ses jobs de joindre dev et prod. Côté déploiement, créez un kubeconfig permanent par namespace cible : une variable CI par environnement, des périmètres étanches.