Pour synthétiser, je pense que le fond du problème, c’est qu’avant de penser "passage à l’échelle" sur une charge de travail, il faut connaître son "profil de performances" (Qu’est-ce qui limite la quantité de travail ? Quand ? Pourquoi ?).
Pour connaître le profil de performances d’un pod ou d’une fonctionnalité, il faut effectivement faire des tests de charge, et pour faire ces tests de charge, il faut d’abord mettre en place la couche d’observabilité du système.
Dit plus simplement : avant de penser à l’auto-scaling, une bonne idée serait que tu installes dans ton cluster un Prometheus et un Grafana qui te permettent d’avoir sous les yeux des graphes qui mettent en correspondance :
- la charge de travail réalisé (nombre de requêtes traitées),
- la consommation en CPU/RAM du pod,
- la consommation de bande passante du pod.
C’est beaucoup plus facile à faire qu’à décrire ! Il suffit d’installer le chart Helm qui va bien (https://github.com/grafana/helm-charts) et de configurer une dashboard dans Grafana. Une fois que tu as ça, tu peux commencer à jouer, à simuler des pics de charge, à voir ce qui pète en premier, et donc à comprendre comment tes pods se comportent face à une montée de charge. Plus important encore, tu peux caractériser ce qui se passe pour de vrai et en temps réel sur ton infra avec un système qui tourne en utilisation normale.
Une fois que tu as ces connaissances à ta disposition, ça te permet de décider d’un tas de trucs que tu vas pouvoir paramétrer dans tes déploiements :
- Les requêtes de ressources du Pod : quelle quantité de RAM et de CPU est-il supposé utiliser en situation normale ? Kubernetes se sert de ces requêtes pour affecter les pods à des noeuds qui disposent des ressources disponibles. Par défaut, Kubernetes tolère qu’un pod dépasse ses requêtes de ressources, c’est une soft limit. Par contre si un node se retrouve très chargé, Kubernetes va tuer (et réaffecter) en priorité les pods qui dépassent leur requête de ressources.
- Les limites de ressources du Pod : à partir de quelle utilisation de RAM et de CPU on considère que le pod est dans un état "pathologique" ? Cette fois, c’est une hard limit : dès l’instant que le pod dépasse une limite, Kubernetes le tue et le re-schedule.
- Combien de répliques tu veux avoir de ce pod "en fonctionnement normal" (pas spécialement en creux ou en pic de charge). Cela dépend de la charge que tu observes au quotidien sur le système, mais aussi des garanties de disponibilité que tu veux tenir (combien de répliques peuvent tomber à la fois sans que ça n’impacte significativement la qualité de service).
- Si ça vaut le coup de configurer de l'autoscaling : certains pods s’y prêtent généralement bien (genre des services d’API) et augmenter les répliques augmente la capacité de travail, d’autres pas du tout et les scaler n’augmentera pas ta capacité de traitement : il n’y a pas de règle pour prendre une décision automatique.
Dans les questions qui restaient, il y avait celle-ci :
Idem, si j’ai 2 pods qui sont répartis entre 2 noeud, et qu’un de ces derniers venait à ne plus être disponible, le pod qui lui était "associé" sera donc dirigé vers le nœud encore en vie. Mais dans ce cas, d’où l’intérêt ?
Là on entre dans les configurations avancées, mais tu peux parfaitement ajouter des hints à Kubernetes pour lui demander d’éviter de scheduler un pod sur un noeud si celui-ci fait déjà tourner une réplique du même deployment. Si tu n’as que 2 machines, ça n’est pas immédiatement apparent, mais si tu as plus de 2 machines (disons 3 : A, B et C) et 2 instances (une sur A et une sur B), alors quand B tombe, kubernetes sera "incité" à redistribuer le travail vers C plutôt que A qui fait déjà tourner une instance.
Il y a plein de petits mécanismes de ce style que tu peux utiliser pour contrôler finement ce qui se passe, mais à mon avis tu n’en es pas encore là. Pareil pour l’auto-scaling.
Je pense qu’avant d’arriver à tuner ce genre de détails, tu devrais déjà te forger une bonne compréhension des mécaniques de base de Kubernetes, et du profil de perfs de ton application. Il sera toujours temps de découvrir les affinities, anti-affinities, taints et tolerations quand tu auras un problème concret à résoudre.
Un point que je ne sais pas du tout, c’est si Kubernetes permet de définir des garanties sur les I/O et la bande passante (disque et réseau), ou si tu peux découvrir des surprise à cause de ça.
Les seules ressources qui sont "comprises" (surveillées explicitement) par K8s pour le moment sont la RAM et le CPU, c’est seulement sur ces ressources que l’on peut configurer les requêtes/limites des pods, et les critères pour leur auto-scaling. Autrement dit, seules les consommations de RAM et de CPU sont utilisées pour partager les ressources des nodes entre les pods comme on se partage un gâteau.
Ça semble sacrément difficile de généraliser cette approche aux IO, notamment parce qu’il ne s’agit pas d’une ressource "unique" où on pourrait se dire "ce pod pioche 5MB/s de bande passante alors qu’il en a 2GB/s disponible".
Dans tous les cas, ce genre de choses se surveille de la même manière et avec les mêmes outils que pour configurer les ressources et limites de CPU/RAM : en installant un système d’observabilité dans le cluster, et en analysant les réactions des pods dans diverses conditions.