Introduction
Les CronJobs Kubernetes sont le mécanisme intégré pour exécuter des charges de travail planifiées dans le temps au sein d'un cluster. Ils permettent aux opérateurs de programmer des tâches récurrentes telles que les sauvegardes de bases de données, la génération de rapports, la rotation des journaux, le renouvellement de certificats ou la synchronisation périodique de données sans recourir à des planificateurs externes. Cet article explique l'architecture des CronJobs Kubernetes et détaille leur implémentation pratique, leur vérification et leur récupération à l'aide de commandes kubectl réelles et de manifestes YAML.
L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets, vérifier le résultat et documenter la récupération si l'état attendu n'est pas atteint. Les lecteurs doivent avoir une familiarité de base avec les concepts Kubernetes tels que les Pods, les Deployments et les namespaces. Tous les exemples sont testés avec Kubernetes 1.24+ et supposent que kubectl est configuré pour un cluster de test.
Inventaire des versions et de l'environnement
Avant de créer ou de modifier des CronJobs, confirmez la version du cluster et la version d'API disponible pour les ressources CronJob. Exécutez kubectl version --short pour voir les versions du client et du serveur. Pour Kubernetes 1.21 et versions ultérieures, l'API stable batch/v1 est utilisée. Les clusters plus anciens peuvent encore servir batch/v1beta1, mais cette API est dépréciée et ne doit pas être utilisée pour de nouveaux manifestes.
kubectl version --short
# La sortie attendue inclut :
# Client Version: v1.24.0
# Server Version: v1.24.0
Vérifiez que l'API batch est disponible :
kubectl api-versions | grep batch
# La sortie doit inclure batch/v1
Ensuite, identifiez le namespace où les CronJobs s'exécuteront. Pour des tests isolés, créez un namespace dédié :
kubectl create namespace cronjob-test
kubectl get namespaces
Vérifiez le compte de service par défaut et les autorisations dans ce namespace. Les pods des CronJobs utilisent le compte de service par défaut du namespace sauf s'il est remplacé. Si les pods doivent accéder à l'API Kubernetes, examinez les rôles et les liaisons RBAC avec :
kubectl get serviceaccounts -n cronjob-test
kubectl get rolebindings,clusterrolebindings -n cronjob-test
Enfin, confirmez que le cluster dispose de ressources suffisantes. Les CronJobs peuvent consommer du CPU et de la mémoire comme toute autre charge de travail. Utilisez kubectl top nodes pour voir l'utilisation actuelle :
kubectl top nodes
# NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
# node-1 250m 5% 2Gi 20%
Si les nœuds sont proches de la saturation, envisagez de planifier les CronJobs uniquement lorsque les ressources sont disponibles ou utilisez des sélecteurs de nœuds pour acheminer les tâches vers des nœuds dédiés.
Chemin de configuration sécurisé
Une configuration sécurisée de CronJob commence par un manifeste minimal appliqué à un namespace de test et vérifié avant tout déploiement en production. Commencez par créer un CronJob qui exécute une simple commande echo toutes les minutes. Cela vérifie la planification, la création de pods et l'achèvement des tâches sans effets secondaires.
Enregistrez le YAML suivant dans cronjob-test.yaml :
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cron
namespace: cronjob-test
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: hello
image: busybox:1.36
command: ["/bin/sh", "-c", "date; echo Hello from CronJob"]
Appliquez le manifeste :
kubectl apply -f cronjob-test.yaml
# Sortie attendue : cronjob.batch/hello-cron created
Vérifiez que le CronJob existe et inspectez sa planification et son statut :
kubectl get cronjobs -n cronjob-test
# NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
# hello-cron * * * * * False 0 32s 1m
En une minute, une tâche (Job) doit être créée. Listez les Jobs et les Pods pour confirmer :
kubectl get jobs -n cronjob-test
kubectl get pods -n cronjob-test --selector=job-name
# Les pods doivent avoir des noms comme hello-cron-28412345-abcde
Une fois la tâche terminée, consultez ses journaux :
kubectl logs job/hello-cron-28412345 -n cronjob-test
# La sortie inclut la date et "Hello from CronJob"
Si aucune tâche n'est créée, inspectez les événements du CronJob :
kubectl describe cronjob hello-cron -n cronjob-test
# Recherchez la section Events en bas
Les erreurs de configuration courantes incluent une chaîne de planification invalide, un restartPolicy manquant (doit être Never ou OnFailure), ou une image de conteneur qui ne peut pas être extraite. Corrigez le manifeste et réappliquez-le jusqu'à ce que le CronJob de test fonctionne de manière fiable.
Après avoir confirmé le chemin de base, étendez le manifeste avec des variables d'environnement, des limites de ressources et une politique de concurrence. L'exemple suivant définit des demandes et des limites de ressources et empêche les exécutions qui se chevauchent :
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-cron
namespace: cronjob-test
spec:
schedule: "0 2 * * *" # Tous les jours à 2h00
concurrencyPolicy: Forbid
startingDeadlineSeconds: 60
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: postgres:15-alpine
env:
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
command: ["pg_dump"]
args: ["-h", "db-host", "-U", "postgres", "mydb", ">", "/backup/backup.sql"]
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Avant d'appliquer, créez le secret référencé :
kubectl create secret generic db-secret --from-literal=password='votre-mot-de-passe-securise' -n cronjob-test
Appliquez le CronJob et attendez la prochaine exécution planifiée. Notez que cet exemple écrit la sauvegarde dans un chemin local à l'intérieur du conteneur ; en production, montez un PersistentVolume ou poussez vers un stockage d'objets.
Gardez le test local réduit. Appliquez un seul manifeste, inspectez les ressources générées et vérifiez le comportement avant de passer à un équilibreur de charge cloud ou à un contrôleur d'entrée. Pour les CronJobs, aucun trafic externe n'est généralement requis, mais si la tâche expose temporairement un service, utilisez kubectl port-forward pour des tests locaux avant de l'exposer largement.
Vérification et diagnostic
La vérification du comportement des CronJobs n'est pas un événement ponctuel ; c'est un processus continu d'observation des planifications, de l'achèvement des tâches et des journaux des pods. Commencez par une vérification en lecture seule :
kubectl get cronjobs -n cronjob-test -o wide
# NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR
# hello-cron * * * * * False 0 10s 5m hello busybox:1.36 <none>
# backup-cron 0 2 * * * False 0 <none> 1m backup postgres:15-alpine <none>
Inspectez l'historique d'un CronJob spécifique :
kubectl get jobs -n cronjob-test --sort-by=.metadata.creationTimestamp
# Liste les tâches avec leurs horodatages de création ; la plus récente en bas
Pour une tâche en échec, décrivez la tâche et le pod :
kubectl describe job <job-name> -n cronjob-test
kubectl describe pod <pod-name> -n cronjob-test
Recherchez des événements tels que Back-off restarting failed container, Failed to pull image ou Pod sandbox changed. Ceux-ci indiquent la cause racine.
Récupérez les journaux d'un pod terminé ou en échec :
kubectl logs <pod-name> -n cronjob-test --previous
Le drapeau --previous est essentiel pour les boucles de crash : il récupère les journaux de l'instance de conteneur précédente. Si les journaux sont vides, vérifiez le code de sortie du conteneur dans le statut du pod :
kubectl get pod <pod-name> -n cronjob-test -o jsonpath='{.status.containerStatuses[0].state}'
Si aucune tâche n'apparaît lorsque la planification se déclenche, vérifiez le champ suspend du CronJob et consultez les journaux du contrôleur CronJob. Le contrôleur s'exécute dans kube-controller-manager sur le plan de contrôle, mais vous pouvez inspecter ses événements récents via le statut du CronJob :
kubectl get cronjob hello-cron -n cronjob-test -o yaml
# Vérifiez status.lastScheduleTime et status.active
Si lastScheduleTime est absent, la chaîne de planification peut être invalide ou le CronJob est suspendu. Validez l'expression cron. Kubernetes utilise le format cron standard avec cinq champs. Par exemple, 0 2 * signifie 2h00 tous les jours. Si vous avez besoin d'une précision à la seconde, Kubernetes ne le prend pas en charge ; utilisez un script wrapper avec sleep ou envisagez un autre outil.
Pour un diagnostic plus approfondi, activez la sortie verbeuse lors de l'application ou de la description :
kubectl apply -f cronjob-test.yaml -v=8 2>&1 | grep -i cronjob
Cela montre les requêtes et réponses de l'API. Si le CronJob est limité en raison de startingDeadlineSeconds, ajustez la valeur ou augmentez la fréquence de vérification.
Modes de défaillance et récupération
Les CronJobs échouent pour des raisons prévisibles. Comprendre les modes de défaillance courants et disposer d'étapes de récupération prêtes réduit les temps d'arrêt et prévient les problèmes en cascade.
1. Planifications manquées en raison d'une indisponibilité du contrôleur ou d'une charge élevée
Si le plan de contrôle Kubernetes est indisponible à l'heure prévue, le contrôleur CronJob peut manquer l'exécution. Par défaut, startingDeadlineSeconds n'est pas défini, ce qui signifie qu'une tâche manquée s'exécutera dès que le contrôleur récupère, mais seulement si elle est toujours dans la tolérance de planification. Pour les tâches critiques en temps, définissez startingDeadlineSeconds à une petite valeur (par exemple, 60) pour garantir que la tâche est ignorée si elle ne peut pas démarrer dans la minute suivant l'heure prévue. Si une tâche ne doit pas être ignorée, laissez-le non défini et surveillez l'arriéré.
Pour vérifier si une tâche a été manquée puis démarrée, comparez le creationTimestamp de la tâche avec la planification cron. Le status.lastScheduleTime du CronJob indique quand le contrôleur a créé une tâche pour la dernière fois. S'il est significativement plus tard que prévu, examinez la santé du contrôleur :
kubectl get pods -n kube-system | grep controller-manager
kubectl logs -n kube-system kube-controller-manager-<node> | grep -i cronjob
Récupération : assurez-vous que le plan de contrôle est sain et que des ressources suffisantes sont disponibles. Si une tâche a été manquée et doit s'exécuter, créez manuellement une tâche à partir du modèle de tâche du CronJob :
kubectl create job manual-run --from=cronjob/hello-cron -n cronjob-test
2. Boucles de crash des pods en raison d'erreurs d'application
Si le conteneur se termine avec un code non nul, le pod de la tâche entrera dans CrashLoopBackOff. Diagnostiquez avec :
kubectl describe pod <pod-name> -n cronjob-test | grep -A10 "State:"
kubectl logs <pod-name> -n cronjob-test --previous
Les correctifs courants incluent la correction des arguments de commande, l'augmentation des limites de ressources, la correction des variables d'environnement ou la mise à jour de l'image. Après avoir corrigé le manifeste, réappliquez-le et laissez la prochaine exécution planifiée repartir à zéro. Pour tester immédiatement, créez une tâche manuelle comme ci-dessus.
3. Échecs d'extraction d'image
Si l'image n'existe pas ou si les identifiants sont incorrects, les pods échouent avec ErrImagePull ou ImagePullBackOff. Vérifiez le nom et l'étiquette de l'image et contrôlez imagePullSecrets dans la spécification du pod.
imagePullSecrets:
- name: regcred
Créez le secret avec :
kubectl create secret docker-registry regcred --docker-server=<registry> --docker-username=<user> --docker-password=<pass> -n cronjob-test
Après l'ajout, supprimez l'ancien pod pour forcer une nouvelle extraction :
kubectl delete pod <pod-name> -n cronjob-test
4. Conflits de concurrence
Si une tâche prend plus de temps que l'intervalle de planification, plusieurs tâches peuvent s'exécuter simultanément. Le champ concurrencyPolicy contrôle cela :
Allow(par défaut) : les tâches simultanées peuvent s'exécuter.Forbid: ignore la nouvelle tâche si la précédente est toujours en cours.Replace: termine la tâche en cours et démarre la nouvelle.
Pour les tâches idempotentes comme la synchronisation de données, Forbid est sûr. Pour les tâches qui doivent s'exécuter à l'heure et peuvent tolérer une interruption, Replace peut être approprié. Assurez-vous que la politique correspond aux exigences métier.
Pour voir les tâches actives :
kubectl get jobs -n cronjob-test --field-selector=status.active=1
5. Épuisement des ressources
Si le cluster manque de ressources, les pods peuvent rester bloqués dans Pending. Utilisez kubectl describe pod pour voir des événements comme Insufficient cpu ou Insufficient memory. Ajustez les demandes de ressources, planifiez les tâches pendant les périodes de faible trafic ou ajoutez des nœuds.
Liste de contrôle de récupération pour toute défaillance :
- Observez l'état actuel avec
kubectl get cronjobs, jobs, pods -n cronjob-test. - Décrivez la ressource en échec pour obtenir les événements.
- Récupérez les journaux, y compris avec
--previous. - Corrigez la cause racine (manifeste, secrets, ressources, image).
- Réappliquez le manifeste du CronJob.
- Si nécessaire, déclenchez une tâche manuelle pour tester.
- Surveillez la prochaine exécution planifiée et vérifiez le succès.
Documentez l'incident et les étapes de récupération dans un runbook pour référence future.
Liste de contrôle des opérations
Utilisez cette liste de contrôle avant, pendant et après les déploiements de CronJobs pour garantir la cohérence et la sécurité.
Pré-déploiement
- [ ] Confirmez la version de Kubernetes et la disponibilité de l'API batch/v1.
- [ ] Créez un namespace de test dédié.
- [ ] Vérifiez les autorisations RBAC pour les comptes de service utilisés par le CronJob.
- [ ] Vérifiez la disponibilité des ressources du cluster.
- [ ] Validez l'expression de planification cron.
- [ ] Examinez la politique de redémarrage de la tâche (
NeverouOnFailure) et la politique de concurrence. - [ ] Assurez-vous que les secrets et ConfigMaps requis existent.
- [ ] Définissez les demandes et limites de ressources pour tous les conteneurs.
- [ ] Planifiez la sortie de la tâche (volume persistant, stockage externe, journalisation).
- [ ] Définissez
startingDeadlineSecondssi le temps est critique.
Pendant le déploiement
- [ ] Appliquez le manifeste du CronJob avec
kubectl apply -f. - [ ] Surveillez les erreurs immédiates :
kubectl get cronjob <name> -o yaml. - [ ] Laissez passer un intervalle de planification et vérifiez qu'une tâche est créée.
- [ ] Vérifiez le statut de la tâche et du pod :
kubectl get jobs,pods -n <namespace>. - [ ] Consultez les journaux de la première exécution réussie.
- [ ] Si la tâche échoue, suivez les étapes de récupération en cas de défaillance.
Post-déploiement et continu
- [ ] Surveillez
kubectl get cronjobspour les colonnesLAST SCHEDULEetACTIVE. - [ ] Configurez des alertes pour les échecs de tâches à l'aide d'outils comme Prometheus et Alertmanager. La métrique
kube_job_status_failedpeut être interrogée. - [ ] Auditez régulièrement les manifestes des CronJobs pour les champs dépréciés ou la dérive des ressources.
- [ ] Testez le déclenchement manuel avec
kubectl create job --from=cronjob/...au moins une fois. - [ ] Documentez tout changement et mettez à jour les runbooks.
Exemple de règle d'alerte Prometheus pour les tâches en échec :
groups:
- name: cronjob-alerts
rules:
- alert: CronJobFailed
expr: increase(kube_job_status_failed{job_name=~"cronjob-test.*"}[5m]) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Le CronJob {{ $labels.job_name }} a échoué"
Conclusion
Les CronJobs Kubernetes offrent un moyen flexible et natif d'exécuter des charges de travail planifiées. Comprendre leur architecture, comment le contrôleur CronJob crée des Jobs, comment les Jobs créent des Pods et comment les modes de défaillance sont gérés, est essentiel pour des opérations fiables. Cet article a parcouru la vérification des versions, la configuration sécurisée, le diagnostic, la récupération en cas de défaillance et une liste de contrôle des opérations avec des commandes kubectl concrètes et des exemples de manifestes.
La clé pour maîtriser les CronJobs est de les traiter comme des charges de travail de production : observer, tester en isolation, appliquer le moindre privilège, les limites de ressources et surveiller en continu. Lorsqu'une défaillance survient, suivez un chemin de récupération structuré au lieu de deviner.
Comme prochaine étape, choisissez un CronJob à faible risque de votre environnement, créez un namespace de test, déployez l'exemple hello-cron fourni, puis étendez-le avec votre propre commande. Enregistrez l'état actuel, exécutez les vérifications documentées, comparez les résultats avec les signaux attendus et examinez les dépendances telles que les registres d'images et les secrets. Cette pratique concrète consolidera votre compréhension et vous préparera à des charges de travail planifiées plus complexes.