Internal
Résilience à la perte d'une AZ¶
Les clusters ont des nœuds dans deux zones, fr-par-1 et fr-par-2. L'entrée (Load Balancers, DNS, Traefik) survit déjà à la perte d'une zone. Une application n'y survit que si ses pods sont répartis entre les deux zones, ce qui n'est pas le cas par défaut.
Checklist¶
| # | Règle | Pourquoi |
|---|---|---|
| 1 | replicas ≥ 2, avec 2 fois les pods nécessaires pour tenir la charge |
Après la perte d'une zone, il ne reste que la moitié des pods |
| 2 | Toleration k8s.scaleway.com/multiaz |
Les pools fr-par-2 ont ce taint : sans elle, aucun pod n'y va |
| 3 | topologySpreadConstraints sur la zone |
Force la répartition entre fr-par-1 et fr-par-2 |
| 4 | Anti-affinité sur le nœud | Un nœud perdu ne coupe qu'un pod |
| 5 | PodDisruptionBudget |
Les maintenances (drain, upgrade) ne coupent pas tous les pods |
| 6 | resources.requests renseignées, mémoire request = limit |
Placement correct et pas d'éviction prioritaire |
| 7 | priorityClassName |
Voir Priority classes |
| 8 | Pas de volume Block Storage partagé | Un volume Block Storage est zonal : un pod qui l'utilise ne peut pas changer de zone |
Exemple¶
Values Helm à adapter : mon-app, les valeurs, et les noms de clés selon le chart.
replicas: 4
priorityClassName: app-high
tolerations:
- key: "k8s.scaleway.com/multiaz"
operator: "Equal"
value: "true"
effect: "NoSchedule"
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name: mon-app
matchLabelKeys:
- pod-template-hash # calcule la répartition par version : un rollout n'est pas bloqué par les anciens pods
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: mon-app
topologyKey: kubernetes.io/hostname
podDisruptionBudget:
minAvailable: 2
Choisir le nombre de replicas¶
Avec maxSkew: 1, l'écart entre les zones ne dépasse jamais 1 pod.
| Replicas | Répartition | Pods restants après perte d'une zone |
|---|---|---|
| 2 | 1 / 1 | 1 |
| 3 | 2 / 1 | 1 ou 2 |
| 4 | 2 / 2 | 2 |
| 5 | 3 / 2 | 2 ou 3 |
Un nombre pair garantit le même résultat quelle que soit la zone perdue.
Un nœud par pod dans chaque zone
Avec l'anti-affinité required, il faut autant de nœuds dans une zone que de pods à y placer.
Vérifier le min_size du pool fr-par-2, sinon les pods attendent que l'autoscaler ajoute des nœuds.
Ce qui se passe quand une zone tombe¶
- Les pods de la zone restante continuent de servir, sans intervention.
- Après environ 5 minutes, les pods de la zone perdue sont recréés, mais restent en Pending : les placer dans la zone restante casserait la répartition.
- Au retour de la zone, les pods en Pending s'y placent automatiquement.
La capacité pendant l'incident est donc celle de la zone restante : c'est la règle 1 qui la dimensionne.
Vérifier¶
kubectl get pods -n <namespace> -o wide
kubectl get nodes -L topology.kubernetes.io/zone
Les pods doivent être sur des nœuds des deux zones, un seul pod par nœud.
Référence¶
Traefik applique ces règles : main-infra/scw-tf-modules/ingress-traefik-ha/helm_values/traefik-*.yaml.