Aller au contenu
Contactez-nous
  1. Accueil
  2. /
  3. Blog
  4. /
  5. Éteindre les environnements Kubernetes non-prod la nuit

Kubernetes
DevOps
Entreprise

Éteindre les environnements Kubernetes non-prod la nuit

5 août 2026

11 min de lecture

Sommaire
Visibilité et scheduling, deux chantiers distincts
Le calcul de gain, fait honnêtement
Le maillon que tout le monde oublie
Trois façons de couper, par ordre de sérieux
Ce qu'on n'éteint pas
Le vrai motif de désactivation : le redémarrage lent
Ce qu'on ferait à votre place
Sources

Le dashboard est en place, les namespaces sont taggés, chaque équipe reçoit son rapport hebdomadaire. On sait précisément que le cluster de recette coûte 2 400 euros par mois. On le sait depuis onze mois. Et il coûte toujours 2 400 euros par mois.

C'est le décrochage le plus banal des démarches FinOps : la visibilité est un projet fini, l'action est un projet permanent. Mesurer un gaspillage ne le supprime pas. Le rapport State of FinOps 2025 de la FinOps Foundation, construit sur un panel d'entreprises pesant plus de 69 milliards de dollars de dépense cloud, place l'optimisation des workloads et la réduction du gaspillage en priorité numéro un pour 50 % des praticiens, loin devant l'allocation des coûts. Tout le monde a compris qu'il fallait agir. Peu de monde a câblé l'automatisme qui agit.

Un environnement de dev, de staging ou une review app n'a aucune raison de tourner à 3 heures du matin un dimanche. C'est le gisement le plus simple à attaquer, et le plus souvent laissé de côté parce qu'il touche au confort des développeurs.

Visibilité et scheduling, deux chantiers distincts

Un outil comme Kubecost répond à la question « combien ». Il ne répond pas à « qu'est-ce qu'on coupe, quand, et qui le rallume ». Si vous n'avez pas encore la première brique, installer Kubecost pour la surveillance des coûts Kubernetes reste le point de départ, et la stratégie FinOps globale avec tagging et rightsizing donne le cadre. Mais aucune des deux ne touche une seule réplique.

Le scheduling actif, c'est un contrôleur qui écrit dans le cluster : il passe des Deployments à zéro réplique le soir, les remonte le matin, et coordonne ça avec les HorizontalPodAutoscaler qui vont vouloir faire l'inverse. C'est une mécanique d'exploitation, pas un tableau de bord.

Le calcul de gain, fait honnêtement

Le chiffre qu'on lit partout, c'est 70 % d'économies. Il vient d'un calcul horaire trivial : une semaine fait 168 heures, une fenêtre lundi-vendredi de 8 h à 19 h en fait 55, soit 33 % de temps allumé. Reste 67 % éteint.

Ce chiffre est faux dès qu'on regarde une facture réelle, pour deux raisons.

D'abord, l'extinction ne touche que la partie élastique de la dépense. Les volumes persistants continuent d'être facturés, l'adresse IP publique du load balancer aussi, le control plane managé aussi, le registre d'images aussi, et les bases managées ne s'arrêtent pas parce qu'un Deployment est passé à zéro. Sur les clusters non-prod qu'on regarde, le compute représente typiquement 55 à 70 % de la facture du cluster. Le reste est un plancher incompressible.

Ensuite, il faut des jours fériés, des astreintes, des équipes distribuées et des démos client. En pratique la fenêtre allumée réelle ressemble plus à 45 % qu'à 33 %.

Le modèle honnête, en posant un cluster non-prod de 12 nœuds à 8 vCPU et 32 Go, avec un compute à 60 % de la facture et une fenêtre allumée à 45 % :

Gain = part_compute x (1 - fenetre_allumee)
     = 0,60 x 0,55
     = 33 % de la facture du cluster non-prod

Un tiers, pas 70 %. Sur un cluster non-prod à 2 400 euros par mois, ça fait environ 800 euros mensuels, 9 600 euros par an, pour un chantier de deux à trois jours d'ops. Le ROI reste excellent. Il n'est simplement pas celui qu'on vous vend.

La règle qu'on applique : mesurez votre propre ratio compute sur facture totale avant d'annoncer un chiffre à la direction financière. Une promesse de 70 % qui atterrit à 30 % tue la deuxième initiative FinOps du même service.

Le maillon que tout le monde oublie

Passer des pods à zéro ne fait économiser strictement rien si les nœuds restent allumés. C'est écrit noir sur blanc dans la documentation de py-kube-downscaler : il faut combiner le downscaler avec un cluster autoscaler élastique pour réellement réduire la facture cloud. Sans ça, vous avez juste un cluster vide qui tourne.

Et le cluster autoscaler a ses propres délais. Par défaut, un nœud doit être considéré comme inutile pendant 10 minutes (--scale-down-unneeded-time) avant d'être candidat à la suppression, avec un seuil d'utilisation à 0,5 : la somme des requests CPU et mémoire des pods doit passer sous 50 % de l'allouable du nœud.

Surtout, la FAQ officielle du cluster autoscaler liste les cas qui bloquent la suppression d'un nœud, et ce sont exactement ceux qu'on retrouve en non-prod :

  • Les pods kube-system sans PodDisruptionBudget, ou avec un PDB trop restrictif.
  • Les pods utilisant du stockage local (hostPath, emptyDir) sans l'annotation cluster-autoscaler.kubernetes.io/safe-to-evict: "true".
  • Les pods non gérés par un contrôleur, ces pods orphelins qu'un dev a créés à la main il y a huit mois.
  • Tout ce qui porte cluster-autoscaler.kubernetes.io/safe-to-evict: "false".

Le piège classique : on déploie le downscaler, on regarde le lendemain, tous les Deployments sont à zéro, tous les nœuds sont toujours là parce qu'un DaemonSet d'agent de sécurité avec emptyDir s'accroche à chacun d'eux. Zéro euro économisé, et une semaine perdue à comprendre pourquoi.

Sur des clusters où le provisioning de nœuds doit être agressif, Karpenter pour l'autoscaling de nœuds Kubernetes consolide plus vite que le cluster autoscaler classique et rend la mécanique nettement plus rentable.

Trois façons de couper, par ordre de sérieux

Le CronJob maison. Deux CronJob, un kubectl scale --replicas=0 le soir, un --replicas=N le matin, un ServiceAccount avec les droits qui vont bien. Ça se code en vingt minutes, et ça casse au premier Deployment ajouté par une équipe qui ne connaît pas le script, ou au premier HPA qui remonte les répliques dans la minute. À réserver aux clusters à périmètre figé et documenté.

py-kube-downscaler, le successeur maintenu du kube-downscaler d'origine. Il couvre les Deployments, StatefulSets, HorizontalPodAutoscalers, DaemonSets, CronJobs, Jobs, PodDisruptionBudgets, Argo Rollouts et les ScaledObject KEDA. Le pilotage se fait par annotations, au niveau du namespace ou de la ressource :

apiVersion: v1
kind: Namespace
metadata:
  name: staging
  annotations:
    downscaler/uptime: 'Mon-Fri 08:00-19:00 Europe/Paris'
    downscaler/downtime-replicas: '0'

Le point à connaître avant de déployer : minReplicas à 0 est interdit sur un HorizontalPodAutoscaler. Si vous annotez à la fois le Deployment et laissez un HPA actif dessus, vous créez une condition de concurrence où l'HPA remonte les répliques en boucle contre le downscaler. La documentation du projet est explicite là-dessus. Deux choix : annoter l'HPA avec un downtime-replicas d'au moins 1, ou supprimer l'HPA en non-prod, ce qui est souvent la bonne réponse de toute façon.

KEDA, si vous l'avez déjà pour de l'event-driven. Le scaler cron définit une fenêtre d'activité, et en dehors de toute fenêtre, KEDA ramène la cible à minReplicaCount :

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: api-staging
spec:
  scaleTargetRef:
    name: api
  minReplicaCount: 0
  cooldownPeriod: 300
  triggers:
    - type: cron
      metadata:
        timezone: Europe/Paris
        start: 0 8 * * 1-5
        end: 0 19 * * 1-5
        desiredReplicas: '2'

Le cooldownPeriod par défaut est de 300 secondes : la descente effective a lieu cinq minutes après la fin de la fenêtre, pas à la seconde près. Erreur fréquente : mettre desiredReplicas: 0 dans le trigger. Le trigger décrit la période allumée, c'est minReplicaCount qui décrit la période éteinte.

Notre position : py-kube-downscaler si le besoin est purement calendaire, KEDA si l'outil est déjà en place et que vous voulez un seul mécanisme d'autoscaling. Le CronJob maison, seulement pour une preuve de concept à jeter.

Ce qu'on n'éteint pas

Les bases de données. Un PostgreSQL ou un MySQL de staging qu'on passe à zéro réplique, c'est un arrêt brutal sans checkpoint propre, et un redémarrage qui commence par un replay de WAL. En StatefulSet avec un PVC, l'espace disque reste facturé de toute façon, donc le gain est marginal pendant que le risque de corruption, lui, est réel. On les laisse tourner, quitte à les redimensionner à la baisse en non-prod.

Tout ce qui porte de l'état en mémoire. Un cache applicatif chaud, une file d'attente en mémoire, un worker au milieu d'un batch nocturne. Si un CronJob de purge tourne à 2 h du matin dans le namespace, l'éteindre à 19 h le fait sauter silencieusement, et personne ne s'en aperçoit avant que la table de logs atteigne 400 Go.

Les environnements de démo client. Un commercial qui ouvre une URL à 21 h devant un prospect et qui tombe sur un 503 coûte plus cher que l'année d'économies. Annotation downscaler/exclude: "true", et on n'en parle plus.

Le vrai motif de désactivation : le redémarrage lent

Ce qui tue ces dispositifs, ce n'est jamais la technique. C'est le développeur qui arrive à 8 h 05, lance sa recette, et attend.

Le chemin critique est long : le downscaler remonte les répliques, le scheduler place les pods, le cluster autoscaler constate qu'il manque de la capacité, provisionne des nœuds (deux à quatre minutes selon le fournisseur), le kubelet tire les images (une image applicative de 800 Mo sur un nœud froid, ça n'est pas instantané), les probes de readiness attendent que la JVM ait fini de démarrer. Quinze minutes de trou, c'est courant. Trois fois de suite, et quelqu'un ouvre un ticket pour désactiver le truc.

Ce qui marche, en exploitation :

  • Redémarrer avant les gens. Fenêtre d'allumage à 7 h 15, pas 8 h. Le surcoût est nul comparé au coût politique de l'attente.
  • Garder un nœud chaud. Un seul nœud maintenu allumé avec les images préchargées absorbe le premier réveil. Le gain perdu est de l'ordre de 8 % sur douze nœuds, la friction évitée est totale.
  • Rendre le réveil explicite. Un bouton, une commande, un webhook ChatOps qui remonte le namespace à la demande. Les gens acceptent bien mieux un système qu'ils peuvent contredire.
  • Afficher l'état. Un tableau Grafana qui montre les namespaces endormis transforme « c'est cassé » en « ah oui, c'est éteint ».

Et parce que ces annotations sont de la configuration, elles vivent dans Git, pas dans un kubectl annotate tapé un mardi soir. Argo CD pour piloter les manifestes en GitOps est le bon endroit : la politique d'extinction devient revue, tracée, et réversible.

Ce qu'on ferait à votre place

Commencez par un seul namespace de staging, pendant deux semaines, avec un cluster autoscaler déjà fonctionnel et vérifié. Mesurez la facture avant et après, pas les répliques. Si le nombre de nœuds ne baisse pas, le problème est dans les pods qui bloquent l'éviction, pas dans le scheduling, et aucune configuration supplémentaire du downscaler ne le réglera.

Ensuite seulement, généralisez par annotation de namespace, avec une liste d'exclusions assumée et documentée. Et gardez en tête que le gain réel se situe autour d'un tiers de la facture des clusters concernés, pas des deux tiers. C'est déjà, de loin, le meilleur ratio effort sur économie de tout le catalogue FinOps Kubernetes.

Ce type de chantier tient sur un détail : quelqu'un doit surveiller que le réveil de 7 h 15 a bien eu lieu tous les matins, et intervenir quand ce n'est pas le cas. C'est exactement le genre de mécanique qu'on met en place et qu'on exploite sur les infrastructures qu'on opère depuis le DC Fullsave de Toulouse et le site TDF de Bordeaux. Si votre non-prod tourne 168 heures par semaine pour un usage de 50, on peut câbler le scheduling et en assurer l'exploitation plutôt que vous laisser découvrir les pods qui bloquent l'éviction en cours de route.

Sources

  • Cluster Autoscaler FAQ, projet Kubernetes : valeurs par défaut de --scale-down-unneeded-time et du seuil d'utilisation, et liste exhaustive des conditions qui empêchent la suppression d'un nœud.
  • KEDA, documentation du scaler Cron : paramètres du trigger cron, comportement hors fenêtre et valeur par défaut du cooldownPeriod.
  • py-kube-downscaler, dépôt officiel : ressources supportées, annotations, interdiction de minReplicas à 0 sur un HPA et nécessité d'un cluster autoscaler élastique.
  • The State of FinOps Report 2025, FinOps Foundation : priorités déclarées des praticiens, périmètre du panel et poids de l'optimisation des workloads.
  • Horizontal Pod Autoscaler, documentation Kubernetes : contraintes sur minReplicas et interaction entre l'HPA et une modification externe du nombre de répliques.
Besoin d'aide sur ce sujet ?

Notre équipe d'experts est là pour vous accompagner dans vos projets d'infrastructure et d'infogérance.

Contactez-nous

Articles similaires

Argo Rollouts : canary et blue-green natifs sur Kubernetes
Kubernetes
DevOps

Argo Rollouts : canary et blue-green natifs sur Kubernetes

Le Deployment Kubernetes ne sait faire qu'un rolling update. Argo Rollouts ajoute canary, blue-green et rollback piloté par SLO Prometheus.

17 juil. 2026

Lire plus

Métriques DORA : les 4 indicateurs clés pour mesurer la performance DevOps
DevOps
Entreprise

Métriques DORA : les 4 indicateurs clés pour mesurer la performance DevOps

Découvrez les 4 métriques DORA, les benchmarks Elite à Low, les outils de mesure et les leviers concrets pour améliorer votre delivery.

24 mars 2026

Lire plus

FluxCD : le GitOps natif Kubernetes en 2026
DevOps
Kubernetes

FluxCD : le GitOps natif Kubernetes en 2026

Déployez FluxCD pour du GitOps natif Kubernetes. Architecture, bootstrap, réconciliation automatique et comparaison avec ArgoCD.

28 févr. 2026

Lire plus


SHPV, votre partenaire de confiance en infrastructure et infogérance informatique en France.

SHPV
Contactez-nousNous contacter
Expertise
InfrastructureDatacenterInfogéranceCloudHébergementTransit IP
Légales
Conditions Générales de VenteCPS - Contrat de ServicesCPS - Hébergement CloudCPS - Microsoft 365Accord sous-traitance RGPDTarifs interventions

SHPV © 2026 - Tous droits réservés

Mentions légalesPolitiques de confidentialité
SHPV FRANCE - SAS au capital de 16 000 € - 52 Rue Romain Rolland, 71230 Saint-Vallier - SIRET n°80886287400035 - R.C.S. Chalon-sur-Saône. Par téléphone 09 72 310 818 - Email: support@shpv.fr