E-NO
Kubernetes 9 min de lecture

Automatisation des CronJobs Kubernetes avec CI/CD : exemples pratiques

calendar_today Publié : 2026-07-27
update Dernière mise à jour : 2026-07-27
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Automatisation des CronJobs Kubernetes avec CI/CD : exemples pratiques ».

Introduction

Les CronJobs Kubernetes sont idéaux pour les tâches récurrentes : synchronisation de données, génération de rapports, préchauffage de cache et nettoyage. Ce guide montre comment automatiser des CronJobs avec CI/CD (Continuous Integration/Continuous Deployment) : intégration continue et déploiement continu en utilisant des exemples pratiques en YAML, Python, Bash et GitLab CI. Vous apprendrez à :

  • Construire et tester une image de job
  • Valider les manifestes avant le déploiement
  • Déployer en toute sécurité avec suspension préalable et tests à la demande
  • Ajouter des tests de fumée et garde-fous
  • Effectuer un rollback rapide en cas d’échec
  • Diagnostiquer les échecs de pipeline courants

Pourquoi ça fonctionne : une approche guidée par l’exemple aide les équipes à passer de l’intention à une automatisation fonctionnelle, tandis qu’une séparation claire des étapes réduit le retravail et accélère les itérations.

Vue d’ensemble du workflow

Le workflow de bout en bout ci-dessous est simple, sûr et prêt pour la production.

1. Écrire le code du job

Exemple de job Python avec codes de sortie explicites et logs :

# app/main.py
import logging, os, sys, time

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s" )

def validate_env():
    required = ["EXAMPLE_PARAM" ]
    missing = [k for k in required if not os.getenv(k)]
    if missing:
        logging.error("Missing required env: %s", " , " .join(missing) )
        return False
    return True

def run_job():
    logging.info("job start" )
    # Simuler du travail
    time.sleep(2)
    # Ajouter la logique réelle ici
    logging.info("job done" )
    return 0

if __name__ == "__main__":
    if not validate_env():
        sys.exit(2)
    code = run_job()
    sys.exit(code)

Point d’entrée avec gestion d’erreur stricte :

# app/entrypoint.sh
#!/usr/bin/env bash
set -Eeuo pipefail
trap 'echo "[ERROR] line $LINENO status $?" >&2' ERR
python /app/main.py

Dockerfile minimal :

# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY app/requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt || true
COPY app/ /app/
RUN useradd -u 10001 appuser && chown -R appuser /app
USER 10001
ENTRYPOINT ["bash", "/app/entrypoint.sh"]

2. Définir le manifeste CronJob

Des valeurs par défaut sûres limitent le rayon d’impact et facilitent le débogage.

# k8s/cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: report-cron
  namespace: staging
spec:
  schedule: "*/15 * * * *"  # toutes les 15 minutes
  # timeZone: "UTC"  # décommenter si votre cluster le supporte
  concurrencyPolicy: Forbid  # éviter les exécutions chevauchées
  startingDeadlineSeconds: 300  # ne pas démarrer si trop en retard
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 2
  suspend: true  # démarrer suspendu ; test de fumée d’abord
  jobTemplate:
    spec:
      backoffLimit: 1
      activeDeadlineSeconds: 600  # limite dure sur la durée d’exécution
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: report
            image: registry.example.com/report-cron:${IMAGE_TAG}
            imagePullPolicy: IfNotPresent
            env:
            - name: EXAMPLE_PARAM
              value: nightly
            resources:
              requests:
                cpu: "100m"
                memory: "128Mi"
              limits:
                cpu: "500m"
                memory: "512Mi"
          imagePullSecrets:
          - name: regcred

Notes :

  • Utilisez des tags d’image immuables (ex. SHA du commit). Évitez latest.
  • Utilisez suspend: true pour les premiers déploiements ; activez après un test de fumée réussi.
  • Pour les secrets, montez depuis un Secret ou utilisez votre approche standard de gestion des secrets.

3. Ajouter les étapes CI/CD

Un exemple pratique GitLab CI avec build, validation, déploiement, test de fumée, promotion et rollback.

# .gitlab-ci.yml
stages: [test, build, validate, deploy_staging, smoke_test, deploy_prod, rollback]

variables:
  APP_NAME: "report-cron"
  IMAGE_REGISTRY: "registry.example.com"
  IMAGE_TAG: "$CI_COMMIT_SHA"
  KUBE_NAMESPACE_STAGING: "staging"
  KUBE_NAMESPACE_PROD: "prod"

# Fournir DOCKER_AUTH, KUBECONFIG et kubectl dans vos runners

unit-test:
  stage: test
  image: python:3.11-slim
  script:
    - pip install -r app/requirements.txt || true
    - python -m py_compile app/main.py

