E-NO
Kubernetes 12 min de lecture

Planification de capacité pour les Kubernetes CronJobs avec exemples pratiques

calendar_today Publié : 2026-08-13
update Dernière mise à jour : 2026-08-13
analytics Efficacité SEO : 97%
Illustration du guide technique pour « Planification de capacité pour les Kubernetes CronJobs avec exemples pratiques ».

Les Kubernetes CronJobs exécutent des conteneurs selon un calendrier. Ils semblent trompeusement simples : on écrit un calendrier, on pointe vers un modèle de Job, et on regarde le tout s'exécuter. En production, cependant, les CronJobs peuvent surcharger les nœuds, s'accumuler lors des redémarrages du contrôleur, ou manquer silencieusement leurs planifications. Ce guide propose une approche pratique, axée sur les opérations, pour la planification de capacité des CronJobs afin qu'ils s'exécutent de manière prévisible à mesure que votre charge de travail augmente.

Ce que vous obtiendrez :

  • Une liste de contrôle d'inventaire des versions et de l'environnement pour planifier selon ce que vous exécutez réellement
  • Un chemin de configuration sécurisé avec des valeurs par défaut protectrices (concurrencyPolicy, délais, historiques)
  • Une méthode de dimensionnement étape par étape avec des exemples construits et des formules simples
  • Une vérification observable et des diagnostics avec résultats attendus
  • Les modes de défaillance et les étapes de récupération, incluant les retours rapides
  • Une liste de contrôle opérationnelle reproductible que vous pouvez adopter dès aujourd'hui

Cet article se concentre sur les leviers opérationnels réels qui comptent : CPU, mémoire, concurrence, chevauchement de planification et marges de sécurité.

Inventaire des versions et de l'environnement

Avant de planifier la capacité, faites l'inventaire de votre état actuel. De petites différences dans les versions et la topologie changent la façon dont les CronJobs se comportent.

Prérequis :

  • Accès pour exécuter kubectl contre le cluster cible
  • Permissions pour créer des CronJobs, des Jobs, et voir les Pods et les Events
  • metrics-server installé pour kubectl top (optionnel mais recommandé)

Vérifiez les versions et les objets API :

kubectl version --short
kubectl api-resources | grep -i cronjob
kubectl get nodes -o wide

Résultats attendus :

  • kubectl version affiche les versions client et serveur ; notez la version serveur pour les fonctionnalités CronJob
  • api-resources liste les cronjobs dans batch/v1
  • La liste des nœuds révèle les types d'instances, le CPU/mémoire allouable, et les zones pour les considérations d'ordonnancement

Notes sur la topologie et l'environnement :

  • Les CronJobs exécutent des Jobs, qui créent des Pods. Les demandes de ressources des Pods déterminent la faisabilité de l'ordonnancement et le risque d'expulsion.
  • Les CronJobs sont réconciliés par le kube-controller-manager. Si ce contrôleur est perturbé, une vague de planifications manquées peut se produire lorsqu'il revient. Les garde-fous plus loin dans ce guide réduisent ce risque.
  • Comportement du fuseau horaire : de nombreux clusters utilisent UTC par défaut. Si votre cluster supporte spec.timeZone pour les CronJobs, privilégiez UTC explicite ou votre fuseau choisi pour éviter les surprises entre régions.

Chemin de configuration sécurisé

La façon la plus sûre d'opérer les CronJobs est de borner combien s'exécutent, combien de temps ils peuvent durer, et combien de résultats sont conservés. Partez de ces valeurs par défaut et ajustez selon les besoins.

Exemple construit : un CronJob horaire simple qui s'exécute pendant ~3 minutes, utilisant 200m CPU et 256Mi mémoire. Remplacez l'image et la commande par votre charge de travail.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: rapport-horaire
  namespace: batch
