Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Jobs et CronJobs Kubernetes : exécuter des tâches ponctuelles et planifiées

15 min de lecture

logo kubernetes

Un Job exécute une tâche jusqu’à sa complétion : migration de base de données, traitement batch, génération de rapport. Un CronJob crée des objets Job selon un planning ; ce sont ensuite ces Jobs qui exécutent les Pods nécessaires.

Contrairement aux Pods gérés par un Deployment qui tournent en continu, les Jobs s’arrêtent une fois leur travail terminé. Kubernetes garantit que la tâche sera complétée, même en cas d’échec temporaire.

Prérequis : un cluster Kubernetes avec kubectl configuré.

  • Créer un Job pour une tâche ponctuelle
  • Configurer le comportement en cas d’échec (backoffLimit, activeDeadlineSeconds)
  • Paralléliser l’exécution avec completions et parallelism
  • Planifier des tâches récurrentes avec CronJob
  • Maîtriser les paramètres de production (concurrencyPolicy, suspend, timeZone)
  • Appliquer les bonnes pratiques pour le nettoyage automatique
RessourceComportementCas d’usage
DeploymentMaintient N Pods en continuApplications web, API, services
JobExécute jusqu’à complétion, puis s’arrêteMigration, backup, traitement batch
CronJobCrée un Job selon un planningTâches planifiées, maintenance

Un Job crée un Pod, exécute la tâche, et se termine une fois le travail fait :

hello-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: hello-job
spec:
template:
spec:
containers:
- name: hello
image: busybox
command: ["echo", "Hello from Kubernetes Job"]
restartPolicy: Never
Fenêtre de terminal
kubectl apply -f hello-job.yaml

Attendez la fin de l’exécution :

Fenêtre de terminal
kubectl wait --for=condition=complete job/hello-job --timeout=60s

Vérifiez le statut :

Fenêtre de terminal
kubectl get jobs
Sortie
NAME STATUS COMPLETIONS DURATION AGE
hello-job Complete 1/1 4s 10s
Fenêtre de terminal
kubectl logs job/hello-job
Sortie
Hello from Kubernetes Job
Fenêtre de terminal
kubectl describe job hello-job

Informations clés :

  • Completions : nombre d’exécutions réussies requises
  • Parallelism : nombre de Pods exécutés en parallèle
  • Active / Succeeded / Failed : état des Pods
Fenêtre de terminal
kubectl get pods -l job-name=hello-job
job-complet.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: backup-database
spec:
backoffLimit: 3 # Tentatives max en cas d'échec
activeDeadlineSeconds: 300 # Timeout global (5 min)
ttlSecondsAfterFinished: 3600 # Nettoyage auto après 1h
template:
spec:
containers:
- name: backup
image: postgres:16
command: ["pg_dump", "-h", "db-host", "-U", "admin", "mydb"]
restartPolicy: Never
ChampDescriptionValeur par défaut
backoffLimitNombre de tentatives avant abandon6 (sauf Indexed Jobs)
activeDeadlineSecondsDurée max d’exécution du JobIllimitée
ttlSecondsAfterFinishedNettoyage automatique après N secondesNon activé
completionsNombre d’exécutions réussies requises1
parallelismNombre de Pods simultanés1

Si un Pod échoue, Kubernetes le relance avec un délai exponentiel (10s, 20s, 40s…). backoffLimit stoppe les tentatives :

spec:
backoffLimit: 3 # Abandon après 3 échecs

Le Job passe en statut Failed avec la raison BackoffLimitExceeded.

Pour la plupart des Jobs, backoffLimit vaut 6 par défaut. Les Indexed Jobs disposent aussi d’options avancées comme backoffLimitPerIndex.

Empêche un Job de tourner indéfiniment :

spec:
activeDeadlineSeconds: 300 # 5 minutes max

Si le temps est dépassé, tous les Pods sont arrêtés et le Job passe en Failed avec la raison DeadlineExceeded.

ValeurComportement
NeverKubernetes crée un nouveau Pod à chaque tentative
OnFailureLe même Pod redémarre (garde les volumes locaux)

Pour traiter plusieurs éléments simultanément :

parallel-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: parallel-job
spec:
completions: 10 # 10 exécutions au total
parallelism: 3 # 3 Pods en parallèle
template:
spec:
containers:
- name: worker
image: busybox
command: ["sh", "-c", "echo 'Processing...' && sleep 5"]
restartPolicy: Never

Kubernetes lance 3 Pods en parallèle, puis en lance de nouveaux dès qu’un se termine, jusqu’à atteindre 10 complétions.

En mode Indexed, chaque Pod reçoit un index de complétion unique. Kubernetes l’expose via l’annotation batch.kubernetes.io/job-completion-index, et la variable d’environnement JOB_COMPLETION_INDEX est disponible dans le conteneur :

spec:
completions: 5
parallelism: 5
completionMode: Indexed
template:
spec:
containers:
- name: worker
image: busybox
command: ["sh", "-c", "echo Processing chunk $JOB_COMPLETION_INDEX"]

Idéal pour traiter des partitions de données (chunk 0, chunk 1…).

Sans nettoyage, les Jobs terminés s’accumulent. ttlSecondsAfterFinished les supprime automatiquement :

spec:
ttlSecondsAfterFinished: 3600 # Supprimé 1h après complétion

Un CronJob crée automatiquement des Jobs selon un planning :

