De la haute disponibilité avec Azure Kubernetes Services : le focus Infra !
Tags: azure, kubernetes, infrastructure
Published: 2020-10-06 13:32:55

Quand on choisit d’utiliser AKS, c’est pour répondre à un besoin de haute disponibilité et de résilience applicative. Dans ce post, je vous propose d'analyser quelques points d’attention au niveau infrastructure pour atteindre ces objectifs. Nous parlerons donc ici de pools de nœuds, de déploiement multi zone et multi région ainsi que de SLA.

#Organiser son cluster avec des pools de nœuds

Quand on utilise un cluster Kubernetes, nous sommes amenés à utiliser des nodes. Ces nodes sont des VMs composant le cluster permettant d’exécuter des pods contenant nos applications. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/o4akhcwcah5kltyn9vay.png)

Ces nœuds sont regroupés en pool de nœuds, un regroupement logique de VM du même type grâce aux VMSS Azure ([Virtual Machine Scale Set](https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/overview)).

*Petit apparté : il est possible d'utiliser des VMAS (VM avec Availability Set plutôt que des VMSS). J'en parle pour être complet mais je déconseille cette approche car il vous sera alors impossible de gérer plusieurs nodepools et configurer un autoscale sur le cluster.*

Tout l’intérêt des nodepools est la possibilité de gérer des nœuds spécifiques pour exécuter nos pods afin de répondre à des besoins bien précis. Voyons comment les manipuler.

##Création du cluster

Je créé un cluster AKS avec un pool de noeud de 2 VM. Important : Le cluster AKS doit utiliser un loadbalancer en SKU "Standard" pour pouvoir utiliser plusieurs pools de nœuds :

```powershell
az aks create --resource-group rgAks --name myAKSCluster --vm-set-type VirtualMachineScaleSets --node-count 2 --generate-ssh-keys --load-balancer-sku standard
```
La commande suivante (az aks nodepool list) me renseigne sur les node pools de mon cluster. Pour le moment il n'y en a qu'un :

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6rg4qrd9lk8du3hcncsr.png)

##Ajout d’un pool de noeud

J'ajoute un second node pool contenant une VM de type D4s_v3 :
```powershell
az aks nodepool add --resource-group rgAks --cluster-name myAKSCluster --name nodepool2 --node-count 1 --node-vm-size Standard_D4s_v3 --no-wait
```
J'ai maintenant deux pools de nœuds à disposition. Deux pools qui contiennent des VM de taille (et donc de puissance de calcul) différente ! Et nous allons tout de suite voir en quoi cette capacité est hyper intéressante :)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jfa5zu5ycfndw2afc615.png)

#Le choix des noeuds

Il est possible de créer des nodes particuliers :

      •	Optimisé en quantité de mémoire ou de processeur.
      •	Avec une prise en charge GPU. 
      •	Optimisé pour le stockage.

Je ne vais pas présenter ici les différents type de VM et le nommage associé donc pour obtenir des informations sur les machine virtuelles vous pouvez consulter ce [lien](https://azure.microsoft.com/fr-fr/pricing/details/virtual-machines/series/) !

Ici par exemple je créé un pool de nœud conçu pour le calcul GPU.
```powershell
az aks nodepool add --resource-group rgAks--cluster-name myAKSCluster --name gpunodepool --node-count 1 --node-vm-size Standard_NC6 --no-wait
```
##Associer des nodes au pods

Maintenant que nous avons des nœuds spécifiques, il serait intéressant que des pods s’exécutent sur ces nœuds en conséquence. Pour ce besoin nous pouvons utiliser les notions de ["taints" et "tolerations"](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) !

      •	Si j’applique une taint à un nœud je pourrais déployer sur ce nœud uniquement des pods prévu pour la supporter.
      •	Je peux alors appliquer une toleration à un pod pour lui permettre de supporter la taint d’un nœud.

Voici les types de taint disponibles :

      •	NoSchedule : les pods qui ne tolèrent pas la taint ne seront pas déployés sur le nœud.
      •	PreferNoSchedule : Kubernetes évite de déployer les pods sur le nœud. Mais si besoin, il peut le faire.
      •	NoExecute : Même punition que le NoSchedule mais en prime, si un pod est déjà en cours d’exécution sur ce nœud, il est supprimé de celui-ci.

Grâce à ces pools de nœuds ainsi que les taints et tolerations nous avons la possibilité de prévoir des nœuds dans notre cluster AKS destinés à des types de pods bien précis. Il est donc possible d’adapter l’environnement d’exécution Kubernetes en fonction du type d’application déployé pour lui affecter plus ou moins de ressources, du stockage ou un GPU.

##Quelques précisions :

      •	La création du cluster crée un pool de nœuds par défaut, qu’il n’est pas possible de supprimer.
      •	Le cluster AKS peut avoir un maximum de huit pools de nœuds et 800 nœuds dans ces 8 pools de nœuds.
Maintenant que nous avons des pools de nœuds adaptés à notre besoin, voyons comment les déployer dans Azure.

#Comment déployer mes nœuds ?

On désigne par résilience la capacité d’un service à continuer de fonctionner malgré la défaillance d’un ou plusieurs éléments d’infrastructure (base de données, serveurs Web, accès réseau, … ). La résilience désigne également la capacité du service à revenir dans un mode nominal de façon automatisée.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4ef05dnsow633vp3x46w.jpg)

