Les CronJobs sont le cœur battant de nombreux environnements Kubernetes : rapports quotidiens, maintenance de bases de données, nettoyage de cache, pipelines ETL, et plus encore. Lors d'un déplacement de cluster, d'une reconstruction de namespace ou d'une défaillance, vous avez besoin d'un moyen sûr et reproductible de sauvegarder et restaurer ces planifications et leurs dépendances d'exécution. Ce guide pratique propose :
- Une sauvegarde minimale et ciblée utilisable dès aujourd'hui
- Une restauration réversible évitant les exécutions en double
- Une vérification observable, les modes de défaillance courants et correctifs rapides
- Les étapes de reprise après sinistre et de retour arrière
- Une liste de contrôle pratique adoptable telle quelle
Les exemples sont conçus pour la clarté et n'utilisent que les outils Kubernetes de base (kubectl et manifests simples). Lorsque des volumes de données sont impliqués, nous montrons comment copier le contenu en toute sécurité.
Inventaire des versions et de l'environnement
Avant de toucher à la production, capturez et figez les détails de l'environnement. Cela réduit la dérive et rend votre sauvegarde et restauration reproductibles et auditable. Enregistrez la version exacte de Kubernetes car le comportement des CronJobs a changé entre v1.27 et v1.28 concernant la gestion des fuseaux horaires.
Commandes d'inventaire rapides
- Enregistrer les versions client et serveur :
kubectl version --short
- Enregistrer les nœuds et leur OS/arch (utile pour déboguer les images) :
kubectl get nodes -o wide
- Confirmer les namespaces dans le périmètre et le plan d'étiquetage :
kubectl get ns
kubectl get cronjob -A --show-labels
- Vérifier que le groupe d'API CronJob est disponible :
kubectl api-resources | grep -i cronjob
Ce qu'il faut enregistrer (exemples construits)
| Élément | À enregistrer | Exemple |
|---|---|---|
| Version Kubernetes | Client et serveur semver | v1.29.3 (client), v1.28.6 (serveur) |
| Namespaces concernés | Namespaces où vivent les CronJobs | jobs, analytics |
| Labels pour la sélection | Labels définissant le périmètre de sauvegarde | app=reporting, backup=enabled |
| Stockage et PVC | Noms des PVC et chemins de montage utilisés par les jobs | report-pvc sur /data |
| Identités RBAC | ServiceAccounts et liaisons | SA cron-runner, RoleBinding cron-runner-rb |
Astuce : Stockez cet inventaire avec vos artefacts de sauvegarde.
Chemin de configuration sûr
Le chemin le plus sûr commence étroitement, est facile à inspecter localement et évite les effets de bord. La séquence ci-dessous vous donne des garde-fous et des commandes concrètes pour agir d'abord sur un seul namespace et une seule charge de travail étiquetée.
0) Un CronJob étiqueté que vous pouvez cibler
Voici un manifest CronJob construit pour tester le processus de bout en bout. Il inclut des labels pour le périmètre, un ServiceAccount, des limites d'historique et un montage PVC pour une sauvegarde de données optionnelle.
apiVersion: batch/v1
kind: CronJob
metadata:
name: report-daily
namespace: jobs
labels:
app: reporting
backup: enabled
spec:
schedule: "0 2 * * *" # 02:00 quotidien (utilisez UTC pour éviter les surprises)
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
suspend: false
jobTemplate:
spec:
backoffLimit: 1
template:
spec:
serviceAccountName: cron-runner
restartPolicy: Never
containers:
- name: report
image: ghcr.io/example/report:1.2.3
args: ["--generate"](The user wants me to translate the English article to French. I need to continue translating the rest of the markdown content. Let me continue from where I left off.)
envFrom:
- secretRef:
name: report-secrets
volumeMounts:
- name: report-data
mountPath: /data
volumes:
- name: report-data
persistentVolumeClaim:
claimName: report-pvc
Appliquez-le d'abord sur un namespace non critique :
kubectl apply -f report-daily.cronjob.yaml
1) Sauvegarder les spécifications des CronJobs (YAML)
Sauvegardez seulement ce dont vous avez besoin, en utilisant les labels pour délimiter le périmètre. Remplacez le namespace et les labels ci-dessous par les vôtres.
# Répertoire de sauvegarde
mkdir -p backups/jobs
# CronJobs (délimités par label)
kubectl get cronjob -n jobs -l backup=enabled -o yaml > backups/jobs/cronjobs.yaml
# Optionnel : ServiceAccounts, Roles, RoleBindings utilisés par les CronJobs
kubectl get sa,role,rolebinding -n jobs -l app=reporting -o yaml > backups/jobs/rbac.yaml
# ConfigMaps et Secrets référencés par les CronJobs
kubectl get configmap,secret -n jobs -l app=reporting -o yaml > backups/jobs/config-secrets.yaml
Notes :
- Les Secrets sont encodés en base64 dans le YAML. Traitez les fichiers de sauvegarde de manière sécurisée (chiffrement au repos et accès restreint).
- Vous avez rarement besoin de sauvegarder les Jobs créés par les CronJobs ; ils sont éphémères. Cependant, il peut être utile de conserver un YAML de Job récent pour comparaison forensique lors des tests.
2) Sauvegarder le contenu des PVC quand pertinent (optionnel)
Si votre CronJob écrit sur un PVC, capturez une archive à un instant T. Ce qui suit crée un pod éphémère qui monte le PVC et diffuse un tarball vers votre poste de travail. Adaptez claimName, namespace et chemins pour votre cas.
# pvc-reader.yaml (exemple construit)
apiVersion: v1
kind: Pod
metadata:
name: pvc-reader
namespace: jobs
labels:
app: reporting
spec:
restartPolicy: Never
containers:
- name: reader
image: busybox:1.36
command: ["sleep", "3600"]
volumeMounts:
- name: report-data
mountPath: /data
volumes:
- name: report-data
persistentVolumeClaim:
claimName: report-pvc
Exécutez la sauvegarde :
kubectl apply -f pvc-reader.yaml
kubectl wait --for=condition=Ready pod/pvc-reader -n jobs --timeout=60s
kubectl exec -n jobs pvc-reader -- tar -C /data -cf - . > backups/jobs/report-pvc-$(date +%F).tar
kubectl delete pod pvc-reader -n jobs --wait=true
3) Séquence de restauration avec garde-fous
Lors de la restauration, évitez les exécutions planifiées en double en suspendant temporairement les CronJobs pendant le processus.
# Créer ou s'assurer que le namespace cible existe
kubectl create namespace jobs 2>/dev/null || true
# 3.1 Dry-run pour valider les manifests contre l'API du cluster
kubectl apply --server-side --dry-run=server -f backups/jobs/rbac.yaml
kubectl apply --server-side --dry-run=server -f backups/jobs/config-secrets.yaml
kubectl apply --server-side --dry-run=server -f backups/jobs/cronjobs.yaml
# 3.2 Appliquer RBAC et configuration d'abord
kubectl apply -f backups/jobs/rbac.yaml
kubectl apply -f backups/jobs/config-secrets.yaml
# 3.3 Appliquer les CronJobs, puis les suspendre immédiatement
kubectl apply -f backups/jobs/cronjobs.yaml
kubectl patch cronjob -n jobs -l backup=enabled -p '{"spec":{"suspend":true}}'
Si vous avez sauvegardé des données PVC, restaurez-les avant de reprendre les planifications :
# pvc-writer.yaml (exemple construit)
apiVersion: v1
kind: Pod
metadata:
name: pvc-writer
namespace: jobs
spec:
restartPolicy: Never
containers:
- name: writer
image: busybox:1.36
command: ["sleep", "3600"]
volumeMounts:
- name: report-data
mountPath: /data
volumes:
- name: report-data
persistentVolumeClaim:
claimName: report-pvc
kubectl apply -f pvc-writer.yaml
kubectl wait --for=condition=Ready pod/pvc-writer -n jobs --timeout=60s
cat backups/jobs/report-pvc-*.tar | kubectl exec -i -n jobs pvc-writer -- tar -C /data -xpf -
kubectl delete pod pvc-writer -n jobs --wait=true
Ne reprenez les planifications qu'après que les données sont en place (voir la section Vérification pour valider d'abord).
Vérification et diagnostics
La vérification doit être explicite et observable. Le but est de prouver que chaque CronJob peut s'exécuter une fois à la demande et que l'exécution planifiée fonctionnera une fois reprise.
1) Vérifier les objets et leur état
# Confirmer que les CronJobs existent et sont suspendus
kubectl get cronjob -n jobs -l backup=enabled -o wide
# Inspecter un CronJob en détail
kubectl describe cronjob -n jobs report-daily
Résultats attendus :
- CronJobs présents dans le bon namespace
- concurrencyPolicy, limites d'historique et serviceAccountName correspondent aux attentes
- suspend est true (temporairement)
2) Exécuter un Job ad-hoc depuis le template du CronJob
Cela ne modifie pas la planification du CronJob mais prouve que le template peut s'exécuter.
# Créer un job ponctuel basé sur le template du CronJob
kubectl create job -n jobs run-once-$(date +%s) --from=cronjob/report-daily
# Observer l'état et les logs
kubectl get jobs -n jobs -o wide
JOB=$(kubectl get jobs -n jobs -o jsonpath='{.items[0].metadata.name}')
POD=$(kubectl get pod -n jobs -l job-name=$JOB -o jsonpath='{.items[0].metadata.name}')
kubectl logs -n jobs $POD -f
Critères de succès :
- Le Job se termine (statut Succeeded)
- Les logs montrent la sortie attendue de votre tâche
- Si un PVC est utilisé, les fichiers de sortie apparaissent dans le chemin monté
3) Inspecter les événements pour les problèmes de planification
kubectl get events -n jobs --sort-by=.lastTimestamp | tail -n 20
Recherchez les messages sur les planifications manquées, les backoffs ou les erreurs de permission.
4) Reprendre les planifications une fois validées
Ne reprenez qu'après que l'exécution ad-hoc a réussi.
kubectl patch cronjob/report-daily -n jobs -p '{"spec":{"suspend":false}}'
# Ou reprendre tous les CronJobs étiquetés
kubectl patch cronjob -n jobs -l backup=enabled -p '{"spec":{"suspend":false}}'
Confirmez que la prochaine heure planifiée est dans le futur et que le contrôleur rapporte Active=0 au repos.
Modes de défaillance et récupération
Les problèmes lors de la restauration tombent généralement dans quelques catégories. Identifiez le symptôme, suivez le correctif rapide, et re-vérifiez.
| Symptôme | Cause probable | Correctif rapide |
|---|---|---|
| Jobs échouent avec erreurs ImagePull | Tag d'image absent du registre cible | Fixer sur un tag ou digest connu bon ; mettre à jour l'image et réappliquer |
| CrashLoopBackOff ou erreurs de permission | Secrets ou ConfigMaps manquants/incorrects | Réappliquer config-secrets.yaml ; confirmer clés et noms correspondent au spec du pod |
| RBAC forbidden lors d'accès API | ServiceAccount ou RoleBinding manquant | Réappliquer rbac.yaml ; vérifier serviceAccountName sur template CronJob |
| Exécutions en double après restauration | Planifications reprises avant données ou vérifications d'idempotence | Suspendre, nettoyer les Jobs en double, restaurer données, puis reprendre |
| Jobs ne s'exécutent jamais | CronJobs restés suspendus | Patcher suspend=false et vérifier la prochaine planification |
| PVC vide après restauration | Restauration de données ignorée ou chemin incorrect | Réexécuter l'extraction tar vers le bon mountPath ; vérifier avec kubectl exec ls |
| Trop de Jobs historiques | Limites d'historique trop hautes | Définir successfulJobsHistoryLimit et failedJobsHistoryLimit appropriément |
Garde-fous supplémentaires :
- Utilisez UTC pour les expressions de planification afin d'éviter les surprises entre clusters.
- Définissez startingDeadlineSeconds si vous voulez exécuter les jobs manqués à la récupération du contrôleur ; mettez une valeur sensée ou omettez si non désiré.
- Préférez concurrencyPolicy=Forbid pour les tâches sensibles à l'idempotence.
Liste de contrôle opérationnelle
Utilisez cette liste concise comme runbook pour chaque namespace.
Inventaire
- [ ] kubectl version --short sauvegardé
- [ ] Namespaces, labels, PVCs enregistrés
- [ ] ServiceAccounts et Roles identifiés
Sauvegarde (commandes construites)
- [ ] kubectl get cronjob -n <ns> -l backup=enabled -o yaml > cronjobs.yaml
- [ ] kubectl get sa,role,rolebinding -n <ns> -l <labels> -o yaml > rbac.yaml
- [ ] kubectl get configmap,secret -n <ns> -l <labels> -o yaml > config-secrets.yaml
- [ ] Si PVC utilisé : exécuter pvc-reader, diffuser tar vers backups/
- [ ] Stocker les artefacts de manière sécurisée (chiffrer, accès restreint)
Restauration
- [ ] kubectl create namespace <ns> (si nécessaire)
- [ ] kubectl apply --server-side --dry-run=server -f rbac.yaml
- [ ] kubectl apply --server-side --dry-run=server -f config-secrets.yaml
- [ ] kubectl apply --server-side --dry-run=server -f cronjobs.yaml
- [ ] kubectl apply -f rbac.yaml, config-secrets.yaml, cronjobs.yaml
- [ ] kubectl patch cronjob -n <ns> -l backup=enabled -p '{"spec":{"suspend":true}}'
- [ ] Si PVC utilisé : exécuter pvc-writer et extraire tar dans /data
Validation
- [ ] kubectl get/describe cronjob montrent les paramètres attendus
- [ ] Exécuter : kubectl create job --from=cronjob/<nom>
- [ ] Vérifier logs et artefacts ; inspecter événements
Reprise
- [ ] kubectl patch cronjob/<nom> -p '{"spec":{"suspend":false}}'
- [ ] Confirmer prochaine planification, aucun Job Active inattendu
Retour arrière / Récupération
- [ ] En cas de problème : suspendre immédiatement
- [ ] Réappliquer le cronjobs.yaml précédent
- [ ] Supprimer Jobs non voulus : kubectl delete job <nom>
- [ ] Ré-restaurer Secrets/ConfigMaps ou données PVC si nécessaire
Conclusion
Vous disposez maintenant d'un chemin pratique et testé pour sauvegarder et restaurer les CronJobs Kubernetes :
- Commencez petit : un namespace, un CronJob étiqueté, et prouvez le flux de bout en bout.
- Sauvegardez le bon périmètre : specs des CronJobs, RBAC, configuration, et contenu PVC quand applicable.
- Restaurez avec des garde-fous : appliquez les configs d'abord, suspendez les planifications, validez avec une exécution ad-hoc, puis reprenez.
- Anticipez et corrigez rapidement les modes de défaillance courants, et gardez un chemin de retour arrière court prêt.
Améliorez ceci en automatisant les étapes pour chaque namespace, en standardisant les labels (par exemple backup=enabled), et en planifiant des restaurations de test périodiques. La combinaison de pilotes étroits, de validation explicite et de changements réversibles réduira le retravail et rendra les opérations CronJob prévisibles même lors d'incidents.
Annexe : Référence rapide du périmètre de sauvegarde
| Ressource | Pourquoi la sauvegarder | Exemple de commande (construit) |
|---|---|---|
| CronJobs | Définit la planification et le template de job | kubectl get cronjob -n jobs -l backup=enabled -o yaml > cronjobs.yaml |
| RBAC (SA/Role/RoleBinding) | Accorde les permissions d'exécution | kubectl get sa,role,rolebinding -n jobs -l app=reporting -o yaml > rbac.yaml |
| ConfigMaps/Secrets | Configuration et identifiants d'exécution | kubectl get configmap,secret -n jobs -l app=reporting -o yaml > config-secrets.yaml |
| Données PVC (optionnel) | Entrées/sorties nécessaires aux jobs | kubectl exec pvc-reader -- tar -C /data -cf - . > report-pvc.tar |