Aller au contenu

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

  1. Les pods de la zone restante continuent de servir, sans intervention.
  2. 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.
  3. 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.