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

sdgsdf

L'image est très légère. Faut dire que le code aussi.

qsfqsdf.png

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!

qsdfqsdf.png

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_(...) ):

azure ressources

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

azure-vote-front précedenté (monté sur 80 aussi). 6379:6379 et 80:80 sont donc les mappages de port entre host et conteneur.
Notez que l'on a qu'une seule réplique de nos instances. On verra cela dans une prochaine section.
> 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/ :

qsdfqsdfqsfsq.png

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

qdfqs.png

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

kbectl set image.png

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/

sdgfqsdf.png

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

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée Champs requis marqués avec *

Poster commentaire