build-image:
  stage: build
  image: docker:24
  services: ["docker:24-dind" ]
  script:
    - echo "$DOCKER_AUTH" | docker login -u "$DOCKER_USER" --password-stdin $IMAGE_REGISTRY
    - docker build -t $IMAGE_REGISTRY/$APP_NAME:$IMAGE_TAG .
    - docker push $IMAGE_REGISTRY/$APP_NAME:$IMAGE_TAG
  needs: ["unit-test" ]

validate-manifest:
  stage: validate
  image: bitnami/kubectl:1.30
  script:
    - sed "s/\${IMAGE_TAG}/$IMAGE_TAG/g" k8s/cronjob.yaml > k8s/rendered.yaml
    - kubectl apply --dry-run=client -f k8s/rendered.yaml
  needs: ["build-image" ]

deploy-staging:
  stage: deploy_staging
  image: bitnami/kubectl:1.30
  script:
    - kubectl config use-context "$KUBE_CONTEXT_STAGING"
    - kubectl -n $KUBE_NAMESPACE_STAGING apply -f k8s/rendered.yaml
    - kubectl -n $KUBE_NAMESPACE_STAGING annotate cronjob/$APP_NAME ci-commit=$CI_COMMIT_SHA --overwrite
  needs: ["validate-manifest" ]
  environment:
    name: staging

smoke-test-staging:
  stage: smoke_test
  image: bitnami/kubectl:1.30
  script:
    - kubectl config use-context "$KUBE_CONTEXT_STAGING"
    - export SMOKE_JOB=${APP_NAME}-smoke-$(date +%s)
    - kubectl -n $KUBE_NAMESPACE_STAGING create job $SMOKE_JOB --from=cronjob/$APP_NAME
    - kubectl -n $KUBE_NAMESPACE_STAGING wait --for=condition=complete job/$SMOKE_JOB --timeout=10m || (kubectl -n $KUBE_NAMESPACE_STAGING logs job/$SMOKE_JOB; exit 1)
    - kubectl -n $KUBE_NAMESPACE_STAGING logs job/$SMOKE_JOB
    - kubectl -n $KUBE_NAMESPACE_STAGING delete job/$SMOKE_JOB --ignore-not-found
    - echo "Smoke test passed"
  needs: ["deploy-staging" ]

promote-prod:
  stage: deploy_prod
  image: bitnami/kubectl:1.30
  script:
    - kubectl config use-context "$KUBE_CONTEXT_PROD"
    - sed "s/namespace: staging/namespace: $KUBE_NAMESPACE_PROD/g" k8s/rendered.yaml > k8s/prod.yaml
    - kubectl -n $KUBE_NAMESPACE_PROD apply -f k8s/prod.yaml
    - kubectl -n $KUBE_NAMESPACE_PROD annotate cronjob/$APP_NAME ci-commit=$CI_COMMIT_SHA --overwrite
    - # Optionnellement désuspendre après test de fumée en prod
  needs: ["smoke-test-staging" ]
  environment:
    name: production

rollback:
  stage: rollback
  image: bitnami/kubectl:1.30
  when: manual
  variables:
    ROLLBACK_TAG: ""  # définir cette variable au déclenchement
  script:
    - test -n "$ROLLBACK_TAG" || (echo "Set ROLLBACK_TAG" && exit 1)
    - kubectl config use-context "$KUBE_CONTEXT_PROD"
    - kubectl -n $KUBE_NAMESPACE_PROD patch cronjob $APP_NAME --type='json' \
      -p='[{"op":"replace","path":"/spec/jobTemplate/spec/template/spec/containers/0/image","value":"'$IMAGE_REGISTRY'/'$APP_NAME':'$ROLLBACK_TAG'"}]'
    - # Vérifier via un job one-off avant de réactiver la planification
    - export SMOKE_JOB=${APP_NAME}-rb-$(date +%s)
    - kubectl -n $KUBE_NAMESPACE_PROD create job $SMOKE_JOB --from=cronjob/$APP_NAME
    - kubectl -n $KUBE_NAMESPACE_PROD wait --for=condition=complete job/$SMOKE_JOB --timeout=10m || (kubectl -n $KUBE_NAMESPACE_PROD logs job/$SMOKE_JOB; exit 1)
    - kubectl -n $KUBE_NAMESPACE_PROD logs job/$SMOKE_JOB
    - kubectl -n $KUBE_NAMESPACE_PROD delete job/$SMOKE_JOB --ignore-not-found

Vérifications de déploiement sécurisées

  • Faire un dry-run des manifestes avant l’application.
  • Déployer les CronJobs suspendus dans les nouveaux environnements.
  • Tester avec un Job one-off créé depuis le template du CronJob.
  • Limiter la durée des exécutions avec activeDeadlineSeconds et empêcher le chevauchement avec concurrencyPolicy: Forbid.
  • Utiliser des tags immuables et annoter les ressources avec le SHA du commit pour la traçabilité.