spec:
  schedule: "0 * * * *" # début de chaque heure
  concurrencyPolicy: Forbid # jamais de chevauchement pour ce job
  successfulJobsHistoryLimit: 2 # garde les 2 derniers succès
  failedJobsHistoryLimit: 2 # garde les 2 derniers échecs
  startingDeadlineSeconds: 300 # si manqué, permet rattrapage dans 5 min
  suspend: false
  jobTemplate:
    spec:
      backoffLimit: 1 # échoue vite pour éviter tempête de retentatives
      activeDeadlineSeconds: 600 # force l'arrêt après 10 min
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: job
            image: ghcr.io/example/rapport:1.2.3
            args: ["--range", "last-hour"]
            resources:
              requests:
                cpu: "200m"
                memory: "256Mi"
              limits:
                cpu: "500m"
                memory: "512Mi"

Pourquoi ces choix :

  • concurrencyPolicy=Forbid garantit l'absence de chevauchement pour la même instance de CronJob ; la capacité est plus simple et plus sûre
  • startingDeadlineSeconds borne les tempêtes de rattrapage après les pannes
  • activeDeadlineSeconds empêche les Pods bloqués de consommer des ressources indéfiniment
  • Des limites d'historique basses gardent le magasin d'objets propre et accélèrent les opérations de liste du contrôleur
  • Les demandes de ressources reflètent l'estimation de base ; les limites fournissent un plafond de sécurité. Si votre charge de travail est liée au CPU et peut bénéficier de pics, définissez les limites modérément plus hautes que les demandes.

Estimation pratique de la capacité

La planification de capacité pour les CronJobs se réduit à quatre questions :

  1. Combien de CPU et de mémoire nécessite une exécution ?
  2. Combien peuvent s'exécuter en même temps (par conception ou par accident) ?
  3. Combien de marge le cluster a-t-il quand le job s'exécute ?
  4. Quelle marge de sécurité faut-il pour la croissance et la variance ?

Une feuille de dimensionnement simple (valeurs d'exemple construites montrées) :

FacteurSymboleExempleNotes
Durée moyenne d'exécution (min)T_run3Depuis la préproduction ou les N dernières exécutions
Durée P95 d'exécution (min)T_p956Inclut les jours de données lentes
Intervalle de planification (min)T_int60Ex: horaire
Variance de démarrage (min)T_jit1Décalage d'horloge, gigue du contrôleur
Demande CPU du Pod (cœurs)R_cpu0.2Base pour l'ordonnancement
Demande mémoire du Pod (Gi)R_mem0.25Base pour l'ordonnancement
Politique de concurrenceC_polForbidForbid, Allow, ou Replace
Parallélisme attendu (pods)P1Pour les jobs qui fragmentent le travail

Calcul du risque de chevauchement :

  • Si C_pol=Forbid : le chevauchement ne se produit que si T_p95 + T_jit > T_int. Dans l'exemple, 6 + 1 = 7 < 60, donc pas de chevauchement.
  • Si C_pol=Allow : le pire cas d'exécutions concurrentes par CronJob est ceil((T_p95 + T_jit) / T_int). Dans l'exemple, 1.

Calcul de la demande cluster par exécution :

  • Demande CPU par exécution = P * R_cpu
  • Demande mémoire par exécution = P * R_mem

Calcul de la demande concurrente maximale pour N CronJobs avec le même calendrier :

  • CPU_demand_max = somme sur les jobs (overlap_factor_i P_i R_cpu_i)
  • Choisissez une marge de sécurité S (ex: 30-50%) pour éviter la contention avec les services temps réel : CPU_headroom_needed = CPU_demand_max * (1+S)

Conseils pratiques :

  • Si plusieurs CronJobs démarrent à :00, décalez-les via des décalages de minutes (ex: :00, :05, :10) pour lisser les pics sans changer les SLA.
  • Pour les jobs lourds, fragmentez le travail intentionnellement en utilisant le parallélisme/completions du Job et réduisez les demandes par pod pour qu'ils tiennent sur les nœuds.

Exemple construit A : rapport horaire

  • Un pod, R_cpu=0.2, R_mem=0.25Gi, T_p95=6, T_int=60, C_pol=Forbid -> overlap_factor=1
  • Avec 10 CronJobs similaires démarrant à :00, CPU_demand_max = 10 * 0.2 = 2 cœurs ; avec 50% de marge, prévoyez 3 cœurs libres sur les nœuds qui planifieront ces pods.

Exemple construit B : fragmentation nocturne (parallèle)

  • S'exécute quotidiennement à 02:00, complète 8 fragments en parallèle : P=8, R_cpu=0.25, R_mem=0.3Gi, T_p95=20, C_pol=Forbid
  • Demande d'un seul CronJob au démarrage : CPU=2 cœurs, Mem=2.4Gi. Si trois jobs nocturnes différents chevauchent entre 02:00-02:30, prévoyez 6 cœurs et 7.2Gi plus la sécurité.

Traduction en YAML pour l'exemple B (Job parallèle) :

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nocturne-fragment
  namespace: batch
spec:
  schedule: "0 2 * * *"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 900
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      parallelism: 8 # exécute 8 pods en parallèle
      completions: 8 # tous les 8 doivent réussir
      backoffLimit: 0
      activeDeadlineSeconds: 3600
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: fragment
            image: ghcr.io/example/indexeur:3.4.5
            args: ["--shard-count", "8", "--shard-id-from-env"]
            env:
            - name: SHARD_ID
              valueFrom:
                fieldRef:
                  fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
            resources:
              requests:
                cpu: "250m"
                memory: "300Mi"
              limits:
                cpu: "500m"
                memory: "600Mi"

Notes :

  • Ce qui précède utilise completions/parallelism pour fragmenter. Assurez-vous que votre application respecte l'index de fragment. Pour simplifier, cet exemple référence l'index de completion du Job via fieldRef ; adaptez à votre charge de travail.

Signaux et limites d'échelle

Définissez les seuils avant d'en avoir besoin. Ces signaux indiquent qu'il est temps de mettre à l'échelle les nœuds, d'étaler les calendriers, ou de resserrer les garde-fous.

SignalSignificationAction
CronJob crée en retard ou manque entièrementContrôleur ou cluster surchargéAugmentez startingDeadlineSeconds modérément ; étalez les calendriers ; ajoutez des nœuds
Pod Pending >2 minutesPas assez de CPU/mémoire libre pour ordonnerAugmentez la capacité du cluster ou réduisez les demandes ; étalez les démarrages
Pod OOMKilledDemande mémoire trop basseAugmentez les demandes/limites mémoire ; investiguez le profil mémoire
Durée P95 augmente et chevauche le prochain démarrageRisque de concurrence croissantPassez à concurrencyPolicy=Forbid ou Replace ; ajoutez activeDeadlineSeconds
Tempête de retentatives de Job (beaucoup de backoffs)Dépendances instablesBaissez backoffLimit ; ajoutez disjoncteurs dans l'app ; évitez les effets de meute
CPU nœud >80% pendant la fenêtre batchLe batch concurrence les servicesAjoutez des nœuds ou déplacez la fenêtre batch ; augmentez la marge de sécurité

Définissez des garde-fous dans les manifestes :

  • concurrencyPolicy: Forbid (le plus sûr) ou Replace (si idempotent), évitez Allow sauf si vous voulez le chevauchement
  • startingDeadlineSeconds: limitez les fenêtres de rattrapage pour éviter les inondations après les pannes
  • activeDeadlineSeconds: assurez-vous que les jobs ne s'exécutent pas éternellement sur des dépendances dégradées
  • backoffLimit: petits nombres empêchent les tempêtes de retentatives sous défaillances systémiques
  • limites d'historique: gardez-les basses pour réduire la charge du control-plane

Protections au niveau namespace :

  • ResourceQuota: plafonnez le CPU/mémoire total pour le namespace batch afin de préserver la capacité des services ailleurs
  • LimitRange: imposez des demandes/limites minimales et maximales pour que les jobs ne puissent pas affamer les nœuds

Exemple LimitRange (construit) :

apiVersion: v1
kind: LimitRange
metadata:
  name: batch-limites
  namespace: batch
spec:
  limits:
  - type: Container
    max:
      cpu: "2"
      memory: "2Gi"
    min:
      cpu: "100m"
      memory: "128Mi"
    default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "200m"
      memory: "256Mi"

Vérification et diagnostics

Après avoir appliqué un CronJob, validez le comportement avec ces vérifications.

Appliquez le manifeste :

kubectl apply -f cronjob.yaml

Confirmez la création et la configuration :

kubectl get cronjob -n batch
kubectl describe cronjob rapport-horaire -n batch

Résultats attendus :

  • get montre le CronJob avec le calendrier prévu et suspend=false
  • describe montre concurrencyPolicy, startingDeadlineSeconds, et limites d'historique ; la section Events devrait avoir les timestamps de prochaine planification

Surveillez les Jobs et Pods après une heure planifiée :

kubectl get jobs -n batch --watch
kubectl get pods -n batch -l job-name=rapport-horaire-<suffixe> -o wide
kubectl logs -n batch job/rapport-horaire-<suffixe>

Résultats attendus :

  • Un Job apparaît par planification (concurrencyPolicy=Forbid) ; les pods passent de Pending à Running à Completed
  • Les logs montrent une complétion normale dans la durée d'exécution attendue

Mesurez les ressources (si metrics-server est installé) :

kubectl top pod -n batch -l job-name=rapport-horaire-<suffixe>

Résultats attendus :

  • Utilisation CPU près ou en dessous de la demande ; les pics peuvent approcher la limite mais ne devraient pas causer d'étranglement à long terme
  • Utilisation mémoire en dessous de la limite avec marge ; utilisation soutenue au-dessus de la demande suggère d'augmenter la demande pour améliorer la certitude d'ordonnancement

Vérifiez le chevauchement et le retard :

kubectl get jobs -n batch --sort-by=.status.startTime | tail -n 5
kubectl describe cronjob rapport-horaire -n batch | grep -iE "Last schedule time|Missed"

Résultats attendus :

  • Exactement un job par heure de planification et pas de lignes d'événement Missed si startingDeadlineSeconds est raisonnable et le contrôleur en santé

Modes de défaillance et récupération

Modes de défaillance courants et comment récupérer en toute sécurité.

  1. Panne du contrôleur cause une tempête de rattrapage
  • Symptôme : Plusieurs Jobs créés immédiatement une fois le contrôleur récupéré
  • Prévention : startingDeadlineSeconds pour limiter jusqu'où le contrôleur rattrape
  • Récupération :
  • Mettez temporairement le CronJob en pause :
    kubectl patch cronjob rapport-horaire -n batch -p '{"spec":{"suspend":true}}'
  • Confirmez qu'aucun nouveau job n'est créé :
    kubectl get cronjob rapport-horaire -n batch -o jsonpath='{.spec.suspend}{"\n"}'
  • Supprimez les jobs en file d'attente non nécessaires (attention s'ils ont fait un travail partiel) :
    kubectl delete job -n batch -l cronjob-name=rapport-horaire --field-selector=status.successful==0
  • Reprenez une fois la charge normalisée :
    kubectl patch cronjob rapport-horaire -n batch -p '{"spec":{"suspend":false}}'
  1. Pods OOMKilled ou étranglés
  • Symptôme : Les pods échouent avec OOMKilled ou s'exécutent beaucoup plus lentement que prévu
  • Prévention : Mesurez et augmentez demandes/limites ; gardez 20-50% de marge mémoire pour le batch
  • Récupération : Mettez à jour les ressources et réappliquez ; pour les exécutions critiques, relancez ad-hoc avec plus de ressources pendant que vous ajustez le manifeste
  1. Chevauchement dû à la croissance de la durée
  • Symptôme : Une nouvelle exécution démarre pendant que la précédente s'exécute encore
  • Prévention : concurrencyPolicy=Forbid plus activeDeadlineSeconds ; étalez les calendriers
  • Récupération : Passez immédiatement à Forbid ou Replace et mettez en pause pour vider l'arriéré si nécessaire
  1. Pannes de dépendances (bases de données, APIs)
  • Symptôme : Beaucoup de retentatives ; longues durées ; erreurs dans les logs
  • Prévention : Petit backoffLimit ; court activeDeadlineSeconds ; timeouts au niveau application
  • Récupération : Mettez le CronJob en pause, corrigez la dépendance, puis reprenez. Envisagez une relance manuelle de la fenêtre manquée avec des arguments évitant le double-traitement.
  1. Surprises de fuseau horaire et dérive d'horloge
  • Symptôme : Les jobs s'exécutent à des heures locales inattendues après changements d'heure d'été ou déplacement de cluster
  • Prévention : Définissez spec.timeZone explicitement si supporté, ou standardisez sur UTC et convertissez dans le code
  • Récupération : Mettez en pause, ajustez le calendrier ou le fuseau, vérifiez la prochaine heure de planification avec describe, puis reprenez

Conseils de retour arrière :

  • Gardez un manifeste précédent fonctionnel (git ou fichier). Pour revenir en arrière :
  kubectl apply -f cronjob-prec.yaml
  • Si un mauvais changement cause une perturbation active, mettez d'abord en pause, puis revenez en arrière, puis reprenez.

Vérification après récupération :

  • Assurez-vous qu'aucun Job inattendu ne reste Running :
  kubectl get jobs -n batch | grep -v "1/1" | grep -v COMPLETED
  • Confirmez l'heure de prochaine planification et que suspend=false avant de quitter la fenêtre de changement.

Liste de contrôle opérationnelle

Utilisez cette liste courte pour chaque CronJob lors de la création et aux revues régulières.

Création (une fois) :

  • [ ] Définissez les demandes et limites CPU/mémoire basées sur une exécution en préproduction
  • [ ] Choisissez concurrencyPolicy (Forbid pour la sécurité sauf si vous avez besoin de chevauchement)
  • [ ] Définissez startingDeadlineSeconds pour borner le rattrapage (5-15 minutes pour horaire ; plus long pour quotidien)
  • [ ] Définissez activeDeadlineSeconds pour tuer les exécutions bloquées
  • [ ] Définissez backoffLimit petit (0-2) pour éviter les tempêtes
  • [ ] Définissez des limites d'historique basses
  • [ ] Si vous utilisez parallelism/completions, validez la conscience des fragments dans l'app
  • [ ] Étalez les calendriers pour éviter les pics synchronisés
  • [ ] Placez les CronJobs dans un namespace contraint avec ResourceQuota/LimitRange

Revue hebdomadaire ou par sprint :

  • [ ] Inspectez la durée P95 et comparez à l'intervalle de planification ; assurez-vous qu'il n'y a pas de risque de chevauchement
  • [ ] Vérifiez le temps Pending ; si >2 minutes régulièrement, ajustez les demandes ou la capacité
  • [ ] Revoyez les événements OOM ou étranglement ; ajustez les ressources en conséquence
  • [ ] Confirmez l'absence d'événements Missed schedule
  • [ ] Validez les prochaines heures de planification après changements de fuseau horaire ou d'heure d'été
  • [ ] Reconfirmez les marges de sécurité si de nouveaux CronJobs ont été ajoutés à des heures similaires

Actions rapides en réponse aux incidents :

  • [ ] Mettez en pause les CronJobs problématiques
  • [ ] Supprimez les Jobs en file d'attente non nécessaires après évaluation d'impact
  • [ ] Revenez au dernier manifeste connu bon
  • [ ] Reprenez avec des garde-fous plus serrés

Conclusion

Les CronJobs sont simples à planifier mais faciles à surcharger sans plan. Traitez chaque CronJob comme une unité prévisible : mesurez une seule exécution, décidez si le chevauchement est permis, bornez le comportement de rattrapage, et imposez des limites de durée et de retentative. Utilisez des mathématiques simples pour prévoir les pics, puis gardez une marge de sécurité saine pour que vos jobs batch ne concurrencent pas les services interactifs.

Le chemin pratique est itératif : pilotez un CronJob avec des garde-fous explicites, vérifiez avec kubectl et les métriques, puis généralisez le motif dans votre flotte. Avec les manifestes et vérifications de ce guide, vous pouvez garder les CronJobs prévisibles, auditable, et faciles à mettre à l'échelle à mesure que vos charges de travail et calendriers grandissent. La planification de capacité devient une revue de routine plutôt qu'un exercice d'urgence, et votre cluster reste sain même quand des dizaines de jobs planifiés s'exécutent simultanément.

Recherches connexes

Score de qualité de l’article

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