Dans cet article nous allons suivre le tutoriel de la doc de microsoft tutorial-kubernetes-prepare-app
J'ai pour ma part totalement effacé toute resource sur Azure (free trial) pour partir d'une feuille blanche car certain nom de resource été similaire.
Ce tuto part du principe que l'on a une application qui fonctionne en dev. On souhaite la conteneuriser, la distribuer sur un registry online puis s'en servir via AKS. Ensuite on verra comment scaler l'app.
Ce tuto est plutot long, mais je pense complet sur les sujet essentiels.
1 - Création d'une image docker
On va cloner une app de demo sur github, mais si vous avez la votre, prennez la. Ouvrez un terminal, créer un répertoire de travail et se mettre dedans puis taper :
git clone https://github.com/Azure-Samples/azure-voting-app-redis.git
L'image est très légère. Faut dire que le code aussi.
En se rendant dans le repertoire azure-voting-app-redis on peut voir quelques fichiers dont un qui va particulièrement nous intéresser : docker-compose.yaml
version: '3' services: azure-vote-back: image: redis container_name: azure-vote-back ports: - "6379:6379" azure-vote-front: build: ./azure-vote image: azure-vote-front container_name: azure-vote-front environment: REDIS: azure-vote-back ports: - "8080:80"
Ce fichier est relativement simple. Nous avons deux services basées sur une image redis et une app web dont l'image est azure-vote-front. L'image Redis proviendra du registry Docker Hub (version officielle) et la seconde sera buildé avec un dockerfile situé dans le projet web azure-vote. Voici ce dockerfile :
FROM tiangolo/uwsgi-nginx-flask:python3.6 RUN pip install redis ADD /azure-vote /app
Ce dockerfile va créer un conteneur basé sur l'image tiangolo/uwsgi-nginx-flask (950 Mo) (avec python 3.6). On execute ensuite une commande pour installer redis (via python) et on ajoute le code source du site web dans un repertoire sur le conteneur nommé app.
On a plus qu'a taper la commande docker-compose up -d ce qui va monter les deux images dans le registry local. Dans un premier temps cela va télécharger les image de tiangolo et redis si vous ne les avez pas déjà sur votre poste. Ensuite docker-compose va builder l'image de notre app. (attention, il faudra la rebuilder pour la mettre a jour dans une prochaine image). La commande suivante va lister vos images locales :
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE azure-vote-front latest 9cc914e25834 40 seconds ago 694MB redis latest a1b99da73d05 7 days ago 106MB tiangolo/uwsgi-nginx-flask flask 788ca94b2313 9 months ago
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 82411933e8f9 azure-vote-front "/usr/bin/supervisord" 57 seconds ago Up 30 seconds 443/tcp, 0.0.0.0:8080->80/tcp azure-vote-front b68fed4b66b6 redis "docker-entrypoint..." 57 seconds ago Up 30 seconds 0.0.0.0:6379->6379/tcp azure-vote-back
En lisant nos conteneurs lancé par docker on voit bien nos deux images. On a plus qu'à tester l'url http://localhost:8080 et on devrait voir notre app tourner localement!
Un petit docker-compose down pour libérer ces process docker et cette partie est finie.
2 - Envoyer nos conteneurs vers Azure Container Registry
La première chose à faire est de créer une instance d'Azure Container Registry (ACR)
En premier lieu on créer le groupe de ressources :
az group create --name myResourceGroup --location eastus
Pour info celui ci n'apparaitra pas sur le portail pour le moment car il est vide. Il faut lui rajouter un élement. Voici la commande pour créer un ACR :
az acr create --resource-group myResourceGroup --name myACR35 --sku Basic
Le nom du registry doit être unique car il sera accessible publiquement via une url comme celle ci myacr.azurecr.io En tapant cette commande, azure nous indique que ce nom est déjà occupé et nous livre une adress web pour vérifier les nom existant.
On va renommer noter myACR en qq chose de libre, myACR35 à l'air de passer :
> az acr create --resource-group myResourceGroup --name myACR35 --sku Basic { "adminUserEnabled": false, "creationDate": "2020-01-30T10:12:36.101431+00:00", "id": "/subscriptions/eaeaae83-9dcd-405b-8f02-4e58e0e30bbb/resourceGroups/myResourceGroup/providers/Microsoft.ContainerRegistry/registries /myACR35", "location": "eastus", "loginServer": "myacr35.azurecr.io", "name": "myACR35", "networkRuleSet": null, "policies": { "quarantinePolicy": { "status": "disabled" }, "retentionPolicy": { "days": 7, "lastUpdatedTime": "2020-01-30T10:12:37.145663+00:00", "status": "disabled" }, "trustPolicy": { "status": "disabled", "type": "Notary" } }, "provisioningState": "Succeeded", "resourceGroup": "myResourceGroup", "sku": { "name": "Basic", "tier": "Basic" }, "status": null, "storageAccount": null, "tags": {}, "type": "Microsoft.ContainerRegistry/registries" }
L'ACR myACR35 étant créé on va s'y connecter :
> az acr login --name myACR35
Uppercase characters are detected in the registry name. When using its server url in docker commands, to avoid authentication errors, use al
l lowercase.
Login Succeeded
Le retour de cette commande nous indique qu'il serait préférable à l'avenir d'utiliser un nom en minuscule.
Balisage (tag)
Pour utiliser l’image conteneur azure-vote-front avec ACR, on doit baliser cette image avec l’adresse du serveur de connexion de votre registre.
Celle ci se trouve dans le retour json précedent : "loginServer": "myacr35.azurecr.io"
Si vous ne l'avez plus, vous pouvez l'obtenir avec la commande suivante :
az acr list --resource-group myResourceGroup --query "[].{acrLoginServer:loginServer}" --output table
À présent, étiquetez votre image azure-vote-front locale avec l’adresse myacr35.azurecr.io (en minuscule) du registre de conteneurs. Pour indiquer la version de l’image, ajoutez :v1 à la fin du nom de l’image :
docker tag azure-vote-front myacr35.azurecr.io/azure-vote-front:v1
PS D:\Kubernetes\AKSText2\azure-voting-app-redis> docker images REPOSITORY TAG IMAGE ID CREATED SIZE azure-vote-front latest df60d4cc1f96 About an hour ago 965MB myacr35.azurecr.io/azure-vote-front v1 df60d4cc1f96 About an hour ago 965MB
On remarque alors qu'une nouvelle image est présente dans la liste (docker image) celle ci étant balisé sur notre serveur distant.
Envoyer l'image
docker push myacr35.azurecr.io/azure-vote-front:v1
On envoit notre image via la commande docker push. Cela peut prendre qq minutes suivant la taille de celle ci. Quand celle ci sera uploadé, on ira vérifier avec cette commande qui liste les images de notre repo de conteneur distant :
> az acr repository list --name myacr35 --output table Result ---------------- azure-vote-front
Notre image est bien sur notre Azure Container Registery myACR35.
3 - Déployer un cluster
az aks create --resource-group myResourceGroup --name myAKSCluster --node-count 2 --generate-ssh-keys --attach-acr myacr35
Cette commande permet la création d'un cluster de 2 nodes branché sur le registre ACR que l'on vient de créer. Vous devriez voir au bout de qq minutes un retour en JSON :
{ "aadProfile": null, "addonProfiles": null, "agentPoolProfiles": [ { "availabilityZones": null, "count": 2, "enableAutoScaling": null, "enableNodePublicIp": null, "maxCount": null, "maxPods": 110, "minCount": null, "name": "nodepool1", "nodeTaints": null, "orchestratorVersion": "1.14.8", "osDiskSizeGb": 100, "osType": "Linux", "provisioningState": "Succeeded", "scaleSetEvictionPolicy": null, "scaleSetPriority": null, "type": "VirtualMachineScaleSets", "vmSize": "Standard_DS2_v2", "vnetSubnetId": null } ], "apiServerAccessProfile": null, "dnsPrefix": "myAKSClust-myResourceGroup-eaeaae", "enablePodSecurityPolicy": null, "enableRbac": true, "fqdn": "myaksclust-myresourcegroup-eaeaae-12f2db23.hcp.eastus.azmk8s.io", "id": "/subscriptions/eaeaae83-9dcd-405b-8f02-4e58e0e30bbb/resourcegroups/myResourceGroup/providers/Microsoft.ContainerService/managedClus ters/myAKSCluster", "identity": null, "kubernetesVersion": "1.14.8", "linuxProfile": { "adminUsername": "azureuser", "ssh": { "publicKeys": [ { "keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxi46MPyNjpH/kBnXxU5t4bPcWpeCrByvAH9p6uzM+IDda+NTrWHpEmUr1IVZS7CXku5lpl6v3WJjuK1 E35DdB5s2ewB7VR6iYKHgruqduAeprMdUx34xeXxn7cc9/QC1b83Lw7k+oyYYYoIfYcy9q/beIlBco8Eidj6GxNRk74fHd3H5r99W0pqA4IfIFpksOb19iiO+pgiABgewmAQETldclaj NjVuV6G3cVDdFILGUXjSA/Z1d1eWoqh00XbtyY7sl3LkLd6puHTm1Qt5UlcD4mZKpI2ggqWicHVLA2Eq2Fz7GE637CdYsqXXs5eDJUeBA8S+d2fas00zMB4Pyb" } ] } }, "location": "eastus", "maxAgentPools": 8, "name": "myAKSCluster", "networkProfile": { "dnsServiceIp": "10.0.0.10", "dockerBridgeCidr": "172.17.0.1/16", "loadBalancerProfile": { "effectiveOutboundIps": [ { "id": "/subscriptions/eaeaae83-9dcd-405b-8f02-4e58e0e30bbb/resourceGroups/MC_myResourceGroup_myAKSCluster_eastus/providers/Microso ft.Network/publicIPAddresses/d2488ce7-add3-4299-9fb3-6443c4f56300", "resourceGroup": "MC_myResourceGroup_myAKSCluster_eastus" } ], "managedOutboundIps": { "count": 1 }, "outboundIpPrefixes": null, "outboundIps": null }, "loadBalancerSku": "Standard", "networkPlugin": "kubenet", "networkPolicy": null, "outboundType": "loadBalancer", "podCidr": "10.244.0.0/16", "serviceCidr": "10.0.0.0/16" }, "nodeResourceGroup": "MC_myResourceGroup_myAKSCluster_eastus", "privateFqdn": null, "provisioningState": "Succeeded", "resourceGroup": "myResourceGroup", "servicePrincipalProfile": { "clientId": "f00bf5fa-37b4-42e5-9f2f-33ff3f32c672", "secret": null }, "tags": null, "type": "Microsoft.ContainerService/ManagedClusters", "windowsProfile": null }
Un petit tour sur le portail web nous informe des ressources qui viennent d'être créé dans un nouveau groupe de resource (automatiquement nommé MC_(...) ):
Dans l'ordre affiché :
- Groupe de sécurité réseau (firewall)
- Table de routage (relie les réseaux privés des nodes)
- Groupe de machines virtuelles identiques (Standard_DS2_v2 (2 instances))
- Réseau virtuel (avec deux IPs privées du sous réseau aks-subnet)
- Adresse IP publique (52.149.255.145) (???)
- Équilibreur de charge (Kubernetes)
- Adresse IP publique (52.146.59.221) (web port 80)
En bas on retrouve notre ACR myACR35 et notre AKS myAKSCluster sur notre groupe de ressource myResourceGroup.
4 - Connexion au cluster
Pour utiliser kubectl (la cli de kubernetes) et se connecter à Kubernetes on va récupérer les informations d'identifiaction via cette commande :
az aks get-credentials --resource-group myResourceGroup --name myAKSCluster
Et pour s'assurer que l'on est bien connecté on va lister nos nodes :
> kubectl get nodes NAME STATUS ROLES AGE VERSION aks-nodepool1-33449556-vmss000000 Ready agent 25m v1.14.8 aks-nodepool1-33449556-vmss000001 Ready agent 25m v1.14.8
Tout va bien on en a bien deux (sur la doc officielle, on en voit qu'une, c'est une erreure de leurs part ou un simple copier coller du précédent tuto).
5 - Déployer une app dans le cluster
Dans la solution du code source cloné de github, on a un fichier à la racine azure-vote-all-in-one-redis.yaml.
Dedans on a une ligne à changer image: microsoft/azure-vote-front:v1
que l'on doit remplacer par notre ACR : image: myacr35.azurecr.io/azure-vote-front:v1
apiVersion: apps/v1beta1 kind: Deployment metadata: name: azure-vote-back spec: replicas: 1 template: metadata: labels: app: azure-vote-back spec: nodeSelector: "beta.kubernetes.io/os": linux containers: - name: azure-vote-back image: redis ports: - containerPort: 6379 name: redis --- apiVersion: v1 kind: Service metadata: name: azure-vote-back spec: ports: - port: 6379 selector: app: azure-vote-back --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: azure-vote-front spec: replicas: 1 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 minReadySeconds: 5 template: metadata: labels: app: azure-vote-front spec: nodeSelector: "beta.kubernetes.io/os": linux containers: - name: azure-vote-front image: myacr35.azurecr.io/azure-vote-front:v1 ports: - containerPort: 80 resources: requests: cpu: 250m limits: cpu: 500m env: - name: REDIS value: "azure-vote-back" --- apiVersion: v1 kind: Service metadata: name: azure-vote-front spec: type: LoadBalancer ports: - port: 80 selector: app: azure-vote-front
Ce fichier indique que l'on souhaite déployer notre backend app web (
azure-vote-back) avec un conteneur Redis port 6379, puis monter un service de ce backend accessible via le port 6379. Ensuite on demande le déploiement du front (
azure-vote-front) via notre image de conteneur stockée sur notre ACR, sur un port 80 avec qq limitation CPU et une variable d'environnement REDIS. Ensuite on indique au port 80 du loadbalancer que l'on souhaite router vers l'instance de conteneur
> kubectl apply -f azure-vote-all-in-one-redis.yaml deployment.apps/azure-vote-back created service/azure-vote-back created deployment.apps/azure-vote-front created service/azure-vote-front created
Quand l’application s’exécute, un service Kubernetes expose le front-end de l’application sur Internet. L’exécution de ce processus peut prendre plusieurs minutes. Pour surveiller la progression :
> kubectl get service azure-vote-front --watch NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE azure-vote-front LoadBalancer 10.0.186.201 52.146.59.221 80:31391/TCP 2m19s
Un petit tour sur le web http://52.146.59.221/ :
6 - Scalling
A présent que l'on a une app qui s'exectute sur Azure avec notre cluster Kubernetes nous allons augmenter le nombre de pods et tenter un scaling automatique.
Scaling manuel
kubectl scale --replicas=5 deployment/azure-vote-front
Cette commande va augmenter le nombre de pods de notre serveur frontal à 5. On peut le vérifier avec cette commande :
> kubectl get pods NAME READY STATUS RESTARTS AGE azure-vote-back-6d4b4776b6-xlgx9 1/1 Running 0 45m azure-vote-front-c9dd6cdf4-5w9fh 1/1 Running 0 45m azure-vote-front-c9dd6cdf4-7dv7r 1/1 Running 0 59s azure-vote-front-c9dd6cdf4-8lf6p 1/1 Running 0 59s azure-vote-front-c9dd6cdf4-jd7t4 1/1 Running 0 59s azure-vote-front-c9dd6cdf4-jtz5b 1/1 Running 0 59s
4 autres pods viennent d'être rajouté.
Scaling auto
A partir de la version 1.10, Kubernetes est livré avec un Metric Server qui collecte des données exposés par les kublets qui se trouvent dans chaque nodes. Il est utilisé pour indiquer l’utilisation des ressources à Kubernetes et est automatiquement déployé dans les clusters AKS versions 1.10 et ultérieures.
Pour utiliser la mise à l’échelle automatique, tous les conteneurs de vos pods et vos pods doivent avoir des demandes et limites de processeur définies. Dans le déploiement azure-vote-front
, le conteneur front-end exige 25% (0.25 ou 250m) de processeur avec une limite de 50% max de CPU. Ces demandes et limites de ressources sont définies comme indiqué dans l’exemple d’extrait suivant :
resources: requests: cpu: 250m limits: cpu: 500m
L’exemple suivant utilise la commande kubectl autoscale pour effectuer un scaling automatique du nombre de pods dans le déploiement azure-vote-front. Si l’utilisation moyenne du processeur sur tous les pods dépasse 50 % de l’utilisation demandée, l’outil de mise à l’échelle automatique (ou « autoscaler ») fait passer le nombre de pods à 10 instances, au maximum. Un minimum de 3 instances est ensuite défini pour le déploiement :
kubectl autoscale deployment azure-vote-front --cpu-percent=50 --min=3 --max=10
Cette opération est appellé "HPA" pour Horizontal Pod Autoscaler. On peut d'ailleurs la demander sous forme de fichier manifest (azure-vote-hpa.yaml):
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: azure-vote-back-hpa spec: maxReplicas: 10 # define max replica count minReplicas: 3 # define min replica count scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: azure-vote-back targetCPUUtilizationPercentage: 50 # target CPU utilization apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: azure-vote-front-hpa spec: maxReplicas: 10 # define max replica count minReplicas: 3 # define min replica count scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: azure-vote-front targetCPUUtilizationPercentage: 50 # target CPU utilization
Il faut maintenant executer la demande avec cette commande :
kubectl apply -f azure-vote-hpa.yaml
Personnellement j'ai une erreur : error: no objects passed to apply
Mais la première étant passé, voici comment vérifier notre action précédente :
> kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE azure-vote-front Deployment/azure-vote-front 0%/50% 3 10 3 12m
Si on attends qq minutes, l'autoscaling s'applique car on passe de 5 pods à 3 comme configurer pour azure-vote-front :
kubectl get pods NAME READY STATUS RESTARTS AGE azure-vote-back-6d4b4776b6-xlgx9 1/1 Running 0 135m azure-vote-front-c9dd6cdf4-5w9fh 1/1 Running 0 135m azure-vote-front-c9dd6cdf4-jd7t4 1/1 Running 0 90m azure-vote-front-c9dd6cdf4-jtz5b 1/1 Running 0 90m
On vient de permettre à Kubernetes de rajouter des pods suivant qq critères et ce automatiquement. C'est du scaling horizontal.
Maintenant on va voir comment rajouter des nodes. C'est toujours du scaling horizontal.
Scaling de nodes
A ce stade nous avons 2 nodes. Passons le à 3 :
az aks scale --resource-group myResourceGroup --name myAKSCluster --node-count 3
Ajouter une node est une opération qui prends un certain temps, ce n'est pas instantané. Quand c'est fait je pense qu'on obtient ceci selon la doc :
"agentPoolProfiles": [ { "count": 3, "dnsPrefix": null, "fqdn": null, "name": "myAKSCluster", "osDiskSizeGb": null, "osType": "Linux", "ports": null, "storageProfile": "ManagedDisks", "vmSize": "Standard_D2_v2", "vnetSubnetId": null }
Je dis je pense car j'ai eu une erreur concernant un quota. Ayant un free trial j'ai pas cherché plus loin.
7 - Mise à jour d'une app
Modification du code source et du conteneur
L'idée est d'aller modifier dans notre code source de l'app front un fichier de conf : azure-voting-app-redis\azure-vote\azure-vote\config_file.cfg
J'ai fait ces modifs :
# UI Configurations TITLE = 'Azure Voting App' VOTE1VALUE = 'Blue' VOTE2VALUE = 'Red' SHOWHOST = 'true'
On re build notre image
docker-compose up --build -d
Et un petit test local pour voir nos modifications : http://localhost:8080
Mise à jour du conteneur localement et sur azure
Super, maintenant que notre image est builder et executer localement dans un conteneur on va l'envoyer sur ACR. Mais avant on va tager notre nouvelle version v2
docker tag azure-vote-front myacr35.azurecr.io/azure-vote-front:v2
puis on se connecte az acr login --name myACR35
et enfin docker push myacr35.azurecr.io/azure-vote-front:v2
En théorie cette opération ne va pas prendre longtemps car docker ne pousse que le contenu modifié, et donc pas besoin d'ajouter ceux non modifié déjà existant. (voir les couches (layer) docker pour plus d'info)
Déployer notre image
La mise à jour se fait via cette commande
kubectl set image deployment azure-vote-front azure-vote-front=myacr35.azurecr.io
/azure-vote-front:v2
L'image ci dessous montre avec la commande kubectl get pods
comment kubernetes gère une mise à jour. Toutes les étapes ne sont pas représentée car j'ai pas été assez rapide ou le timing n'était pas bon. Voici ce qu'il se passe :
Kubernetes ajoute 3 nouveaux pods avec notre mise à jour et va supprimer les anciens quand c'est fait.
On voir des lignes ContainerCreating et Terminating et Running indiquant les états de chacun avec leur "age".
Petit test en ligne sur http://52.146.59.221/
En martelant F5 on peut voir l'id du pod qui gère le site web changer.
8 - Conclusion
Ce tuto de microsoft m'a vraiment aider à appréhender AKS, Kubernetes et Docker. Je me forme depuis 2 semaines sur le sujet et je suis content d'en être arrivé la. Mise à part l'application elle même, on a fait toute les phases intéressantes de la mise en production avec une étape de scaling.
J'ai ommis une dernière étape du tuto qui consiste à mettre à niveau Kubernetes. Je vous laisse le soin d'aller voir.
Donc j'espère que cette expérience puisse servir à d'autre. Merci de laisser un commentaire si c'est le cas !
Source :
https://docs.microsoft.com/fr-fr/azure/aks/tutorial-kubernetes-prepare-app