Lorsque la création de pods basés sur ECI échoue dans une zone, tous les réplicas concentrés dans cette zone deviennent indisponibles. Deux scénarios d'échec sont courants : tous les réplicas se retrouvent dans la même zone lors de la planification, et les échecs de création ECI dans certaines zones violent silencieusement les garanties de répartition. Cette rubrique explique comment utiliser les contraintes de répartition topologique Kubernetes et les règles d'affinité pour prévenir ces deux problèmes dans un cluster ACK managé Pro.
Prérequis
Avant de commencer, assurez-vous de disposer des éléments suivants :
-
Un cluster ACK managé Pro répondant aux exigences suivantes :
Version de Kubernetes 1.22 ou ultérieure
Composant ACK Virtual Node version 2.10.0 ou ultérieure
Composant kube-scheduler version 5.9 ou ultérieure, avec la politique de planification des pods basée sur les nœuds virtuels activée
Plusieurs zones (vSwitch) configurées dans le profil eci-profile afin que les pods puissent être planifiés entre les zones
Les champs
nodeAffinity,podAffinityoutopologySpreadConstraintsdéfinis dans la spécification de votre pod, ou une ResourcePolicy configurée pour le pod
Pour planifier des pods sur des nœuds virtuels basés sur ARM, ajoutez des tolérations correspondant aux taints de ces nœuds.
Notes d'utilisation
Définissez
topologyKeysurtopology.kubernetes.io/zone.-
Le comportement de planification décrit dans cette rubrique ne s'applique pas lorsque :
L'annotation
k8s.aliyun.com/eci-schedule-strategy: "VSwitchOrdered"est définie sur le pod (la planification multi-zones suit alors un ordre fixe de vSwitch).L'annotation
k8s.aliyun.com/eci-fail-strategy: "fail-fast"est définie sur le pod.
Choisir une approche
Deux mécanismes Kubernetes répondent à des objectifs différents :
| Objectif | Mécanisme | Cas d'utilisation |
|---|---|---|
| Répartir les pods uniformément entre toutes les zones disponibles | topologySpreadConstraints |
Haute disponibilité — les réplicas sont distribués de sorte qu'une défaillance d'une seule zone n'affecte qu'une fraction d'entre eux |
| Épingler les pods à une zone spécifique ou les maintenir colocalisés | podAffinity + nodeAffinity |
Performance — la faible latence entre les pods est cruciale, ou votre charge de travail doit se trouver dans une zone particulière |
Les deux exemples ci-dessous utilisent les mêmes champs requis par ECI : une tolération pour virtual-kubelet.io/provider et une affinité de nœud preferredDuringSchedulingIgnoredDuringExecution qui privilégie les nœuds Elastic Compute Service (ECS) par rapport aux nœuds virtuels. Seule la règle de répartition ou d'affinité change.
Exemple 1 : Répartir les pods uniformément entre les zones
Cet exemple crée un Deployment avec 10 réplicas répartis uniformément entre toutes les zones disponibles.
Étape 2 : Vérifier le résultat de la planification
Exécutez la commande suivante pour voir sur quels nœuds les pods ont été planifiés :
kubectl get po -lapp=with-pod-topology-spread \
-o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName \
--no-headers | grep -v "<none>"
Pour compter les pods par zone :
kubectl get po -lapp=with-pod-topology-spread \
-o custom-columns=NODE:.spec.nodeName \
--no-headers | grep -v "<none>" \
| xargs -I {} kubectl get no {} -o json \
| jq '.metadata.labels["topology.kubernetes.io/zone"]' \
| sort | uniq -c
Exemple 2 : Déployer des pods dans une zone spécifique
Cet exemple crée un Deployment avec 3 réplicas qui doivent tous se trouver dans la même zone. Utilisez ce modèle lorsque la faible latence entre les pods est plus importante que la répartition entre les zones.
Étape 1 : Créer le Deployment
Enregistrez le code YAML suivant dans le fichier deployment.yaml et exécutez la commande kubectl apply -f deployment.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
name: with-affinity
labels:
app: with-affinity
spec:
replicas: 3
selector:
matchLabels:
app: with-affinity
template:
metadata:
labels:
app: with-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- with-affinity
topologyKey: topology.kubernetes.io/zone
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: type
operator: NotIn
values:
- virtual-kubelet
tolerations:
- key: "virtual-kubelet.io/provider"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: with-affinity
image: registry.k8s.io/pause:2.0
Les trois sections pertinentes pour la planification sont :
| Section | Fonction |
|---|---|
podAffinity (requiredDuringSchedulingIgnoredDuringExecution, topologyKey: topology.kubernetes.io/zone) |
Exige que tous les pods portant le libellé app: with-affinity se trouvent dans la même zone. kube-scheduler ne placera pas un pod sauf si cela est réalisable. Consultez la section Node affinity. |
nodeAffinity (preferredDuringSchedulingIgnoredDuringExecution, type NotIn virtual-kubelet) |
Privilégie les nœuds ECS ; bascule sur les nœuds virtuels lorsqu'aucun nœud ECS n'est disponible. Consultez la section Node affinity. |
tolerations (virtual-kubelet.io/provider: Exists, NoSchedule) |
Permet à kube-scheduler de placer des pods sur des nœuds virtuels. Consultez la section Taints and tolerations. |
Pour épingler les pods à une zone spécifique au lieu de les laisser se colocaliser là où le premier pod est planifié, remplacez le bloc podAffinity par une affinité de nœud requiredDuringSchedulingIgnoredDuringExecution. La configuration suivante planifie les pods exclusivement dans la zone A de Pékin :
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- cn-beijing-a
Étape 2 : Vérifier le résultat de la planification
Exécutez la commande suivante pour voir sur quels nœuds les pods ont été planifiés :
kubectl get po -lapp=with-affinity \
-o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName \
--no-headers | grep -v "<none>"
Pour compter les pods par zone :
kubectl get po -lapp=with-affinity \
-o custom-columns=NODE:.spec.nodeName \
--no-headers | grep -v "<none>" \
| xargs -I {} kubectl get no {} -o json \
| jq '.metadata.labels["topology.kubernetes.io/zone"]' \
| sort | uniq -c
Répartition topologique stricte des pods ECI
Par défaut, kube-scheduler vise une distribution uniforme entre les zones, mais ne bloque pas le placement des pods lorsque la création ECI échoue dans certaines zones. Cela peut violer silencieusement la contrainte maxSkew.
Par exemple, avec maxSkew: 1 et trois zones (A, B, C), kube-scheduler déploie uniformément les pods d'une charge de travail entre toutes les zones. Si la création ECI échoue dans les zones B et C, les pods ne s'exécutent que dans la zone A, ce qui viole la contrainte spécifiée par maxSkew.
Activez la répartition topologique stricte des pods ECI pour garantir le respect de la contrainte. Avec le mode strict activé, kube-scheduler assigne d'abord un pod à chaque zone et retient les pods en attente jusqu'à ce que les pods planifiés soient créés. La figure ci-dessous montre l'état initial : un pod assigné à chaque zone, tous les autres étant en attente.
Même après la création du pod A1, kube-scheduler ne planifie pas le pod suivant, car si la zone B ou C échouait, la contrainte serait violée. Ce n'est qu'après la création du pod B1 que kube-scheduler planifie un pod dans la zone C. Les pods ombrés en vert indiquent les pods créés.
Pour désactiver la répartition stricte et permettre à kube-scheduler de planifier des pods indépendamment de la satisfaction des contraintes, définissez whenUnsatisfiable: ScheduleAnyway. Pour plus de détails sur les paramètres, consultez la section Définition de la contrainte de répartition.