daily-backup.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-backup
spec:
schedule: "0 2 * * *" # Tous les jours à 2h du matin
timeZone: "Europe/Paris" # Fuseau horaire explicite
successfulJobsHistoryLimit: 3 # Garde les 3 derniers Jobs réussis
failedJobsHistoryLimit: 1 # Garde le dernier Job échoué
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres:16
command: ["pg_dump", "-h", "db-host", "-U", "admin", "mydb"]
restartPolicy: Never
┌───────────── minute (0-59)
│ ┌───────────── heure (0-23)
│ │ ┌───────────── jour du mois (1-31)
│ │ │ ┌───────────── mois (1-12)
│ │ │ │ ┌───────────── jour de la semaine (0-6, 0=dimanche)
│ │ │ │ │
* * * * *
ExpressionSignification
0 * * * *Chaque heure à :00
0 2 * * *Tous les jours à 2h
0 0 * * 0Chaque dimanche à minuit
*/15 * * * *Toutes les 15 minutes
0 9-17 * * 1-5Chaque heure de 9h à 17h, lundi à vendredi
Fenêtre de terminal
kubectl get cronjobs
Sortie
NAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE
daily-backup 0 2 * * * Europe/Paris False 0 12h 3d

Que faire si l’exécution précédente n’est pas terminée ?

ValeurComportement
AllowAutorise plusieurs Jobs simultanés (par défaut)
ForbidSkip l’exécution si un Job est en cours
ReplaceArrête l’ancien Job et en démarre un nouveau
spec:
concurrencyPolicy: Forbid # Recommandé pour les backups

Si le cluster était indisponible à l’heure prévue, combien de temps après peut-on encore démarrer ?

spec:
startingDeadlineSeconds: 3600 # 1h de délai max

Si startingDeadlineSeconds est défini, Kubernetes saute une exécution qui a dépassé ce délai. Si ce champ n’est pas défini, les occurrences n’ont pas de date limite de démarrage.

Arrêter temporairement les exécutions sans supprimer le CronJob :

Fenêtre de terminal
kubectl patch cronjob daily-backup -p '{"spec":{"suspend":true}}'

Réactiver :

Fenêtre de terminal
kubectl patch cronjob daily-backup -p '{"spec":{"suspend":false}}'

Depuis Kubernetes 1.27, vous pouvez spécifier le fuseau horaire :

spec:
timeZone: "Europe/Paris"

Sans timeZone, le planning utilise le fuseau horaire du kube-controller-manager, souvent UTC dans de nombreux clusters.

Pour tester ou forcer une exécution :

Fenêtre de terminal
kubectl create job --from=cronjob/daily-backup manual-backup

Suivez l’exécution :

Fenêtre de terminal
kubectl wait --for=condition=complete job/manual-backup --timeout=300s
kubectl logs job/manual-backup
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
spec:
backoffLimit: 1 # Pas de retry sur migration
activeDeadlineSeconds: 600 # 10 min max
ttlSecondsAfterFinished: 86400
template:
spec:
containers:
- name: migrate
image: myapp:latest
command: ["./manage.py", "migrate", "--no-input"]
envFrom:
- secretRef:
name: db-credentials
restartPolicy: Never
apiVersion: batch/v1
kind: CronJob
metadata:
name: postgres-backup
spec:
schedule: "0 3 * * *"
timeZone: "Europe/Paris"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 7 # 1 semaine d'historique
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres:16
command:
- /bin/sh
- -c
- pg_dump -h $DB_HOST -U $DB_USER $DB_NAME | gzip > /backup/$(date +%Y%m%d).sql.gz
envFrom:
- secretRef:
name: db-credentials
volumeMounts:
- name: backup-volume
mountPath: /backup
volumes:
- name: backup-volume
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: Never
apiVersion: batch/v1
kind: CronJob
metadata:
name: data-cleanup
spec:
schedule: "0 4 * * 0" # Chaque dimanche à 4h
timeZone: "Europe/Paris"
jobTemplate:
spec:
ttlSecondsAfterFinished: 86400
template:
spec:
containers:
- name: cleanup
image: myapp:latest
command: ["./cleanup.sh", "--older-than", "90d"]
restartPolicy: Never
  1. Le Job reste en “Running” indéfiniment

    Vérifiez les logs du Pod :

    Fenêtre de terminal
    kubectl logs job/my-job

    Solution : ajoutez activeDeadlineSeconds pour forcer un timeout.

  2. Le Job échoue avec BackoffLimitExceeded

    Analysez les événements :

    Fenêtre de terminal
    kubectl describe job my-job

    Vérifiez les logs des Pods échoués :

    Fenêtre de terminal
    kubectl logs -l job-name=my-job --all-containers
  3. Le CronJob ne s’exécute pas

    Vérifiez l’expression cron et le fuseau horaire :

    Fenêtre de terminal
    kubectl get cronjob my-cronjob
    kubectl describe cronjob my-cronjob | grep "Last Schedule"
  4. CronJob suspendu accidentellement

    Fenêtre de terminal
    kubectl get cronjob my-cronjob -o jsonpath='{.spec.suspend}'

    Si true, réactivez avec kubectl patch.

ErreurCauseSolution
BackoffLimitExceededTrop d’échecsAnalyser les logs, corriger le code
DeadlineExceededJob trop longAugmenter activeDeadlineSeconds ou optimiser
Job ne démarre pasExpression cron invalideVérifier la syntaxe et le timeZone
Jobs qui s’accumulentPas de TTLAjouter ttlSecondsAfterFinished

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
80% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  1. Un Job exécute une tâche jusqu’à complétion, un CronJob la planifie
  2. backoffLimit limite les tentatives, activeDeadlineSeconds impose un timeout
  3. ttlSecondsAfterFinished nettoie automatiquement les Jobs terminés
  4. parallelism et completions permettent le traitement parallèle
  5. concurrencyPolicy: Forbid évite les exécutions simultanées de CronJobs
  6. timeZone garantit des exécutions à l’heure locale
  7. suspend permet de mettre un CronJob en pause sans le supprimer
  8. Testez avec kubectl create job --from=cronjob/... avant la mise en prod

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn