Les CronJobs Kubernetes sont excellents pour les tâches récurrentes telles que les exports de données nocturnes, la rotation des logs ou le nettoyage périodique. Pourtant, de petites erreurs de configuration peuvent provoquer des exécutions chevauchantes, des planifications manquées, des objets d'historique bruyants ou des jobs qui ne démarrent jamais. Ce guide montre des méthodes pratiques et sûres pour configurer, vérifier et dépanner les CronJobs avec des exemples concrets YAML et kubectl. Vous apprendrez à inventorier votre environnement, choisir des valeurs par défaut sûres, déployer les changements sans surprise, valider le comportement, récupérer après des échecs et adopter une liste de vérification qui rend les opérations reproductibles.
Inventaire des versions et de l'environnement
Avant de modifier quoi que ce soit, capturez une vue minimale mais complète de votre environnement. La version et la topologie déterminent souvent quels champs sont disponibles et comment le contrôleur se comporte.
Commandes
- Vérifier les versions client et serveur :
kubectl version --short
- Lister les groupes d'API CronJob pour confirmer la prise en charge :
kubectl api-resources | grep -i cronjob
- Inventorier les espaces de noms et les CronJobs existants :
kubectl get cronjobs.batch -A
- Inspecter un CronJob spécifique en profondeur :
kubectl get cronjob my-cron -n myns -o yaml
Éléments à capturer (exemples construits ; vérifiez dans votre environnement)
| Élément à capturer | Commande exemple | Valeur exemple (construite) |
|---|---|---|
| Version serveur Kubernetes | kubectl version --short | Server Version: v1.28.3 |
| API CronJob | kubectl api-resources | batch/v1 CronJob |
| Prise en charge du fuseau horaire | kubectl explain cronjob.spec.timeZone | Champ présent depuis v1.27+ |
| Espace de noms et nom | n/a | myns/my-cron |
| Santé du contrôleur | kubectl get deploy -n kube-system | contrôleur cronjob disponible |
Notes
batch/v1CronJob est largement disponible dans les clusters modernes. Si votre cluster est très ancien, confirmez si vous êtes surbatch/v1beta1et planifiez une migration.- Le champ
timeZoneest disponible depuis Kubernetes 1.27+. S'il n'apparaît pas dans la sortie dekubectl explain, ne l'utilisez pas.
Parcours de configuration sûr
Cette section couvre les erreurs de configuration courantes et les choix sûrs, avec du YAML pratique que vous pouvez copier et adapter.
Erreur 1 : Autoriser les exécutions chevauchantes par défaut
Symptôme : Une nouvelle exécution démarre tandis que la précédente est encore active, causant un travail en double ou une contention de ressources.
Pourquoi cela arrive : concurrencyPolicy vaut Allow par défaut.
Choix sûr : Préférez Forbid pour les tâches idempotentes qui ne doivent pas se chevaucher. Utilisez Replace seulement si la nouvelle exécution doit préempter l'ancienne.
Mauvais exemple (chevauchements probables) :
apiVersion: batch/v1
kind: CronJob
metadata:
name: overlap-prone
spec:
schedule: "* * * * *" # chaque minute
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: busybox:1.36
command: ["/bin/sh","-c","echo starting; sleep 90; echo done"]
Correctif :
spec:
concurrencyPolicy: Forbid
schedule: "* * * * *"
jobTemplate:
spec:
backoffLimit: 1
template:
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: busybox:1.36
command: ["/bin/sh","-c","echo starting; sleep 90; echo done"]
Résultat attendu : Lorsqu'une minute s'écoule alors que l'exécution précédente dort encore, la nouvelle exécution est ignorée. Vérifiez avec :
kubectl get jobs -l cronjob-name=overlap-prone
Erreur 2 : restartPolicy invalide dans le modèle de Job
Symptôme : Le Job ne planifie jamais de Pods ; vous voyez des erreurs de validation comme restartPolicy: Always is not allowed for Jobs.
Choix sûr : Réglez restartPolicy sur OnFailure (le plus courant) ou Never.
Extrait de correctif :
spec:
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure # pas Always
Erreur 3 : Planifications manquées à cause d'un startingDeadlineSeconds trop petit
Symptôme : Le CronJob ne crée pas de Job après un incident temporaire du control-plane, une lenteur du registre d'images ou une dérive d'horloge.
Pourquoi cela arrive : startingDeadlineSeconds limite la fenêtre dans laquelle les exécutions manquées sont démarrées. Trop petit signifie que le CronJob abandonne vite. Par exemple, si un job quotidien à 02h00 rate sa fenêtre parce que l'API server était injoignable pendant 15 minutes, un startingDeadlineSeconds de 600 (10 minutes) fera que l'exécution de ce jour sera définitivement ignorée.
Choix sûr : Définissez une fenêtre raisonnable. Pour des jobs horaires, utilisez 3600 secondes (1 heure). Pour des jobs quotidiens, utilisez 86400 secondes (24 heures) ou au moins 3600.
Exemple de correctif pour un job horaire :
spec:
schedule: "0 * * * *"
startingDeadlineSeconds: 3600 # autoriser le rattrapage dans l'heure
Erreur 4 : Encoder le fuseau horaire dans l'expression cron ou dépendre de l'heure du nœud
Symptôme : Les jobs se déclenchent à la mauvaise heure locale ou dérivent lors des transitions d'heure d'été/hiver. Par exemple, un job planifié à 0 2 * pour 2h HNE s'exécutera à 2h UTC (21h HNE la veille) en hiver et 3h UTC (22h HNE) en été si le cluster utilise UTC.
Choix sûr :
- Si votre cluster le prend en charge (Kubernetes 1.27+), utilisez
spec.timeZonepour définir explicitement le fuseau horaire du job. - Sinon, planifiez en UTC et convertissez les heures métier en UTC dans votre planification.
Exemple avec timeZone :
spec:
schedule: "0 2 * * *"
timeZone: "America/New_York" # utiliser seulement si supporté dans votre version de cluster
Erreur 5 : Sur-rétention ou sous-rétention de l'historique des jobs
Symptôme : Bruit API dû à des centaines d'anciens objets Job ou, inversement, pas assez d'historique pour dépanner un échec de la semaine dernière.
Choix sûr : Ajustez les limites par CronJob selon la fréquence de planification. Pour un job quotidien, gardez 7 réussis et 10 échoués. Pour un job horaire, gardez 24 réussis et 48 échoués.
Exemple :
spec:
successfulJobsHistoryLimit: 7
failedJobsHistoryLimit: 10
jobTemplate:
spec:
ttlSecondsAfterFinished: 86400 # optionnel dans le spec du Job quand le contrôleur TTL est activé
Erreur 6 : Relances non bornées sur Pods en échec
Symptôme : Les Pods relancent indéfiniment et chevauchent les planifications suivantes, surtout quand restartPolicy: OnFailure se combine sans backoffLimit.
Choix sûr : Limitez les relances et la durée d'exécution. Définissez backoffLimit pour plafonner les redémarrages de Pod, et activeDeadlineSeconds pour plafonner la durée totale du Job.
Exemple :
spec:
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 1200 # 20 minutes de plafond dur pour chaque job
template:
spec:
restartPolicy: OnFailure
Avec backoffLimit: 2, un Pod en échec redémarre au maximum deux fois (3 tentatives au total). Ensuite, le Job est marqué comme échoué et le contrôleur CronJob ne relancera pas avant la prochaine planification.
Erreur 7 : Service account ou permissions manquantes
Symptôme : Les Pods démarrent mais échouent avec des erreurs RBAC quand ils doivent appeler l'API ou accéder à des secrets.
Choix sûr : Assignez un ServiceAccount minimal et les Role/RoleBinding requis dans le même espace de noms.
Exemple d'extrait :
apiVersion: v1
kind: ServiceAccount
metadata:
name: cron-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cron-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get","list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cron-reader-binding
subjects:
- kind: ServiceAccount
name: cron-sa
roleRef:
kind: Role
name: cron-reader
apiGroup: rbac.authorization.k8s.io
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: rbac-aware
spec:
schedule: "*/15 * * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
serviceAccountName: cron-sa
restartPolicy: OnFailure
containers:
- name: worker
image: busybox:1.36
command: ["/bin/sh","-c","kubectl get cm || echo no kubectl here"]
Erreur 8 : Utiliser Always pour l'image pull sur des images stables
Symptôme : Tirages d'images inutiles augmentent la latence ou échouent quand le registre est down.
Choix sûr : Si vous pinez sur un digest ou un tag immuable, utilisez IfNotPresent.
containers:
- name: worker
image: myrepo/tool@sha256:abc123...
imagePullPolicy: IfNotPresent
Habitudes de déploiement plus sûres
- Exécutions de test : Utilisez
kubectl create job --from=cronjob/pour simuler un job planifié immédiatement. - Validation dry-run : Utilisez
kubectl apply --dry-run=server -f cron.yamlpour attraper les erreurs de schéma. - Changement progressif : Introduisez un nouveau CronJob avec le suffixe
-v2, exécutez-le en parallèle mais suspendez l'ancien (suspend: true) pour une seule fenêtre, puis finalisez le basculement. - Contrôle de suspension : Mettez temporairement un CronJob en pause si nécessaire :
kubectl patch cronjob my-cron -p '{"spec":{"suspend":true}}'
Vérification et diagnostics
Utilisez ces vérifications pour confirmer le comportement attendu et isoler rapidement les problèmes.
Vérifications de base
- Confirmer la santé du contrôleur et l'activité de planification :
kubectl get cronjob my-cron -n myns
kubectl describe cronjob my-cron -n myns
- Lister les Jobs créés par un CronJob :
kubectl get jobs -n myns -l cronjob-name=my-cron
- Inspecter les événements et logs des Pods pour le Job le plus récent :
JOB=$(kubectl get jobs -n myns -l cronjob-name=my-cron -o jsonpath='{.items[-1:].metadata.name}')
kubectl get pods -n myns -l job-name=$JOB
POD=$(kubectl get pods -n myns -l job-name=$JOB -o jsonpath='{.items[0].metadata.name}')
kubectl logs -n myns $POD
- Valider l'analyse de l'expression cron et les champs :
kubectl apply --dry-run=server -f cron.yaml
kubectl explain cronjob.spec # confirmer les champs disponibles
Erreurs courantes, symptômes, vérifications et correctifs
| Erreur | Ce que vous voyez | Vérifier avec | Correctif recommandé |
|---|---|---|---|
| Exécutions chevauchantes (Allow par défaut) | Plusieurs Jobs actifs | kubectl get jobs -l cronjob-name=NAME | Définir concurrencyPolicy: Forbid ou Replace |
| restartPolicy invalide | Job a 0 Pods ; erreur de validation | kubectl apply --dry-run=server -f | Définir restartPolicy: OnFailure ou Never |
| startingDeadlineSeconds trop petit | Planifications manquées non rattrapées | kubectl describe cronjob | Augmenter startingDeadlineSeconds |
| Support timeZone manquant | Champ ignoré ou apply échoue | kubectl explain cronjob.spec.timeZone | Utiliser planifications UTC ou mettre à jour le cluster |
| Rétention d'historique excessive | Centaines d'objets Job | kubectl get jobs -l cronjob-name=NAME | Baisser les limites successful/failed history |
| Relances non bornées | Échecs longs ou chevauchants | kubectl describe job ; regarder backoff | Définir backoffLimit et activeDeadlineSeconds |
| RBAC manquant | Logs Pod montrent erreurs Forbidden | kubectl logs ; kubectl auth can-i | Attacher ServiceAccount minimal et Role |
Résultats attendus pour des CronJobs sains
kubectl get cronjobafficheLAST SCHEDULEavec un timestamp récent qui correspond à votre planification et stratégie de fuseau horaire.kubectl get jobsmontre soit un job réussi pour chaque période attendue, soit un job en cours d'exécution. Les statuts passent de 0/1 à 1/1 completions.kubectl logsdu Pod le plus récent contiennent la sortie attendue sans boucles de crash répétées.
Déclenchement manuel et backfill
Quand vous devez tester la logique sans attendre la planification :
- Créer un job one-off à partir du modèle CronJob :
kubectl create job --from=cronjob/my-cron my-cron-adhoctest -n myns
- Étiqueter et suivre le job ad-hoc distinctement :
kubectl label job my-cron-adhoctest purpose=adhoc -n myns
- Supprimer le job ad-hoc après validation :
kubectl delete job my-cron-adhoctest -n myns
Modes d'échec et récupération
Comprenez ce qui échoue, comment cela se présente et comment récupérer en toute sécurité.
Indisponibilité du contrôleur ou de l'API
- Symptôme : Aucun nouveau Job créé aux heures attendues.
LAST SCHEDULEcesse d'avancer. - Cause : Perturbation du control-plane ou contrôleur CronJob non en cours d'exécution.
- Récupération : Après la récupération du control-plane, assurez-vous que
startingDeadlineSecondsest assez grand pour rattraper les exécutions manquées. Confirmez que le déploiement du contrôleur est sain.
Dérive d'horloge et confusion de fuseau horaire
- Symptôme : Les planifications dérivent par rapport à l'heure métier ou à l'heure d'été/hiver.
- Récupération : Préférez les planifications UTC ou utilisez
spec.timeZonesi votre version le supporte. Validez en comparantLAST SCHEDULEà une horloge UTC connue.
Erreurs de tirage d'image
- Symptôme :
ImagePullBackOffsur les Pods. - Récupération : Vérifiez
imagePullSecrets, la disponibilité du registre, et envisagezIfNotPresentpour les images immuables. Relancez avec un job ad-hoc pour confirmer.
Échecs RBAC
- Symptôme : Erreurs
Forbiddendans les logs lors de l'accès aux ressources API. - Récupération : Attachez un ServiceAccount minimal, Role et RoleBinding. Testez les permissions avec :
kubectl auth can-i get configmaps --as=system:serviceaccount:myns:cron-sa -n myns
Boucles de crash de Pod ou timeouts
- Symptôme : Les Pods redémarrent répétitivement ou dépassent les fenêtres d'exécution.
- Récupération : Définissez
backoffLimità un nombre raisonnable, ajoutezactiveDeadlineSeconds, et assurez-vous que le job est idempotent. Étudiez les logs du conteneur.
Encombrement d'historique
- Symptôme : Grand nombre de Jobs terminés ralentissent les opérations de listage.
- Récupération : Baissez
successfulJobsHistoryLimitetfailedJobsHistoryLimit; activezttlSecondsAfterFinisheddans le modèle de Job si le contrôleur TTL est disponible.
Arrêt d'urgence et reprise
- Suspendre temporairement la planification :
kubectl patch cronjob my-cron -n myns -p '{"spec":{"suspend":true}}'
- Reprendre après atténuation :
kubectl patch cronjob my-cron -n myns -p '{"spec":{"suspend":false}}'
Stratégie de rollback
- Conservez un manifeste connu-bon pour chaque CronJob. Pour faire un rollback, réappliquez le fichier précédent explicitement :
kubectl apply -f cronjob-prev.yaml
- Si un changement de champ nécessite une recréation (rare pour les CronJobs), suspendez le job actuel, créez le remplacement avec un nom distinct, validez une exécution de test, puis supprimez l'ancien.
Vérification après récupération
- Confirmez que
LAST SCHEDULEavance à nouveau. - Assurez-vous qu'un seul Job s'exécute par période quand
concurrencyPolicyestForbid. - Vérifiez que les limites d'historique conservent assez de contexte pour la revue post-incident sans encombrement.
Liste de vérification des opérations
Utilisez cette liste concise lors des revues et avant/après les changements.
Inventaire et prérequis
- [ ]
kubectl version --shortcapturé (client et serveur) - [ ] Groupe d'API CronJob confirmé (
batch/v1) - [ ] Présence du champ
timeZonevérifiée aveckubectl explain - [ ] Espace de noms et noms enregistrés
Sécurité de la configuration
- [ ]
concurrencyPolicydéfini surForbid(ouReplaceavec justification) - [ ]
restartPolicydéfini surOnFailureouNever - [ ]
startingDeadlineSecondsdimensionné à la fenêtre de tolérance attendue - [ ]
successfulJobsHistoryLimitetfailedJobsHistoryLimitajustés - [ ]
backoffLimitetactiveDeadlineSecondsraisonnables - [ ]
serviceAccountNamedéfini si accès API/secret nécessaire, RBAC minimal - [ ] Référence d'image immuable,
imagePullPolicyapproprié - [ ]
suspenddéfini appropriément pendant le déploiement ou les fenêtres de pause
Étapes de validation
- [ ]
kubectl apply --dry-run=serverpasse - [ ]
kubectl describe cronjobmontre l'heure de prochaine planification attendue - [ ] Job ad-hoc manuel créé et complété pour les changements nouveaux ou risqués
Observation et diagnostics
- [ ]
LAST SCHEDULEse met à jour comme attendu après le changement - [ ] Seul le nombre attendu de Jobs actifs par période
- [ ] Logs des Pods inspectés pour signal de succès
Récupération et rollback
- [ ] Manifeste connu-bon sous la main pour rollback immédiat
- [ ] Capacité à suspendre/reprendre vérifiée
- [ ] Nettoyage des jobs ad-hoc ou échoués effectué
Signaux de référence et actions
| Signal | Ce qu'il suggère | Action suivante |
|---|---|---|
| LAST SCHEDULE n'avance pas | Problème contrôleur ou planification | Vérifier santé contrôleur ; revoir startingDeadlineSeconds |
| Plusieurs Jobs concurrents | Chevauchement autorisé | Définir concurrencyPolicy: Forbid ou Replace |
| ImagePullBackOff | Problème registre ou pull policy | Vérifier secrets ; envisager IfNotPresent pour tags immuables |
| Forbidden dans logs | Lacune RBAC | Attacher ServiceAccount ; ajouter Role/Binding minimal |
| Jobs ne finissent jamais | Relances non bornées ou tâche longue | Définir backoffLimit et activeDeadlineSeconds |
Conclusion
Les CronJobs sont fiables quand ils sont configurés délibérément. Le parcours le plus sûr consiste à inventorier les versions et champs, adopter l'exécution non chevauchante par défaut, dimensionner les limites de relance et de délai, et définir une rétention qui garde l'historique utile sans causer d'encombrement. Validez les changements avec un dry-run côté serveur et un job one-off avant d'activer les planifications, et gardez un plan de rollback simple en conservant les manifestes connus-bons. Avec ces pratiques et la liste de vérification ci-dessus, vous pouvez réduire les surprises opérationnelles et maintenir les tâches récurrentes prévisibles.