Activer les planifications après vérification

Une fois les tests de fumée passés, désuspendre la planification :

kubectl -n staging patch cronjob report-cron -p '{"spec": {"suspend": false}}'

Répéter en production après promotion et validation.

Question rapide 1 sur 2

Quelle annotation kubectl définit-il sur un Job lorsqu'il est créé manuellement à partir d'un CronJob en utilisant le drapeau --from=cronjob/<nom> ?

La référence indique que lorsqu'on utilise kubectl create job avec le drapeau --from=cronjob/<nom-du-cronjob>, kubectl définit l'annotation cronjob.kubernetes.io/instantiate: "manual" sur le Job nouvellement créé.

Plan pilote local

Commencez avec un seul CronJob et gardez une portée étroite.

Objectifs du pilote

  • Un CronJob dans un namespace bac à sable
  • Build, validation, déploiement suspendu et test de fumée réussi
  • Mesuré par un code de sortie 0 et les logs attendus

Étapes

  1. Choisir un job à faible risque (ex. génération de rapport sans effets de bord externes).
  2. Conteneuriser et ajouter codes de sortie stricts et logs (comme ci-dessus).
  3. Écrire un manifeste CronJob avec valeurs par défaut sûres et suspend: true.
  4. Exécuter des vérifications locales :
  • Linter le Python, lancer tests rapides
  • Rendre le manifeste avec le SHA du commit
  • kubectl apply --dry-run=client -f k8s/rendered.yaml
  1. Déployer dans un namespace bac à sable.
  2. Créer un job one-off depuis le CronJob et attendre la fin.
  3. Inspecter logs et statut de sortie ; corriger les problèmes.
  4. Documenter les critères de succès et seulement alors désuspendre la planification.

Pourquoi ce plan : un pilote étroit, mesurable et inspectable localement est le chemin le plus rapide vers la valeur et l’apprentissage sans risquer la production.

Modèles pratiques de rollback

Les CronJobs ne supportent pas kubectl rollout undo. Gardez le rollback simple :

  • Tags immuables : construire des images taguées avec le SHA du commit ; conserver une trace du dernier tag connu bon.
  • Patch retour au dernier tag connu bon et vérifier avec un job one-off.
  • Alternative : revenir au commit Git qui a mis à jour le tag d’image et redéployer.

Exemple de patch (déjà dans le job CI) :

kubectl -n prod patch cronjob report-cron --type='json' \
  -p='[{"op":"replace","path":"/spec/jobTemplate/spec/template/spec/containers/0/image","value":"registry.example.com/report-cron:abc123"}]'

Question rapide 2 sur 2

À quoi l'annotation cronjob.kubernetes.io/instantiate aide-t-elle à distinguer ?

L'annotation permet de distinguer les Jobs créés à la demande par un utilisateur des Jobs que le contrôleur CronJob crée automatiquement à l'heure planifiée.

Échecs de pipeline courants et correctifs

  • ImagePullBackOff : identifiants de registre manquants ou mauvais tag d’image.
  • Correctif : vérifier imagePullSecrets et tags immuables ; confirmer que le push a réussi.
  • CrashLoopBackOff ou sortie non nulle : code ou configuration d’environnement incorrecte.
  • Correctif : ajouter variables d’environnement requises ; renforcer la gestion d’erreur du point d’entrée ; inspecter les logs.
  • Job dépasse la limite de temps :
  • Correctif : définir activeDeadlineSeconds et revoir la charge ; diviser en tâches plus petites.
  • Exécutions chevauchées causent des conflits :
  • Correctif : concurrencyPolicy: Forbid et espacement raisonnable de la planification.
  • Heures de début manquées quand le cluster est occupé :
  • Correctif : définir startingDeadlineSeconds et envisager d’augmenter les ressources.
  • CronJob suspendu ne s’exécute jamais :
  • Correctif : désuspendre après test de fumée réussi.
  • Erreurs RBAC ou de contexte dans CI :
  • Correctif : confirmer contexte kubectl, namespace et permissions pour apply, create job et patch.
  • Confusion de fuseau horaire Cron :
  • Correctif : planifier en UTC ou valider le comportement du fuseau horaire du cluster ; documenter les attentes.

Conclusion

Automatiser les CronJobs Kubernetes avec CI/CD est simple quand on sépare les préoccupations et qu’on intègre la sécurité :

  • Construire et tester l’image avec codes de sortie explicites
  • Valider les manifestes avec dry runs
  • Déployer suspendu, puis tester via un Job one-off
  • Promouvoir avec tags immuables et annotations claires
  • Garder un rollback simple et rapide en patchant le tag d’image

Commencez avec un CronJob en bac à sable, rendez-le mesurable, et n’étendez qu’une fois votre pilote vert et observable.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO