Observer et maîtriser les coûts
Pourquoi
Un cluster Kapsule se met à coûter de l'argent et à tomber en panne de la même façon : doucement, sans que personne ne regarde. Les nœuds sont facturés comme des instances, que leurs pods les remplissent ou non. Un répartiteur de charge créé par un Service de type LoadBalancer, oublié après un essai, est facturé tant qu'il existe. Un volume qui survit à son pod reste facturé. Et un nœud qui passe NotReady à 3 heures du matin ne prévient personne, sauf si quelqu'un a écrit une alerte.
Pour Signalements, deux questions reviennent deux semaines après la migration. L'API répond-elle correctement, et si elle ne le fait pas, où est le problème : dans l'application, sur le nœud, dans le plan de contrôle ? Et combien coûte ce cluster, par rapport aux deux instances d'avant, et à quoi tient la différence ? Sans observation, la première question se règle à coups de kubectl logs pendant l'incident. Sans mesure des coûts, la seconde se découvre à la facture.
Cette leçon répond aux deux. Elle s'appuie sur Cockpit, déjà présenté, dont elle ne répète pas les notions (sources de données, jetons, conservation, gestionnaire d'alertes) : elle dit ce que Kapsule y envoie, et ce qu'il faut y ajouter.
Les concepts
Ce que Kapsule envoie de lui-même
D'après la documentation de Scaleway, Kapsule est intégré à Cockpit : les métriques du plan de contrôle sont fournies gratuitement, ainsi que celles des nœuds, des ressources gérées et des applications système du cluster. Le tableau de bord préconfiguré Kubernetes cluster overview montre le plan de contrôle, les nœuds (processeur, mémoire), les ressources gérées et les composants système. Un second, Kubernetes cluster logs, affiche les journaux des composants du plan de contrôle : controller-manager, ccm (le cloud controller manager, voir la leçon 4), kapsule-autoscaler, et d'autres. La documentation précise qu'aucun journal du kube-apiserver n'y est envoyé.
Trois précisions à retenir.
- La conservation par défaut est de 31 jours pour les métriques et 7 jours pour les journaux ; elle se change dans Cockpit.
- Le journal d'audit de l'API (qui a fait quoi) n'est disponible que pour les clusters à plan de contrôle dédié : activé par défaut pour les nouveaux, et à activer dans les réglages d'un cluster plus ancien passé en dédié. Il est visible dans le tableau de bord Kubernetes Cluster Audit Logs.
- La taille d'etcd du plan de contrôle est visible dans Cockpit. Elle est limitée (55 Mo pour un plan de contrôle mutualisé, 200 Mo pour un plan dédié, selon la documentation) : un cluster qui accumule des objets (jobs terminés, événements, ressources personnalisées) s'en rapproche, et la documentation avertit qu'on ne peut pas rétrograder d'un plan dédié vers un plan mutualisé quand la taille dépasse le quota du second.
Ce qui reste à vous : le plan de données
Le plan de données (nœuds, kubelet, containerd, vos pods) tourne dans votre projet. Scaleway le dit sans ambiguïté : les journaux de ces composants sont « vos propres données », et leur envoi vers Cockpit est facturé au volume ingéré. Ce qui n'est pas fourni sans agent :
- les journaux des conteneurs (la sortie standard de l'API, de Traefik, d'Argo CD) ;
- le journal systemd des nœuds (
kubeleten particulier) ; - l'état des objets Kubernetes (« ce pod est en
CrashLoopBackOff», « ce volume est plein ») : ce sont les métriques dekube-state-metricset du kubelet, qu'aucun produit Scaleway n'expose pour vous à notre connaissance ; - les métriques de l'application (celles de
/metricsde Signalements).
L'agent est Grafana Alloy, déjà présenté à propos des instances. Scaleway propose de le déployer par la fonction Easy Deploy de la console (« Alloy to Cockpit ») : le déploiement crée automatiquement une source de données kubernetes-logs et un jeton de Cockpit autorisé à écrire des journaux. Sa configuration par défaut collecte les journaux de l'espace de noms kube-system et tout le journal systemd.
Quatre alertes que l'on regrette de ne pas avoir
Le gestionnaire d'alertes de Cockpit évalue des règles en PromQL (métriques) et LogQL (journaux). Pour un cluster, quatre symptômes valent une alerte, parce qu'ils précèdent la panne visible :
- un nœud
NotReady(le kubelet ne répond plus) ; - des pods en échec durable :
CrashLoopBackOff,ImagePullBackOff,Pendingdepuis longtemps ; - un volume persistant presque plein (la base de formation, un
StatefulSet) ; - un déploiement qui n'a plus le nombre de réplicas voulu.
Une alerte utile porte sur un symptôme et non sur une cause (le cours Concevoir une alerte utile reviendra sur ce principe) : « des pods ne démarrent plus » vaut mieux que « le processeur du nœud 3 dépasse 80 % ».
Les postes de coût d'un cluster
Au 5 octobre 2026, la facturation d'un cluster Kapsule se compose de :
| Poste | Ce qui est facturé | Remarque |
|---|---|---|
| Plan de contrôle | Gratuit en type mutualisé ; payant en type dédié (4, 8 ou 16 Go de mémoire) | La FAQ de Scaleway dit que le plan de contrôle est fourni sans coût supplémentaire pour le type mutualisé ; le dédié est facturé à l'heure, avec un engagement de 30 jours calendaires |
| Nœuds | Au prix de l'instance sous-jacente, à l'heure | Le poste dominant, et le seul qui suit l'autoscaler |
| Répartiteurs de charge | Un par Service LoadBalancer, tant qu'il existe | Voir la leçon 4 |
| Volumes | Block Storage, par volume et par taille, tant que le volume existe | Y compris le disque système des nœuds, dont vous choisissez la taille et le type |
| Adresses IP | Les IP flexibles des répartiteurs et, selon la grille, les adresses publiques des nœuds | Vérifiez la grille de tarifs avant de supposer qu'une adresse est gratuite |
| Passerelle publique | Si des pools sont en isolation complète : une passerelle par réseau privé | Surcoût indiqué par la documentation de Scaleway |
| Journaux et métriques personnalisés | Au volume ingéré dans Cockpit au-delà de la conservation gratuite | Voir le cours Cockpit |
Les montants ne figurent pas ici : ils changent, et la grille de tarifs de Scaleway est la référence. Ce qui compte dans la leçon est de savoir quel poste augmente quand on ajoute une fonction.
Requests, usage et sur-dimensionnement
Les requests d'un conteneur sont la quantité de processeur et de mémoire que le planificateur réserve pour lui sur un nœud (voir Ressources, planification et qualité de service). C'est la somme des requests, pas la consommation, qui décide du nombre de nœuds : l'autoscaler ajoute un nœud quand un pod ne trouve pas de place pour ses requests. Des requests deux fois trop hautes font donc payer, en permanence, deux fois plus de nœuds que nécessaire, et la consommation réelle n'en dit rien.
La mesure se fait avec les utilisations observées (kubectl top, ou les métriques de Cockpit) comparées aux requests. Le coût du sous-dimensionnement est l'inverse : un pod qui dépasse sa limite de mémoire est tué (OOMKilled), un pod qui atteint sa limite de processeur est ralenti.
Autoscaler, types d'instances et remplissage
L'autoscaler de Kapsule (voir la leçon 3) retire un nœud « inutile » quand son utilisation, calculée comme la somme des requests divisée par la capacité allouable, passe sous un seuil pendant un délai (10 minutes par défaut, d'après l'aide de la CLI). Deux conséquences. Si les requests sont gonflées, les nœuds paraissent pleins, et l'autoscaler ne les retire jamais. Et un pod sans PodDisruptionBudget ni stockage local peut être déplacé pour libérer un nœud ; un pod avec stockage local (emptyDir, hostPath) l'empêche par défaut (skip-nodes-with-local-storage, vrai par défaut).
Le type d'instance change le coût par vCPU. Un type à vCPU partagés (par exemple PRO2, utilisé dans la leçon 8) coûte moins, mais ses performances dépendent des voisins ; un type à vCPU dédiés (familles STANDARD3 ou POP2, voir Instances) donne des performances prévisibles. Pour des pools de production sensibles à la latence, la prévisibilité peut l'emporter ; pour un environnement éphémère de test, le type partagé suffit. Mesurez le temps volé avant de payer l'écart. La documentation de Kapsule exclut certains types trop petits (mémoire insuffisante) : DEV1-S, PLAY2-PICO et STARDUST ne sont pas éligibles. Un petit nombre de gros nœuds gaspille moins de capacité réservée aux composants système, mais perdre l'un d'eux touche plus de pods ; un grand nombre de petits nœuds fait l'inverse.
Répartir le coût par équipe
Facturer par application suppose de savoir qui consomme. Kubernetes donne deux leviers : les espaces de noms (un par application et par environnement) et les étiquettes (team, app, env), à poser sur les espaces de noms et sur les pods. Avec les requests des pods agrégées par espace de noms, on obtient une clé de répartition : la part des requests de chaque espace dans le total du cluster. Appliquée au coût des nœuds, elle donne un coût approché. OpenCost (projet de la CNCF) fait ce calcul de façon continue, par espace de noms, étiquette ou contrôleur ; il a besoin des prix de vos ressources pour ne pas se contenter d'estimations génériques, et son réglage fait partie du travail. Nous le citons sans le détailler : le cours FinOps y reviendra.
En pratique
1. Ouvrir ce qui existe déjà
Dans la console, ouvrez Cockpit, Visualize Scaleway data, et le tableau de bord Kubernetes cluster overview ; choisissez le cluster dans la liste déroulante en haut de la page. Regardez, dans cet ordre : l'état du plan de contrôle et la taille d'etcd ; les nœuds (processeur, mémoire, disque) ; l'activité de l'autoscaler. Puis le tableau Kubernetes cluster logs : à la création d'un répartiteur par un Service, la ligne du ccm montre la réconciliation. Rien n'est à installer.
Note
La documentation de Scaleway observe que sur de gros clusters avec beaucoup d'objets et des contrôleurs très actifs (Argo CD, Velero), le serveur d'API peut connaître des pics de processeur et de mémoire, avec des erreurs EOF côté kubectl. Surveillez-le dans le tableau de bord : c'est l'argument qui justifie, le moment venu, un plan de contrôle dédié.
2. Envoyer les journaux des pods
Deux voies. Easy Deploy (« Alloy to Cockpit » dans l'onglet Easy Deploy du cluster) crée tout : l'application Alloy, le secret d'identifiants, la source kubernetes-logs. L'interface permet de restreindre les sources, en éditant la configuration. D'après la documentation de Scaleway, les macros cockpit_alloy_kubernetes_pods et cockpit_alloy_journal s'écrivent ainsi :
{{{- cockpit_alloy_kubernetes_pods "signalements" "signalements-preprod" }}}
{{{- cockpit_alloy_journal "kubelet" }}}La première limite la collecte aux conteneurs des espaces de noms cités, la seconde aux unités systemd données. Le volume facturé se règle ici : ne collectez pas tout, collectez ce qu'on lira.
La configuration par défaut contient aussi trois étages de traitement utiles à ne pas supprimer sans raison : une limite de débit (500 lignes par seconde, avec une rafale de 500), le rejet des lignes de plus de 4 Ko, et le rejet des lignes vieilles de plus de 48 heures. Ils bornent la facture en cas de boucle d'erreurs.
L'autre voie est de déployer Alloy vous-même avec un chart Helm, versionné dans Git et synchronisé par Argo CD, comme tout composant de lyneko-apps. On y gagne la revue et la reproductibilité, on y perd la simplicité de la console. Le cours Helm détaille ce travail.
Dans Grafana, une requête LogQL sur la source kubernetes-logs retrouve les journaux d'un pod. Les étiquettes disponibles (namespace, pod, container, ou app) dépendent de la configuration d'Alloy : listez-les dans l'Explore avant d'écrire une requête.
3. Rendre l'état des pods visible : kube-state-metrics
Pour alerter sur les pods en échec et les volumes pleins, il faut des métriques. kube-state-metrics expose l'état des objets Kubernetes (nœuds, pods, déploiements, volumes), le kubelet expose l'espace des volumes. Vous déployez kube-state-metrics (chart Helm de la communauté Prometheus, par Argo CD), puis Alloy les collecte et les pousse vers la source de métriques de Cockpit. L'extrait suivant est à adapter (adresses, jeton) ; il reprend la forme de la configuration vue dans le cours Cockpit :
prometheus.scrape "etat_kubernetes" {
targets = [{"__address__" = "kube-state-metrics.monitoring.svc:8080"}]
scrape_interval = "60s"
forward_to = [prometheus.remote_write.cockpit.receiver]
}
prometheus.remote_write "cockpit" {
endpoint {
url = sys.env("COCKPIT_METRIQUES_URL") + "/api/v1/push"
headers = { "X-TOKEN" = sys.env("COCKPIT_JETON") }
}
}L'adresse de la cible est celle du Service de kube-state-metrics dans votre cluster ; l'URL et le jeton viennent de la source de métriques personnalisée que vous avez créée dans Cockpit, et ils arrivent par des variables d'environnement alimentées par un Secret (pas écrits dans la configuration). Les métriques du kubelet sur les volumes (kubelet_volume_stats_*) se collectent de la même façon, par un second bloc prometheus.scrape qui interroge le kubelet (le chemin et l'authentification dépendent de votre chart, vérifiez-les dans sa documentation).
Warning
Comptez avant de collecter, comme le cours Cockpit le montre : un cluster fait vite des dizaines de milliers de séries avec les réglages par défaut des charts. Gardez uniquement les métriques utilisées par vos alertes et vos tableaux de bord.
4. Trois règles d'alerte
Dans un fichier regles-cluster.yaml, à envoyer comme les règles du cours Cockpit :
name: cluster
interval: 1m
rules:
- alert: NoeudNotReady
expr: kube_node_status_condition{condition="Ready",status="true"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Un nœud est NotReady depuis plus de 5 minutes"
- alert: PodsEnEchec
expr: |
sum by (namespace) (
kube_pod_container_status_waiting_reason{reason=~"CrashLoopBackOff|ImagePullBackOff|ErrImagePull"}
) > 0
for: 10m
labels:
severity: warning
annotations:
summary: "Des conteneurs sont en échec durable dans {{ $labels.namespace }}"
- alert: VolumePresquePlein
expr: |
kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes < 0.15
for: 15m
labels:
severity: warning
annotations:
summary: "Le volume {{ $labels.persistentvolumeclaim }} a moins de 15 % d'espace libre"Lisez-les :
- La première utilise l'état
Readydu nœud tel que Kubernetes le rapporte.for: 5mévite d'alerter pour un redémarrage normal. Pendant une montée de pool (leçon 6), les nœuds sont remplacés et passent brièvement par un état non prêt : testez-la pendant une montée en préproduction. - La deuxième somme les conteneurs qui attendent pour une raison d'échec, par espace de noms.
for: 10mlaisse passer un redémarrage normal. - La troisième compare l'espace disponible à la capacité de chaque volume persistant. 15 % est un point de départ : un volume qui grossit vite demande un seuil plus haut, ou une prévision (
predict_linear) plutôt qu'un seuil.
Un quatrième symptôme, un déploiement qui n'a plus tous ses réplicas, se détecte en comparant kube_deployment_status_replicas_available à kube_deployment_spec_replicas sur la durée.
5. Mesurer les requests contre l'usage
Sans rien installer d'autre que ce que Kapsule fournit (le serveur de métriques répond à kubectl top, la définition par défaut de scaleway:cluster-read donne accès à metrics.k8s.io) :
$ kubectl top nodes
$ kubectl top pods -n signalements --containers
$ kubectl describe nodes | grep -A 8 "Allocated resources"
La première affiche la consommation des nœuds, la deuxième celle de chaque conteneur de l'application, la troisième le total des requests et des limites réservées sur chaque nœud, avec leur pourcentage de la capacité allouable. L'écart entre « réservé » et « consommé » est le sur-dimensionnement. Une consommation instantanée ne suffit pas : une API a des pointes. Mesurez sur une semaine (dans Cockpit, la consommation par conteneur), puis fixez les requests près du quantile 95 de l'usage, et la limite de mémoire un peu au-dessus du maximum observé. Pour le processeur, beaucoup d'équipes ne posent pas de limite (elle ralentit sans protéger), mais gardent la request ; voir la leçon sur les ressources.
6. Les coûts cachés à chasser
Une fois par mois, une revue en quelques commandes :
$ kubectl get svc -A --field-selector spec.type=LoadBalancer
$ kubectl get pvc -A
$ kubectl get pv | grep -v Bound
$ scw lb lb list
$ scw block volume list
La première liste les répartiteurs que le cluster a créés ; si scw lb lb list en montre plus, certains ne sont pas du cluster (ou ont survécu à leur Service). Les volumes Released ou Available d'un PersistentVolume sont des restes de claims supprimés : selon la reclaimPolicy de la classe de stockage, la ressource Scaleway peut subsister (leçon 4). Chaque ligne est un poste de coût sans utilité si personne ne peut dire à quoi elle sert. La commande scw block volume list suppose la CLI configurée sur le projet ; n'oubliez pas que les listes se font par région et par zone.
7. Étiqueter pour répartir
Chaque espace de noms reçoit trois étiquettes, dans Git :
apiVersion: v1
kind: Namespace
metadata:
name: signalements
labels:
app.kubernetes.io/part-of: signalements
lyneko.example/equipe: plateforme-civique
lyneko.example/environnement: productionElles servent ensuite à agréger. Avec kube-state-metrics, les requests de processeur de chaque espace de noms se calculent par une requête du type sum by (namespace) (kube_pod_container_resource_requests{resource="cpu"}) ; la part de l'espace dans le total est le rapport entre les deux sommes. Appliquée au coût mensuel des nœuds, elle donne un coût approché par espace. Cette approximation répartit les nœuds, pas les répartiteurs, les volumes ni la passerelle, qui se rattachent à leur propriétaire direct par leurs étiquettes Scaleway (le champ tags des ressources).
8. Éteindre la nuit ce qui n'a pas à tourner
Un environnement éphémère (une préproduction, la copie d'une branche) n'a aucune raison de coûter 24 heures sur 24. Deux mécanismes se combinent.
Réduire les pods. Un CronJob met les Deployment d'un espace à zéro le soir, et les remet en marche le matin. Il lui faut un compte de service et des droits limités à cet espace (leçon 5) :
apiVersion: v1
kind: ServiceAccount
metadata:
name: extinction
namespace: signalements-preprod
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: extinction
namespace: signalements-preprod
rules:
- apiGroups: ["apps"]
resources: ["deployments", "deployments/scale"]
verbs: ["get", "list", "patch", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: extinction
namespace: signalements-preprod
subjects:
- kind: ServiceAccount
name: extinction
roleRef:
kind: Role
name: extinction
apiGroup: rbac.authorization.k8s.io
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: extinction-du-soir
namespace: signalements-preprod
spec:
schedule: "0 19 * * 1-5"
timeZone: "Europe/Paris"
jobTemplate:
spec:
template:
spec:
serviceAccountName: extinction
restartPolicy: Never
containers:
- name: kubectl
image: <votre-registre>/kubectl:1.36
command: ["kubectl", "scale", "deployment", "--all", "--replicas=0"]Un second CronJob identique, à 0 7 * * 1-5, remet un nombre de réplicas connu (--replicas=1). Attention : si Argo CD synchronise cet espace avec réparation automatique (selfHeal), il remettra les réplicas à la valeur de Git. Il faut alors exclure le champ replicas de la comparaison, ou piloter l'extinction par Argo CD lui-même (les fenêtres de synchronisation, voir Synchronisation avancée).
Réduire les nœuds. Éteindre les pods ne coûte rien de moins tant que les nœuds restent. Si l'environnement éphémère a son propre pool avec l'autoscaling et min-size=0, l'autoscaler retire les nœuds vides après son délai (10 minutes par défaut) et le pool tombe à zéro ; le matin, le premier pod Pending fait revenir un nœud, ce qui prend quelques minutes (voir la leçon 3). Les volumes et les répartiteurs de l'espace restent facturés : c'est un coût fixe, à connaître, que l'extinction ne supprime pas.
Sous le capot
Pourquoi les requests, pas l'usage. Le planificateur raisonne sur des quantités déclarées : à l'instant où il place un pod, il ne sait rien de l'usage futur. Le nœud est « plein » quand la somme des requests atteint sa capacité allouable, même s'il est à 10 % d'usage. Réduire le sur-dimensionnement revient à rapprocher les requests de la réalité, pas à optimiser quoi que ce soit côté nœud. La capacité allouable d'un nœud est inférieure à sa capacité totale : le système, le kubelet et les composants de Kapsule en prennent une part, d'où l'intérêt de lire kubectl describe node.
Pourquoi un seul nœud peut faire la différence. L'autoscaler travaille au niveau du pool : il évalue chaque nœud contre le seuil d'utilisation, mais ne retire un nœud que si ses pods peuvent aller ailleurs. Un pod mal placé (stockage local, PodDisruptionBudget trop strict, anti-affinité) fige un nœud à moitié vide. Les journaux du composant kapsule-autoscaler, visibles dans le tableau de bord des journaux du plan de contrôle, peuvent éclairer pourquoi un nœud n'a pas été retiré.
Pièges courants
Aucune donnée dans le tableau de bord. Le sélecteur de cluster en haut de la page est vide ou sur le mauvais cluster ; la région de Cockpit n'est pas celle du cluster ; ou le tableau n'a pas encore reçu de points (quelques minutes après la création du cluster).
La facture des journaux qui s'envole. Alloy collecte par défaut l'espace kube-system et tout le journal systemd ; ajouter tous les espaces de noms « pour voir » multiplie le volume. Une application qui journalise en boucle multiplie le tout. Gardez la limite de débit des étages par défaut, et supprimez la collecte de ce qu'on ne lit pas.
L'alerte NodeNotReady qui sonne à chaque montée. Pendant le remplacement des nœuds, Ready passe à faux pour le nœud vidé. Soit on allonge for, soit on silence l'alerte pendant la fenêtre de maintenance connue (leçon 6).
Les requests réduites jusqu'au OOMKilled. Le conteneur est tué par le noyau avec le statut OOMKilled (visible par kubectl describe pod) : la limite de mémoire était trop basse, pas seulement la request. Remontez-la par paliers, jamais d'un coup à une valeur trop proche de la moyenne.
Sécurité
- Les journaux sont des données. Ils contiennent des adresses, des identifiants d'usagers, parfois des jetons. Pour Signalements, les journaux de l'API ne doivent pas contenir les données personnelles des signalements ; la conservation courte (7 jours par défaut) est un avantage, non un défaut. Le principe de minimisation s'applique aux journaux comme au reste.
- Le jeton d'Alloy est un secret : écriture seule, une source par usage, rangé dans un
Secretgéré par External Secrets, jamais dans le dépôt. S'il fuit, on peut polluer vos tableaux de bord et faire monter votre facture. - Le journal d'audit de l'API est le seul moyen de reconstituer qui a fait quoi dans le cluster. Il suppose un plan de contrôle dédié : c'est un critère de choix pour un cluster qui porte des données de clients ou qui doit satisfaire des exigences de conformité.
- L'accès à Grafana s'organise par IAM (jeux de permissions d'observabilité). Réservez l'écriture de règles d'alerte aux personnes qui exploitent le cluster.
En production
Réserver un plan dédié, ou pas. Un plan de contrôle dédié apporte un SLA (99,5 % selon la documentation), deux réplicas du serveur d'API, plus de nœuds et d'etcd, et le journal d'audit, pour un coût supplémentaire à l'heure avec 30 jours d'engagement. Pour Signalements en production, l'audit et le SLA le justifient souvent ; un environnement de préproduction s'en passe.
Un budget par cluster. Fixez un coût mensuel cible, calculé à partir du nombre de nœuds au repos et à la pointe, et suivez l'écart : l'autoscaler a un max-size qui est aussi un plafond de dépense. Posez-le avec soin.
Revue mensuelle. Les répartiteurs et volumes orphelins, les requests par rapport à l'usage, l'âge du plus vieux pool, la liste des environnements éphémères et de leur propriétaire. Une demi-heure par mois évite la surprise d'une facture trimestrielle.
Exercices
1. Choisir la source (niveau 200). Pour chaque question, dites si la réponse est dans Cockpit sans rien installer, ou si elle exige un agent : (a) le nœud 3 manque-t-il de mémoire ? (b) quel pod a planté hier soir ? (c) l'autoscaler a-t-il retiré un nœud ? (d) quelle est la taille d'etcd ? (e) qui a supprimé ce Deployment ?
Solution
(a) Sans agent : la mémoire des nœuds est dans le tableau de bord du cluster. (b) Il faut un agent : le journal des conteneurs et l'état des pods ne sont pas envoyés d'eux-mêmes ; Alloy et, pour l'état, kube-state-metrics. (c) Sans agent : les journaux du composant kapsule-autoscaler figurent dans le tableau de bord des journaux du plan de contrôle. (d) Sans agent : la documentation indique que la taille d'etcd se consulte dans Cockpit. (e) Le journal d'audit, disponible seulement avec un plan de contrôle dédié ; sinon, l'historique Git d'Argo CD et le journal d'audit de l'IAM donnent une réponse partielle.
2. Combien de nœuds de trop (niveau 200). Le pool applications compte 4 nœuds de 8 vCPU allouables. Les requests de processeur totalisent 20 vCPU ; la consommation observée au 95e centile, 9 vCPU. Combien de nœuds suffiraient si les requests étaient à l'usage au 95e centile plus 30 % de marge, et quelle part de capacité reste réservée sans servir aujourd'hui ?
Solution
Des requests ajustées à 9 × 1,3 = 11,7 vCPU tiennent en théorie sur 2 nœuds (16 vCPU). Mais la perte d'un nœud laisserait 8 vCPU pour 11,7 demandés : on retient donc 3 nœuds (24 vCPU, 16 après la perte d'un nœud, ce qui couvre 11,7). Aujourd'hui, 20 vCPU sont réservés pour 9 utilisés : 11 vCPU, soit 55 %, le sont pour rien. Le gain réaliste est d'un nœud sur quatre : la disponibilité impose de garder de la marge, ce qui fait la différence avec le calcul brut.
3. Éteindre la nuit (niveau 300). Un environnement éphémère compte 3 nœuds. Il tourne aujourd'hui en continu ; on veut qu'il tourne de 7 h à 19 h du lundi au vendredi. Calculez la réduction des heures de nœuds, puis dites ce qui reste facturé, et ce qui peut faire échouer l'extinction.
Solution
Aujourd'hui : 3 × 24 × 7 = 504 heures de nœud par semaine. Avec l'extinction : 3 × 12 × 5 = 180 heures, soit 36 % des heures d'origine, donc 64 % de moins. Restent facturés : les volumes persistants et leurs disques système tant que les nœuds existent, les répartiteurs de charge créés par des Service, les adresses IP, et les journaux déjà ingérés. Ce qui peut échouer : Argo CD en selfHeal qui remet les réplicas, un pod avec stockage local ou un budget d'interruption qui empêche l'autoscaler de retirer les nœuds, ou un pool dont min-size n'est pas à 0.
Récapitulatif
- Kapsule envoie à Cockpit, sans agent et sans frais, les métriques du plan de contrôle, des nœuds et des composants système, et les journaux du plan de contrôle (pas ceux de
kube-apiserver) ; le journal d'audit exige un plan de contrôle dédié. - Le plan de données est à vous : journaux des conteneurs et du systemd par Grafana Alloy (Easy Deploy ou chart Helm), facturés au volume ingéré ; l'état des pods demande kube-state-metrics.
- Quatre alertes de symptômes : nœud NotReady, pods en échec, volume presque plein, réplicas manquants, écrites en PromQL avec un
forqui évite le bruit. - Les coûts : plan de contrôle (gratuit en mutualisé, payant et engagé en dédié), nœuds (poste dominant), répartiteurs, volumes, IP, passerelle, journaux ingérés.
- Les nœuds se paient selon les requests, pas l'usage : on compare
kubectl topet les requests, on ajuste près du quantile 95, on garde de la marge pour la perte d'un nœud. - Le coût se répartit par espace de noms et par étiquette ; OpenCost fait ce travail en continu, avec des prix à lui fournir.
- Un environnement éphémère s'éteint la nuit par CronJob (pods) et pool à
min-sizenul (nœuds) ; volumes et répartiteurs restent facturés.
Pour aller plus loin
- La leçon 14 de Scaleway en pratique, pour les jetons, la conservation et le gestionnaire d'alertes.
- La page de Scaleway sur la supervision de Kapsule et celle sur l'envoi des journaux du plan de données.
- La documentation de
kube-state-metrics, qui liste les métriques de chaque type d'objet. - La leçon 8, pour décrire en Terraform les pools d'environnements éphémères à
min_size = 0. - Les cours FinOps et Concevoir une alerte utile, pour la discipline de coût et la qualité des alertes.
Sources
- Scaleway, How to monitor your Kubernetes Kapsule cluster with Cockpit
- Scaleway, How to monitor your Kapsule data plane with Cockpit (Alloy, Easy Deploy)
- Scaleway, How to access Kubernetes audit logs
- Scaleway, Kubernetes control plane offers
- Scaleway, Kubernetes FAQ (facturation)
- Aide de la CLI scw 2.62.0 : k8s cluster update (autoscaler-config), k8s pool update
- Kubernetes, Resource Management for Pods and Containers
- kube-state-metrics, documentation des métriques de nœuds et de pods
- OpenCost, documentation