##Les régions et zones Azure

Avant de parler de régions, il faut introduire les zone géographiques. Une zone géographique correspond à une offre de déploiement de composants Azure. Par exemple France. Une zone géographique contient au minimum deux régions, qui peuvent être géorépliqué (le pairage des régions étant définis par Microsoft).
Par exemple la zone géographique France est composée de France Centre et France Sud. Celles-ci permettent de répondre à des exigences clients concernant le déploiement et le stockage des informations.

Une région est un emplacement physique de datacenter Azure. Par exemple la région France Centre est constitué de 3 datacenters situés en région parisienne.

Les zones de disponibilité sont des emplacements physiquement séparés au sein d’une région Azure comme France Centre. Chaque zone de disponibilité est composée d’un ou de plusieurs centres de données équipés d’une alimentation, d’un refroidissement et d’un réseau indépendants.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h5d2c045jgsy14z4966z.png)

##AKS et zones de disponibilité

Voyons l’application des zones de disponibilités sur AKS ! Si vous avez bien suivis, vous comprenez maintenant que les clusters AKS déployés à l’aide de zones de disponibilité peuvent répartir les nœuds sur plusieurs zones au sein d’une même région ! Par exemple, un cluster dans la région  France Centre  peut créer des nœuds dans les trois zones de disponibilité de France Centre. Il y aura des noeuds sur chaque datacenter composant la région.
 
Grace à cela votre cluster AKS est capable de tolérer une défaillance dans l’une de ces zones ; si un des datacenter de la région est indisponible la continuité de service est assuré. A contrario, si tout les nœuds de notre cluster était déployé au même endroit, le service serait indisponible.

###SLA des Nodes AKS

Le SLA d’un node de notre cluster correspond au SLA de la VM utilisée par ce node.

Le SLA “standard” est à 99.9%. Si nous utilisons un availability set : 99.95% soit environ 4h d’indisponibilité par an.
Grace à l’availability zone, on monte à 99.99% soit moins d’une heure d’indisponibilité par an.

###Limitations et disponibilité de la région

Attention, toutes les régions ne gèrent pas les AZ ! Nous pouvons actuellement créer des clusters AKS en utilisant des zones de disponibilité dans les régions listées [ici](https://docs.microsoft.com/fr-fr/azure/aks/availability-zones#limitations-and-region-availability).

Attention, quelques informations à prendre en compte !

      •	Les zones de disponibilité se gèrent à la création du cluster. Ces paramètres ne sont pas modifiables ultérieurement.
      •	Les clusters avec des zones de disponibilité activées nécessitent l’utilisation du loadbalancer SKU Standard Azure pour la distribution entre les zones.
      •	Incompatible avec les pods statefulset avec un volume persistent !

###Mise en oeuvre

Le paramètre permettant d’utiliser les zones de disponibilité est zones :
```powershell
az aks create --resource-group aksAvailabilityZone --name aks --generate-ssh-keys --vm-set-type VirtualMachineScaleSets --load-balancer-sku standard --node-count 3 --zones 1 2 3
```
Je me connecte à mon cluster nouvellement créé :
```powershell
az aks get-credentials --resource-group aksAvailabilityZone --name aks
```
Pour obtenir la description des nodes :
```powershell
kubectl describe nodes | select-string -pattern '^Name:','zone='
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rniqpatrr0mwzfp4r0vh.png)

J’ai bien un node de déployé dans chaque zone de la région France Centre. Réalisons une montée en charge pour analyser la répartition des nodes :
```powershell
az aks scale --resource-group aksAvailabilityZone --name myAKSCluster --node-count 5
kubectl describe nodes | select-string -pattern '^Name:','zone='
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/c53us54gwz7c3ndmr4dt.png)

J’ai donc deux nodes sur France Centre 1 et 2, et un node sur France Centre 3. Je déploie un nginx :
```powershell
kubectl run nginx --image=nginx --replicas=3
```
Et je demande un descriptif de mes pods :
```powershell
kubectl describe pod | select-string -pattern '^Name:','^Node:'
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/t495lrzczzhqhj7stt5j.png)

J’ai donc un pod en zone 1 et 3. Si le premier datacenter de la région est indisponible, j'aurais toujours un pod à s'éxécuter sur un autre datacenter.

###Comment fonctionne le déploiement multi zones ?

Par défaut Kubernetes est capable de répartir automatiquement les pods sur les différents [noeuds](https://kubernetes.io/docs/setup/best-practices/multiple-zones/) du cluster. Ceci afin de prévenir la défaillance de l'un d'eux. Cependant, sans contrôle de notre part, rien ne garantit qu'ils seront répartis de façon optimale.

Dans le cas d'un déploiement multi zones il peux être intéressant d'influer sur la façon dont la répartition est effectuée.
Il pourra par exemple être pertinent de demander l'exécution de minimum 2 réplicas sur chacune des 3 AZ d'une région.

Pour ce faire nous pourrons utiliser les [topology spread constraints](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/). Associé aux labels des nodes, ces topologies nous permettront de contrôler la propagation des pods dans notre cluster afin de garantir au mieux la haute disponibilité et l'utilisation des ressources allouées.

Je vous renvoie à la [doc officielle du composant](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods) pour la mise en œuvre.

##Pour aller plus loin : le déploiement multi-région

Pour se prémunir de l’indisponibilité d’une région entière comme France Centre, on peux imaginer déployer deux clusters AKS sur deux régions différentes.

A ce moment-là, on peut utiliser Traffic Manager pour contrôler la façon dont le trafic est dirigé vers les clusters dans différentes régions. 

On peux router le traffic suivant divers paramètres :

      •	Le temps de réponse des clusters
      •	En fonction de critères géographiques (pour connecter un utilisateur à sa région la plus proche par exemple).
      •	Si cette région rencontre un problème, Traffic Manager peux diriger l’utilisateur vers une autre région.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nyvtcg5opxwk9qefp39b.png)

Nous pourrons utiliser cette approche conjointement avec la Réplication des registry afin d’accélérer les déploiements applicatifs.

Coté backend (base de données, stockage de documents) il est possible également de mettre en oeuvre des mécanismes de déploiement multi régions et de synchronisation automatique des données :

- Avec une base de données [SQL Database géo répliqué](https://docs.microsoft.com/fr-fr/azure/azure-sql/database/active-geo-replication-overview).
- Avec un storage account avec une [réplication](https://docs.microsoft.com/fr-fr/azure/storage/common/storage-redundancy) GRS voir RA-GRS afin que les données puissent être en R/W dans les deux régions simultanément.


#Concernant le master ...

En déploiement « standard » Microsoft fournit un SLO de 99.5% pour l’API Server du Master Kubernetes, point d’entrée de toutes les sollicitations au cluster.

Depuis peu Microsoft propose un “uptime SLA” pour AKS pour garantir la disponibilité de l’API Server Kubernetes.

Cette possibilité se positionne en parallèle du déploiement classique d’AKS, que nous connaissons déjà.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0uxcwxlc7j1xrfwobox6.png)

Le contrat de SLA garantit une durée de bon fonctionnement de 99,95 % pour le serveur d’API Kubernetes pour les clusters utilisant des zones de disponibilité Azure et de 99,9 % pour les clusters n’utilisant pas de zones de disponibilité.

Pour atteindre ce niveau de SLA (99.9), la plateforme utilise une réplication de nodes du master sur des availability set : des “zones” d’un datacenter qui garantissent :

      •	Des mises à jour qui ne seront pas appliquées en même temps qu’une autre zone
      •	Une alimentation électrique spécifique
      •	Une gestion réseau spécifique

Le coût de cet option est d’environ (il varie suivant les régions) de 0.10$ par heure par cluster. Un cluster AKS déployé sans cette option (comme actuellement donc) conserve son SLO de 99.5% !

Le tableau récapitulatif :

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/j4so5tecsbpi9bgfjtx7.png)

Pricing par région : https://azure.microsoft.com/fr-fr/pricing/details/kubernetes-service/

La disponibilité des nœuds, comme vu précédemment, est couverte par le contrat SLA des machine virtuelle sur lesquelles s’exécutent les pods. 

##Mise en oeuvre

Pour utiliser cette garantie de disponibilité, il faudra utiliser le paramètre --uptime-sla comme dans la commande ci-dessous, fournie par Microsoft :
```powershell
az aks create --resource-group myResourceGroup --name myAKSCluster --uptime-sla --node-count 1 --generate-ssh-keys
```
Attention, il n’est pas possible de retirer cette configuration à un cluster une fois appliquée. En revanche il est possible de créer un cluster "standard" puis de configurer le uptime SLA.

La différence se verra ici au niveau du SKU du cluster déployé :

  "sku": {
    "name": "Basic",
    "tier": "Paid"
  },

#Conclusion

Nous avons vu dans cet article les différents éléments composants un cluster AKS et les moyens d'optimiser leur disponibilité. Nous étions aujourd'hui concentré sur la partie infrastructure, mais attention cette gestion seule n'est pas suffisante ! Il faut également s'intéresser à la haute disponibilité applicative. Une infrastructure résiliente c'est bien, mais si l'applicatif ne l'est pas cela ne sert à rien !

Dans un prochain article nous nous intéresserons au façon de propager cette haute disponibilité aux applications avec l'autoscaling au niveau des pods comme du cluster.

J'espère que cet article vous aura apporté des informations pour la gestion de votre cluster k8s dans Azure !

**Merci à [Louis-Guillaume Morand](https://www.linkedin.com/in/lgmorand) et [Yves de Caqueray](https://www.linkedin.com/in/yves-de-cacqueray-88b5b793) pour la relecture et leurs précieux conseils.**

Thomas