Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
elearning:workbooks:kubernetes:k8s09 [2024/02/21 13:04] adminelearning:workbooks:kubernetes:k8s09 [2024/12/20 13:54] (Version actuelle) admin
Ligne 1: Ligne 1:
 +~~PDF:LANDSCAPE~~
  
 +Version - **2024.01**
 +
 +Dernière mise-à-jour : ~~LASTMOD~~
 +
 +
 +======DOF310 - StatefulSets, StorageClass Avancé, Helm Avancé et Monitoring======
 +
 +=====Contenu du Module=====
 +
 +  * **DOF310 - StatefulSets, StorageClass Avancé, Helm Avancé et Monitoring**
 +    * Contenu du Module
 +    * StatefulSets
 +      * LAB #1 - Mise en Place d'un StatefulSet Simple
 +        * 1.1 - Création du Service et du StatefulSet
 +        * 1.2 - Mise en Place d'un Scale Up
 +        * 1.3 - Mise en Place d'un Scale Down
 +        * 1.4 - Suppression du StatefulSet
 +    * StorageClass Avancé
 +      * LAB #2 - Provisionnement NFS dynamique
 +        * 2.1 - Configuration du Serveur NFS
 +        * 2.2 - Configuration des Clients NFS
 +        * 2.3 - Configuration de K8s
 +        * 2.4 - Création d'un PersistentVolumeClaim
 +        * 2.5 - Utilisation du PersistentVolumeClaim avec un pod
 +        * 2.6 - Création d'un Deuxième PersistentVolumeClaim
 +        * 2.7 - Suppression des PersistentVolumeClaims
 +    * Helm Avancé
 +      * LAB #3 - Création d'un Paquet Helm Simple
 +        * 3.1 - Le Fichier values.yaml
 +        * 3.2 - Les Templates
 +        * 3.3 - Installation et Suppression
 +    * Monitoring
 +      * LAB #4 - Mise en Place d'une Solution Prometheus
 +        * 4.1 - Déploiement du Stack avec Helm
 +        * 4.2 - Consultation des Données avec Grafana
 +        * 4.3 - Consultation des Alertes avec le Web UI de Prometheus 
 +
 +=====Ressources=====
 +
 +====Lab #1====
 +
 +  * https://www.dropbox.com/scl/fi/xqqpanbovwrx7cknd0yam/quarkus-service.yaml?rlkey=buou4viy128u7cgxapwmpetpl&dl=0
 +  * https://www.dropbox.com/scl/fi/zqrdnfhcxuzcfftgbokx6/statefulset.yaml?rlkey=tqs0xxdlxjlukv30crwy2gll1&dl=0
 +
 +====Lab #2====
 +
 +  * https://www.dropbox.com/scl/fi/rk3xnorqu6gk6tstvlivz/pvc.yaml?rlkey=g1dr28lrs6ec6iejp07q2o4jf&dl=0
 +  * https://www.dropbox.com/scl/fi/1rjljxupug5wra2zpu84n/nfs-busybox.yaml?rlkey=yta13fyr2rh6a6dmsnjl10p7b&dl=0
 +  * https://www.dropbox.com/scl/fi/b2ocglzuqbadnnyzipfyc/pvc2.yaml?rlkey=xxc7wz3pwdo4ybfqa54zav63z&dl=0
 +
 +====Lab #3====
 +
 +  * https://www.dropbox.com/scl/fi/0d5znog6rdou1doko43yy/ghost.yaml?rlkey=hebkdn9ch0v9nctimiayondwc&dl=0
 +  * https://www.dropbox.com/scl/fi/m6fmpsz25lqugzqfqxpdt/ghost-service.yaml?rlkey=zyxh7ep17eujbuycddqjdsrqy&dl=0
 +  * https://www.dropbox.com/scl/fi/zot4i0u0hf4yw2yj3kyey/values.yaml?rlkey=apv0grxwvomxa9c0avig87pzy&dl=0
 +  * https://www.dropbox.com/scl/fi/zyf0mbbp3wuwnnfzzez3a/service.yaml?rlkey=47bpjs3f6u474f8v0tiunl3am&dl=0
 +  * https://www.dropbox.com/scl/fi/kark41xnz5hlilag5on0y/ghost-values.yaml?rlkey=fohccb7rwc8z66qhn4heyn2lj&dl=0
 +
 +=====StatefulSets=====
 +
 +Un StatefulSet est un composant de Kubernetes qui est utilisé pour des applications avec état (//Stateful Applications//).
 +
 +Des exemples d'applications avec état sont :
 +
 +  * MySQL
 +  * elasticsearch
 +  * mongoDB
 +
 +Ces applications enregistrent les données client des activités d'une session pour les utiliser lors de la session suivante. Les données enregistrées sont appelées l'état de l'application.
 +
 +Les applications avec état sont déployées en utilisant un StatefulSet tandis que des applications **sans** état sont déployées en utilisant un **Deployment**.
 +
 +Les StatefulSets et les Deployments sont similaires dans la mesure où les deux répliquent de multiples pods basés sur une spécification **identique** d'un conteneur.
 +
 +La différence entre un StatefulSet et un Deployment est que dans un StatefulSet les pods ne sont **pas** identiques et possèdent ce que l'on appelle un **Pod Identity**. De ce fait les pods :
 +
 +  * ne peuvent pas être créés ou supprimés en même temps,
 +  * ne peuvent pas être adressés d'une manière aléatoire.
 +
 +Prenons le cas d'un StatfulSet contenant trois répliques d'un pod MySQL :
 +
 +  * mysql-0
 +  * mysql-1
 +  * mysql-2
 +
 +Notez que :
 +
 +  * le nom du pod prend la forme **$(Nom_du_StatefulSet)-$(ordinal)** où l'ordinal commence à **0**
 +  * le StatefulSet ne créera pas le pod suivant tant que le pod précédent n'est pas dans un état de **Running**
 +  * dans le cas de la suppression du StatefulSet ou bien dans le cas d'un **scale down**, les pods sont supprimés dans l'ordre inverse de leur création, par exemple **mysql-2 > mysql-1 > mysql-0**. Chaque pod doit être complètement supprimé avant que K8s procède à la suppression du suivant
 +
 +Dans ce cas de notre StatefulSet, les trois pods :
 +
 +  * ne peuvent pas tous accepter des requêtes d'écriture car ceci donnerait des données incohérentes,
 +  * peuvent tous accepter des requêtes de lecture.
 +
 +De ce fait, un mécanisme du StatefulSet choisit un **maître** pour accepter des requêtes d'écriture, par exemple :
 +
 +  * mysql-0 - écriture / lecture - **Maître**
 +  * mysql-1 - lecture seulement - **Esclave**
 +  * mysql-2 - lecture seulement - **Esclave**
 +
 +Il existe donc une différence précise entre le pod Maître et les deux pods Esclaves.
 +
 +La différence entre les deux pods Esclaves s'expliquent par le fait que les pods n'utilisent **pas** le même stockage physique persistant et distant :
 +
 +  * mysql-0 - **/data/vol/pv1**
 +  * mysql-1 - **/data/vol/pv2**
 +  * mysql-2 - **/data/vol/pv3**
 +
 +De façon à ce que chaque pod contient les mêmes données, un mecanisme de réplication en continu doit être mis en place entre les deux pods Esclaves et le pod Maître.
 +
 +Dans le cas où un nouveau pod est ajouté au **cluster** MySQL, celui-ci doit commencer par cloner les données du dernier pod dans le cluster existant, puis il doit commencer la réplication des données avec le Maître :
 +
 +  * mysql-0 - données
 +  * mysql-1 - données répliquées de mysql-0
 +  * mysql-2 - données répliquées de mysql-0
 +  * mysql-3 - clone des données du pod mysql-2 puis, par la suite, données répliquées de mysql-0 
 +
 +L'état de chaque pod, incluant sa Pod Identity, est stocké dans le stockage physique à côté des données. De ce fait, quand un pod est remplacé, et un nouveau pod ajouté, ce pod nouveau hérite de l'identité de l'ancien pod.
 +
 +Par exemple, si on supprime le pod **mysql-1**, on obtient : 
 +
 +  * mysql-0 - /data/vol/pv1
 +  * pod supprimé - /data/vol/pv2 = stockage physique persistant et distant **non-supprimé**
 +  * mysql-2 - /data/vol/pv3
 +  * mysql-3 - /data/vol/pv4
 +
 +En ajoutant un pod de remplaceement, on obtient :
 +
 +  * mysql-0
 +  * mysql-1 <<<<<<<<<< Le /data/vol/pv2 est rattaché au pod. Le nouveau pod s'appelle **mysql-1** et non **mysql-4**. 
 +  * mysql-2
 +  * mysql-3
 +
 +Lors de la création d'un ReplicaSet, un service d'équilibrage de charge est créé. Ce service attribue un **Endpoint DNS** unique à chaque pod. L'Endpoint DNS prend la forme **$(Nom_du_pod).$(Nom_du_service).$(namespace).svc.cluster.local
 +** :
 +
 +  * mysql-0 - **mysql-0.mysvc.default.svc.cluster.local**
 +  * mysql-1 - **mysql-1.mysvc.default.svc.cluster.local**
 +  * mysql-2 - **mysql-2.mysvc.default.svc.cluster.local**
 +  * mysql-3 - **mysql-3.mysvc.default.svc.cluster.local**
 +
 +De cette façon, quand un pod est redémarré bien que son adresse IP changera :
 +
 +  * son nom ne changera **pas**
 +  * son Endpoint DNS ne changera **pas**
 +
 +Pour résumer :
 +
 +  * mysql-0
 +    * Rôle : **Maître**
 +    * Données : écriture / lecture
 +    * Stockage : /data/vol/pv1
 +    * Endpoint DNS : mysql-0..mysvc.default.svc.cluster.local
 +  * mysql-1
 +    * Rôle : **Esclave**
 +    * Données : lecture seulement
 +    * Stockage : /data/vol/pv2
 +    * Endpoint DNS : mysql-1.mysvc.default.svc.cluster.local
 +  * mysql-2
 +    * Rôle : **Esclave**
 +    * Données : lecture seulement
 +    * Stockage : /data/vol/pv3
 +    * Endpoint DNS : mysql-2.mysvc.default.svc.cluster.local
 +  * mysql-3
 +    * Rôle : **Esclave**
 +    * Données : lecture seulement
 +    * Stockage : /data/vol/pv4
 +    * Endpoint DNS : mysql-3.mysvc.default.svc.cluster.local
 +
 +Dernièrement, un StatefulSet est un composant K8s **compliqué** et difficile à mettre en oeuvre car Kubernetes ne s'occupe pas de certaines tâches telles :
 +
 +  * la configuration du clonage des données
 +  * la configuration de la réplication des données
 +  * la création et la configuration du stockage physique persistant et distant
 +  * la configuration et la gestion des sauvegardes des données
 +
 +====LAB #1 - Mise en Place d'un StatefulSet Simple====
 +
 +Créez un Namespace **quarkus** puis modifiez le **context** de **kubernetes-admin@kubernetes** :
 +
 +<code>
 +root@kubemaster:~# kubectl create ns quarkus
 +namespace/quarkus created
 +
 +root@kubemaster:~# kubectl config set-context --current --namespace=quarkus
 +Context "kubernetes-admin@kubernetes" modified.
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Quarkus est un framework Java natif pour Kubernetes complet, conçu pour les machines virtuelles Java (JVM) et la compilation native, qui permet d'optimiser Java spécifiquement pour les conteneurs afin d'en faire une plateforme efficace pour les environnements serverless, cloud et Kubernetes.
 +</WRAP>
 +
 +Si vous souhaitez observer les résultats des commandes suivantes en temps réel, ouvrez un deuxième terminal et saisissez la commande suivante :
 +
 +<code>
 +root@kubemaster:~# watch -n 1 "kubectl get pods -o wide | awk '{print \$1 \" \" \$2 \" \" \$3 \" \" \$5 \" \" \$7}' | column -t"
 +</code>
 +
 +===1.1 - Création du Service et du StatefulSet===
 +
 +Créez maintenant le fichier **quarkus-service.yaml** :
 +
 +<code>
 +root@kubemaster:~# vi quarkus-service.yaml
 +root@kubemaster:~# cat quarkus-service.yaml
 +apiVersion: v1
 +kind: Service
 +metadata:
 +  name: quarkus 
 +  labels:
 +    app: quarkus-statefulset
 +spec:
 +  ports:
 +  - port: 8080
 +    name: web
 +  clusterIP: None 
 +  selector:
 +    app: quarkus-statefulset
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez le nom du service - **quarkus**. La valeur **None** de l'entrée **ClusterIP** rend le service **headless**. Dans ce cas, le serveur DNS renverra les adresses IP des pods individuels au lieu de l'adresse IP du service. Le client peut alors se connecter à n'importe lequel d'entre eux.
 +</WRAP>
 +
 +Créez le service :
 +
 +<code>
 +root@kubemaster:~# kubectl apply -f quarkus-service.yaml
 +service/quarkus created
 +</code>
 +
 +Créez maintenant le fichier **statefulset.yaml** :
 +
 +<code>
 +root@kubemaster:~# vi statefulset.yaml
 +root@kubemaster:~# cat statefulset.yaml 
 +apiVersion: apps/v1
 +kind: StatefulSet
 +metadata:
 +  name: quarkus-statefulset
 +  labels:
 +    app: quarkus-statefulset
 +spec:
 +  serviceName: "quarkus" 
 +  replicas: 2
 +  template:
 +    metadata:
 +      labels:
 +        app: quarkus-statefulset
 +    spec:
 +      containers:
 +      - name: quarkus-statefulset
 +        image: quay.io/rhdevelopers/quarkus-demo:v1
 +        ports:
 +        - containerPort: 8080
 +          name: web
 +  selector:
 +    matchLabels:
 +      app: quarkus-statefulset
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez que la valeur de **serviceName** est **quarkus**.
 +</WRAP>
 +
 +Créez le StatefulSet :
 +
 +<code>
 +root@kubemaster:~# kubectl apply -f statefulset.yaml
 +statefulset.apps/quarkus-statefulset created
 +</code>
 +
 +Constatez la présence des deux pods dans le Namespace :
 +
 +<code>
 +Every 1,0s: kubectl get pods -o wide | awk '{print $1 " " $2 " " $3 " " $5 " " $7}' | column -t                                                                kubemaster.ittraining.loc: Tue Dec  6 17:43:50 2022
 +
 +NAME                   READY  STATUS   AGE    NODE
 +quarkus-statefulset-0  1/1    Running  2m17s  kubenode2.ittraining.loc
 +quarkus-statefulset-1  1/1    Running  106s   kubenode1.ittraining.loc
 +</code>
 +
 +Contrôlez l'état du StatefulSet :
 +
 +<code>
 +root@kubemaster:~# kubectl get statefulsets
 +NAME                  READY   AGE
 +quarkus-statefulset   2/    3m35s
 +</code>
 +
 +ainsi que la présence du service :
 +
 +<code>
 +root@kubemaster:~# kubectl get services
 +NAME      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
 +quarkus   ClusterIP   None         <none>        8080/TCP   12m
 +</code>
 +
 +===1.2 - Mise en Place d'un Scale Up===
 +
 +Procédez à un scale up :
 +
 +<code>
 +root@kubemaster:~# kubectl scale sts quarkus-statefulset --replicas=3
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez que le nom court d'un **serviceName** est **sts**.
 +</WRAP>
 +
 +Constatez la présence des **trois** pods dans le Namespace :
 +
 +<code>
 +Every 1,0s: kubectl get pods -o wide | awk '{print $1 " " $2 " " $3 " " $5 " " $7}' | column -t                                                                kubemaster.ittraining.loc: Tue Dec  6 17:46:42 2022
 +
 +NAME                   READY  STATUS   AGE    NODE
 +quarkus-statefulset-0  1/1    Running  5m9s   kubenode2.ittraining.loc
 +quarkus-statefulset-1  1/1    Running  4m38s  kubenode1.ittraining.loc
 +quarkus-statefulset-2  1/1    Running  13s    kubenode2.ittraining.loc
 +</code>
 +
 +Constatez l'ordre de création des pods :
 +
 +<code>
 +root@kubemaster:~# kubectl get events --sort-by=.metadata.creationTimestamp
 +LAST SEEN   TYPE     REASON             OBJECT                            MESSAGE
 +6m35s       Normal   SuccessfulCreate   statefulset/quarkus-statefulset   create Pod quarkus-statefulset-0 in StatefulSet quarkus-statefulset successful
 +6m35s       Normal   Scheduled          pod/quarkus-statefulset-0         Successfully assigned quarkus/quarkus-statefulset-0 to kubenode2.ittraining.loc
 +6m34s       Normal   Pulling            pod/quarkus-statefulset-0         Pulling image "quay.io/rhdevelopers/quarkus-demo:v1"
 +6m5s        Normal   Pulled             pod/quarkus-statefulset-0         Successfully pulled image "quay.io/rhdevelopers/quarkus-demo:v1" in 28.871622372s
 +6m4s        Normal   Created            pod/quarkus-statefulset-0         Created container quarkus-statefulset
 +6m4s        Normal   Started            pod/quarkus-statefulset-0         Started container quarkus-statefulset
 +6m3s        Normal   Scheduled          pod/quarkus-statefulset-1         Successfully assigned quarkus/quarkus-statefulset-1 to kubenode1.ittraining.loc
 +6m3s        Normal   SuccessfulCreate   statefulset/quarkus-statefulset   create Pod quarkus-statefulset-1 in StatefulSet quarkus-statefulset successful
 +5m58s       Normal   Pulling            pod/quarkus-statefulset-1         Pulling image "quay.io/rhdevelopers/quarkus-demo:v1"
 +5m22s       Normal   Pulled             pod/quarkus-statefulset-1         Successfully pulled image "quay.io/rhdevelopers/quarkus-demo:v1" in 35.551473165s
 +5m21s       Normal   Created            pod/quarkus-statefulset-1         Created container quarkus-statefulset
 +5m21s       Normal   Started            pod/quarkus-statefulset-1         Started container quarkus-statefulset
 +99s         Normal   Scheduled          pod/quarkus-statefulset-2         Successfully assigned quarkus/quarkus-statefulset-2 to kubenode2.ittraining.loc
 +99s         Normal   SuccessfulCreate   statefulset/quarkus-statefulset   create Pod quarkus-statefulset-2 in StatefulSet quarkus-statefulset successful
 +98s         Normal   Pulled             pod/quarkus-statefulset-2         Container image "quay.io/rhdevelopers/quarkus-demo:v1" already present on machine
 +97s         Normal   Created            pod/quarkus-statefulset-2         Created container quarkus-statefulset
 +97s         Normal   Started            pod/quarkus-statefulset-2         Started container quarkus-statefulset
 +</code>
 +
 +Créez maintenant un pod pour interroger le DNS de K8s :
 +
 +<code>
 +root@kubemaster:~# kubectl run -it --restart=Never --rm --image busybox:1.28 dns-test
 +If you don't see a command prompt, try pressing enter.
 +/ # nslookup quarkus-statefulset-0.quarkus
 +Server:    10.96.0.10
 +Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
 +
 +Name:      quarkus-statefulset-0.quarkus
 +Address 1: 192.168.150.2 quarkus-statefulset-0.quarkus.quarkus.svc.cluster.local
 +/ # exit
 +pod "dns-test" deleted
 +root@kubemaster:~#
 +</code>
 +
 +===1.3 - Mise en Place d'un Scale Down===
 +
 +Procédez maintenant à un scale down :
 +
 +<code>
 +root@kubemaster:~# kubectl scale sts quarkus-statefulset --replicas=2
 +statefulset.apps/quarkus-statefulset scaled
 +</code>
 +
 +Constatez la présence de **deux** pods dans le Namespace :
 +
 +<code>
 +Every 1,0s: kubectl get pods -o wide | awk '{print $1 " " $2 " " $3 " " $5 " " $7}' | column -t                                                                kubemaster.ittraining.loc: Tue Dec  6 18:02:27 2022
 +
 +NAME                   READY  STATUS   AGE  NODE
 +quarkus-statefulset-0  1/1    Running  20m  kubenode2.ittraining.loc
 +quarkus-statefulset-1  1/1    Running  20m  kubenode1.ittraining.loc
 +</code>
 +
 +===1.4 - Suppression du StatefulSet===
 +
 +Pour terminer, supprimez le StatefulSet, le service et le Namespace :
 +
 +<code>
 +root@kubemaster:~# kubectl delete -f statefulset.yaml 
 +statefulset.apps "quarkus-statefulset" deleted
 +
 +root@kubemaster:~# kubectl delete -f quarkus-service.yaml 
 +service "quarkus-statefulset-2" deleted
 +
 +root@kubemaster:~# kubectl config set-context --current --namespace=default
 +Context "kubernetes-admin@kubernetes" modified.
 +</code>
 +
 +=====StorageClass Avancé=====
 +
 +====LAB #2 - Provisionnement NFS dynamique====
 +
 +===2.1 - Configuration du Serveur NFS===
 +
 +Connectez-vous à la VM CentOS8 en tant que trainee au 10.0.2.45.
 +
 +Devenez root puis créez le répertoire **/srv/nfs/kubedata** :
 +
 +<code>
 +[root@centos8 ~]# mkdir -p /srv/nfs/kubedata
 +</code>
 +
 +Continuez maintenant par activer et démarrer le service **nfs-server** :
 +
 +<code>
 +[root@centos8 ~]# systemctl status nfs-server
 +● nfs-server.service - NFS server and services
 +   Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; disabled; vendor prese>
 +   Active: inactive (dead)
 +
 +[root@centos8 ~]# systemctl enable nfs-server.service
 +Created symlink /etc/systemd/system/multi-user.target.wants/nfs-server.service → /usr/lib/systemd/system/nfs-server.service.
 +
 +[root@centos8 ~]# systemctl start nfs-server.service
 +
 +[root@centos8 ~]# systemctl status nfs-server.service
 +● nfs-server.service - NFS server and services
 +   Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
 +   Active: active (exited) since Mon 2022-11-21 11:02:13 CET; 9s ago
 +  Process: 3276 ExecStart=/bin/sh -c if systemctl -q is-active gssproxy; then systemctl reload gssproxy ; fi (code=exited, >
 +  Process: 3263 ExecStart=/usr/sbin/rpc.nfsd (code=exited, status=0/SUCCESS)
 +  Process: 3261 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
 + Main PID: 3276 (code=exited, status=0/SUCCESS)
 +
 +Nov 21 11:02:12 centos8.ittraining.loc systemd[1]: Starting NFS server and services...
 +Nov 21 11:02:13 centos8.ittraining.loc systemd[1]: Started NFS server and services.
 +</code>
 +
 +Editez le fichier **/etc/exports** :
 +
 +<code>
 +[root@centos8 ~]# vi /etc/exports
 +[root@centos8 ~]# cat /etc/exports
 +/srv/nfs/kubedata       *(rw,sync,no_subtree_check,no_root_squash,no_all_squash,insecure)
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Dans ce cas, nous avons partagé le répertoire **/srv/nfs/kubedata** avec le monde.
 +</WRAP>
 +
 +Appliquez l'export :
 +
 +<code>
 +[root@centos8 ~]# exportfs -rav
 +exporting *:/srv/nfs/kubedata
 +
 +[root@centos8 ~]# exportfs -v
 +/srv/nfs/kubedata
 +                <world>(sync,wdelay,hide,no_subtree_check,sec=sys,rw,insecure,no_root_squash,no_all_squash)
 +</code>
 +
 +Passez SELinux en mode permissive :
 +
 +<code>
 +[root@centos8 ~]# getenforce
 +Enforcing
 +
 +[root@centos8 ~]# setenforce permissive
 +
 +</code>
 +
 +Configurez ensuite le pare-feu :
 +
 +<code> 
 +[root@centos8 ~]# firewall-cmd --permanent --add-service=nfs
 +success
 +[root@centos8 ~]# firewall-cmd --permanent --add-service=rpc-bind
 +success
 +[root@centos8 ~]# firewall-cmd --permanent --add-service=mountd
 +success
 +[root@centos8 ~]# firewall-cmd --reload
 +success
 +</code>
 +
 +===2.2 - Configuration des Clients NFS===
 +
 +Revenez à votre gateway et connectez-vous en tant que l'utilisateur **trainee** à **kubenode2** au 192.168.56.4. Devenez ensuite l'utilisateur root :
 +
 +<code>
 +trainee@kubenode2:~$ su -
 +Mot de passe : fenestros
 +root@kubenode2:~#
 +</code>
 +
 +Installez le paquet **nfs-common** :
 +
 +<code>
 +root@kubenode2:~# apt update
 +...
 +
 +root@kubenode2:~# apt install nfs-common
 +...
 +</code>
 +
 +Vérifiez que vous pouvez voir le répertoire exporté par le 10.0.2.45 :
 +
 +<code>
 +root@kubenode2:~# showmount --exports 10.0.2.45
 +Export list for 10.0.2.45:
 +/srv/nfs/kubedata *
 +</code>
 +
 +Vérifiez que vous pouvez monter le répertoire exporté par le 10.0.2.45 :
 +
 +<code>
 +root@kubenode2:~# mount -t nfs 10.0.2.45:/srv/nfs/kubedata /mnt
 +root@kubenode2:~# mount | grep kubedata
 +10.0.2.45:/srv/nfs/kubedata on /mnt type nfs4 (rw,relatime,vers=4.2,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=10.0.2.67,local_lock=none,addr=10.0.2.45)
 +</code>
 +
 +Démontez ensuite **10.0.2.45:/srv/nfs/kubedata** :
 +
 +<code>
 +root@kubenode2:~# umount /mnt
 +
 +root@kubenode2:~# mount | grep kubedata
 +</code>
 +
 +Connectez-vous à kubenode1 au 192.168.56.3 :
 +
 +<code>
 +root@kubenode2:~# ssh -l trainee 192.168.56.3
 +The authenticity of host '192.168.56.3 (192.168.56.3)' can't be established.
 +ECDSA key fingerprint is SHA256:sEfHBv9azmK60cjqF/aJgUc9jg56slNaZQdAUcvBOvE.
 +Are you sure you want to continue connecting (yes/no)? yes
 +Warning: Permanently added '192.168.56.3' (ECDSA) to the list of known hosts.
 +trainee@192.168.56.3's password: trainee
 +Linux kubenode1.ittraining.loc 4.9.0-19-amd64 #1 SMP Debian 4.9.320-2 (2022-06-30) x86_64
 +
 +The programs included with the Debian GNU/Linux system are free software;
 +the exact distribution terms for each program are described in the
 +individual files in /usr/share/doc/*/copyright.
 +
 +Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
 +permitted by applicable law.
 +Last login: Wed Sep 28 09:54:21 2022 from 192.168.56.2
 +trainee@kubenode1:~$ su -
 +Mot de passe : fenestros
 +root@kubenode1:~# 
 +</code>
 +
 +Installez ensuite le paquet **nfs-common** :
 +
 +<code>
 +root@kubenode1:~# apt update
 +...
 +
 +root@kubenode1:~# apt install nfs-common
 +...
 +</code>
 +
 +Revenez à votre gateway :
 +
 +<code>
 +root@kubenode1:~# exit
 +déconnexion
 +trainee@kubenode1:~$ exit
 +déconnexion
 +Connection to 192.168.56.3 closed.
 +root@kubenode2:~# exit
 +déconnexion
 +trainee@kubenode2:~$ exit
 +déconnexion
 +Connection to 192.168.56.4 closed.
 +</code>
 +
 +===2.3 - Configuration de K8s===
 +
 +Connectez-vous à votre **kubemaster** au 192.168.56.2.
 +
 +Installez ensuite le paquet **nfs-common** :
 +
 +<code>
 +root@kubemaster:~# apt update
 +...
 +
 +root@kubemaster:~# apt install nfs-common
 +...
 +</code>
 +
 +Ajoutez le dépôt **nfs-subdir-external-provisioner** à **helm** :
 +
 +<code>
 +root@kubemaster:~# helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
 +"nfs-subdir-external-provisioner" has been added to your repositories
 +</code>
 +
 +Installez le chart helm **nfs-subdir-external-provisioner** :
 +
 +<code>
 +root@kubemaster:~# helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --set nfs.server=10.0.2.45 --set nfs.path=/srv/nfs/kubedata
 +NAME: nfs-subdir-external-provisioner
 +LAST DEPLOYED: Wed Dec  7 11:12:23 2022
 +NAMESPACE: default
 +STATUS: deployed
 +REVISION: 1
 +TEST SUITE: None
 +</code>
 +
 +Contrôlez l'état du pod créé :
 +
 +<code>
 +root@kubemaster:~# kubectl get pods -o wide
 +NAME                                               READY   STATUS              RESTARTS      AGE   IP               NODE                       NOMINATED NODE   READINESS GATES
 +netshoot                                           1/    Running             3 (25h ago)   70d   192.168.239.58   kubenode1.ittraining.loc   <none>           <none>
 +nfs-subdir-external-provisioner-59b4b5c476-wxkp4   0/    ContainerCreating               19m   <none>           kubenode1.ittraining.loc   <none>           <none>
 +nginx-netshoot                                     1/    Running             3 (25h ago)   70d   192.168.239.59   kubenode1.ittraining.loc   <none>           <none>
 +postgresql-6f885d8957-tnlbb                        1/1     Running             3 (25h ago)   70d   192.168.239.62   kubenode1.ittraining.loc   <none>           <none>
 +sharedvolume                                       2/    Running             6 (25h ago)   78d   192.168.150.60   kubenode2.ittraining.loc   <none>           <none>
 +troubleshooting                                    1/1     Running             3 (25h ago)   70d   192.168.239.60   kubenode1.ittraining.loc   <none>           <none>
 +volumepod                                          0/1     Completed                       78d   192.168.150.41   kubenode2.ittraining.loc   <none>           <none>
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Si le pod **nfs-subdir-external-provisioner-yyyyyyyyyy-xxxxx** reste dans un état de **ContainerCreating** pour plus de 5 minutes, supprimez les trois pods **calico-node-xxxxx** du Namespace **kube-system** et attendez qu'ils soient recréés.
 +</WRAP>
 +
 +Une fois recréés, vous pouvez constater que le pod **nfs-subdir-external-provisioner-yyyyyyyyyy-xxxxx** est dans un état de Running :
 +
 +<code>
 +root@kubemaster:~# kubectl get pods -o wide
 +NAMESPACE          NAME                                                READY   STATUS      RESTARTS         AGE     IP               NODE                        NOMINATED NODE   READINESS GATES
 +default            netshoot                                            1/1     Running     3 (25h ago)      70d     192.168.239.58   kubenode1.ittraining.loc    <none>           <none>
 +default            nfs-subdir-external-provisioner-59b4b5c476-wxkp4    1/1     Running     1 (3m18s ago)    36m     192.168.239.63   kubenode1.ittraining.loc    <none>           <none>
 +default            nginx-netshoot                                      1/1     Running     3 (25h ago)      70d     192.168.239.59   kubenode1.ittraining.loc    <none>           <none>
 +default            postgresql-6f885d8957-tnlbb                         1/    Running     3 (25h ago)      70d     192.168.239.62   kubenode1.ittraining.loc    <none>           <none>
 +default            sharedvolume                                        2/2     Running     6 (25h ago)      78d     192.168.150.60   kubenode2.ittraining.loc    <none>           <none>
 +default            troubleshooting                                     1/    Running     3 (25h ago)      70d     192.168.239.60   kubenode1.ittraining.loc    <none>           <none>
 +default            volumepod                                           0/    Completed                  78d     192.168.150.41   kubenode2.ittraining.loc    <none>           <none>
 +</code>
 +
 +L'examen du log du pod **nfs-subdir-external-provisioner-yyyyyyyyyy-xxxxx** démontre que tout fonctionne :
 +
 +<code>
 +root@kubemaster:~# kubectl logs nfs-subdir-external-provisioner-59b4b5c476-wxkp4
 +I1207 10:45:38.321263       1 leaderelection.go:242] attempting to acquire leader lease  default/cluster.local-nfs-subdir-external-provisioner...
 +I1207 10:45:59.097918       1 leaderelection.go:252] successfully acquired lease default/cluster.local-nfs-subdir-external-provisioner
 +I1207 10:45:59.097979       1 event.go:278] Event(v1.ObjectReference{Kind:"Endpoints", Namespace:"default", Name:"cluster.local-nfs-subdir-external-provisioner", UID:"986e4938-a054-4bf9-bfdd-903749c7f63f", APIVersion:"v1", ResourceVersion:"6690493", FieldPath:""}): type: 'Normal' reason: 'LeaderElection' nfs-subdir-external-provisioner-59b4b5c476-wxkp4_1d17de3a-ac5b-442c-aa63-8253d33c2857 became leader
 +I1207 10:45:59.098098       1 controller.go:820] Starting provisioner controller cluster.local/nfs-subdir-external-provisioner_nfs-subdir-external-provisioner-59b4b5c476-wxkp4_1d17de3a-ac5b-442c-aa63-8253d33c2857!
 +I1207 10:45:59.198332       1 controller.go:869] Started provisioner controller cluster.local/nfs-subdir-external-provisioner_nfs-subdir-external-provisioner-59b4b5c476-wxkp4_1d17de3a-ac5b-442c-aa63-8253d33c2857!
 +</code>
 +
 +Consultez maintenant la liste des StorageClasses :
 +
 +<code>
 +root@kubemaster:~# kubectl get storageclass
 +NAME         PROVISIONER                                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
 +localdisk    kubernetes.io/no-provisioner                    Delete          Immediate           true                   77d
 +nfs-client   cluster.local/nfs-subdir-external-provisioner   Delete          Immediate           true                   52m
 +</code>
 +
 +===2.4 - Création d'un PersistentVolumeClaim===
 +
 +Créez maintenant le fichier **pvc.yaml** : 
 +
 +<code>
 +root@kubemaster:~# vi pvc.yaml
 +root@kubemaster:~# cat pvc.yaml
 +apiVersion: v1
 +kind: PersistentVolumeClaim
 +metadata:
 +  name: pvc1
 +spec:
 +  storageClassName: nfs-client 
 +  accessModes:
 +    - ReadWriteMany
 +  resources:
 +    requests:
 +      storage: 500Mi
 +</code>
 +
 +Appliquez le fichier pvc.yaml :
 +
 +<code>
 +root@kubemaster:~# kubectl apply -f pvc.yaml 
 +persistentvolumeclaim/pvc1 created
 +</code>
 +
 +Constatez maintenant la liste de PersistentVolumes et de PersistentVolumeClaims :
 +
 +<code>
 +root@kubemaster:~# kubectl get pv,pvc
 +NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM          STORAGECLASS   REASON   AGE
 +persistentvolume/mypv                                       1Gi        RWO            Recycle          Available                  localdisk               77d
 +persistentvolume/pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da   500Mi      RWX            Delete           Bound       default/pvc1   nfs-client              66s
 +
 +NAME                         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
 +persistentvolumeclaim/pvc1   Bound    pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da   500Mi      RWX            nfs-client     67s
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez que le PersistentVolume **persistentvolume/pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da** a été créé automatiquement.
 +</WRAP>
 +
 +Connectez-vous au serveur NFS et constatez le contenu du répertoire **/srv/nfs/kubedata** :
 +
 +<code>
 +root@kubemaster:~# ssh -l trainee 10.0.2.45
 +The authenticity of host '10.0.2.45 (10.0.2.45)' can't be established.
 +ECDSA key fingerprint is SHA256:Q7T/CP0SLiMbMAIgVzTuEHegYS/spPE5zzQchCHD5Vw.
 +Are you sure you want to continue connecting (yes/no)? yes
 +Warning: Permanently added '10.0.2.45' (ECDSA) to the list of known hosts.
 +trainee@10.0.2.45's password: trainee
 +Activate the web console with: systemctl enable --now cockpit.socket
 +
 +Last login: Wed Dec  7 10:34:25 2022 from 10.0.2.65
 +
 +[trainee@centos8 ~]$ ls -l /srv/nfs/kubedata/
 +total 0
 +drwxrwxrwx. 2 root root 6 Dec  7 12:32 default-pvc1-pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da
 +[trainee@centos8 ~]$ exit
 +logout
 +Connection to 10.0.2.45 closed.
 +</code>
 +
 +===2.5 - Utilisation du PersistentVolumeClaim avec un pod===
 +
 +Créez maintenant le fichier **nfs-busybox.yaml** :
 +
 +<code>
 +root@kubemaster:~# vi nfs-busybox.yaml
 +root@kubemaster:~# cat nfs-busybox.yaml
 +apiVersion: v1
 +kind: Pod
 +metadata:
 +  name: nfs-pv-pod
 +spec:
 +  restartPolicy: Never
 +  containers:
 +  - name: busybox
 +    image: busybox
 +    command: ['sh', '-c', 'while true; do sleep 3600; done']
 +    volumeMounts:
 +    - name: pv-storage
 +      mountPath: /pv-pod-storage
 +  volumes:
 +  - name: pv-storage
 +    persistentVolumeClaim:
 +      claimName: pvc1
 +</code>
 +
 +Appliquez le fichier nfs-busybox.yaml :
 +
 +<code>
 +root@kubemaster:~# kubectl apply -f nfs-busybox.yaml
 +pod/nfs-pv-pod created
 +</code>
 +
 +Vérifiez que le statut du pod **nfs-pv-pod** est **Running** :
 +
 +<code>
 +root@kubemaster:~# kubectl get pods
 +NAME                                               READY   STATUS      RESTARTS      AGE
 +netshoot                                           1/    Running     3 (26h ago)   70d
 +nfs-pv-pod                                         1/    Running                 2m9s
 +nfs-subdir-external-provisioner-59b4b5c476-wxkp4   1/    Running     1 (80m ago)   113m
 +nginx-netshoot                                     1/    Running     3 (26h ago)   70d
 +postgresql-6f885d8957-tnlbb                        1/1     Running     3 (26h ago)   70d
 +sharedvolume                                       2/    Running     6 (26h ago)   78d
 +troubleshooting                                    1/1     Running     3 (26h ago)   70d
 +volumepod                                          0/1     Completed               78d
 +</code>
 +
 +Connectez-vous au conteneur du pod **nfs-pv-pod** :
 +
 +<code>
 +root@kubemaster:~# kubectl exec -it nfs-pv-pod -- sh
 +/ # 
 +</code>
 +
 +Créez le fichier **hello** dans le répertoire **pv-pod-storage** : 
 +
 +<code>
 +root@kubemaster:~# kubectl exec -it nfs-pv-pod -- sh
 +/ # ls
 +bin             dev             etc             home            lib             lib64           proc            pv-pod-storage  root            sys             tmp             usr             var
 +/ # touch /pv-pod-storage/hello
 +/ # ls /pv-pod-storage/
 +hello
 +/ # exit
 +</code>
 +
 +Connectez-vous au serveur NFS et constatez le contenu du répertoire **/srv/nfs/kubedata** :
 +
 +<code>
 +root@kubemaster:~# ssh -l trainee 10.0.2.45
 +trainee@10.0.2.45's password: 
 +Activate the web console with: systemctl enable --now cockpit.socket
 +
 +Last login: Wed Dec  7 12:37:00 2022 from 10.0.2.65
 +[trainee@centos8 ~]$ ls -lR /srv/nfs/kubedata/
 +/srv/nfs/kubedata/:
 +total 0
 +drwxrwxrwx. 2 root root 19 Dec  7 13:13 default-pvc1-pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da
 +
 +/srv/nfs/kubedata/default-pvc1-pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da:
 +total 0
 +-rw-r--r--. 1 root root 0 Dec  7 13:13 hello
 +[trainee@centos8 ~]$ exit
 +logout
 +Connection to 10.0.2.45 closed.
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez la présence du fichier **hello**.
 +</WRAP>
 +
 +===2.6 - Création d'un Deuxième PersistentVolumeClaim===
 +
 +Vréez le fichier **pvc2.yaml** :
 +
 +<code>
 +root@kubemaster:~# vi pvc2.yaml
 +root@kubemaster:~# cat pvc2.yaml
 +apiVersion: v1
 +kind: PersistentVolumeClaim
 +metadata:
 +  name: pvc2
 +spec:
 +  storageClassName: nfs-client 
 +  accessModes:
 +    - ReadWriteOnce
 +  resources:
 +    requests:
 +      storage: 100Mi
 +</code>
 +
 +Appliquez le fichier **pvc2.yaml** :
 +
 +<code>
 +root@kubemaster:~# kubectl apply -f pvc2.yaml 
 +persistentvolumeclaim/pvc2 created
 +</code>
 +
 +Constatez maintenant la liste de PersistentVolumes et de PersistentVolumeClaims :
 +
 +<code>
 +root@kubemaster:~# kubectl get pv,pvc
 +NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM          STORAGECLASS   REASON   AGE
 +persistentvolume/mypv                                       1Gi        RWO            Recycle          Available                  localdisk               77d
 +persistentvolume/pvc-6dbce6de-e473-4e4c-99be-0fbea26576de   100Mi      RWO            Delete           Bound       default/pvc2   nfs-client              58s
 +persistentvolume/pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da   500Mi      RWX            Delete           Bound       default/pvc1   nfs-client              53m
 +
 +NAME                         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
 +persistentvolumeclaim/pvc1   Bound    pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da   500Mi      RWX            nfs-client     53m
 +persistentvolumeclaim/pvc2   Bound    pvc-6dbce6de-e473-4e4c-99be-0fbea26576de   100Mi      RWO            nfs-client     58s
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez que le PersistentVolume **persistentvolume/pvc-6dbce6de-e473-4e4c-99be-0fbea26576de** a été créé automatiquement.
 +</WRAP>
 +
 +===2.7 - Suppression des PersistentVolumeClaims===
 +
 +Commencer par supprimer le pod **nfs-pv-pod** :
 +
 +<code>
 +root@kubemaster:~# kubectl delete pod nfs-pv-pod
 +pod "nfs-pv-pod" deleted
 +</code>
 +
 +Constatez la suppression effective du pod :
 +
 +<code>
 +root@kubemaster:~# kubectl get pods
 +NAME                                               READY   STATUS      RESTARTS       AGE
 +netshoot                                           1/    Running     3 (27h ago)    70d
 +nfs-subdir-external-provisioner-59b4b5c476-wxkp4   1/    Running     1 (126m ago)   159m
 +nginx-netshoot                                     1/    Running     3 (27h ago)    70d
 +postgresql-6f885d8957-tnlbb                        1/1     Running     3 (27h ago)    70d
 +sharedvolume                                       2/    Running     6 (27h ago)    78d
 +troubleshooting                                    1/1     Running     3 (27h ago)    70d
 +volumepod                                          0/1     Completed                78d
 +</code>
 +
 +Constatez maintenant la liste de PersistentVolumes et de PersistentVolumeClaims :
 +
 +<code>
 +root@kubemaster:~# kubectl get pv,pvc
 +NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM          STORAGECLASS   REASON   AGE
 +persistentvolume/mypv                                       1Gi        RWO            Recycle          Available                  localdisk               77d
 +persistentvolume/pvc-6dbce6de-e473-4e4c-99be-0fbea26576de   100Mi      RWO            Delete           Bound       default/pvc2   nfs-client              27m
 +persistentvolume/pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da   500Mi      RWX            Delete           Bound       default/pvc1   nfs-client              79m
 +
 +NAME                         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
 +persistentvolumeclaim/pvc1   Bound    pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da   500Mi      RWX            nfs-client     79m
 +persistentvolumeclaim/pvc2   Bound    pvc-6dbce6de-e473-4e4c-99be-0fbea26576de   100Mi      RWO            nfs-client     27m
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez que les PersistentVolumes et les PersistentVolumeClaims sont toujours présents.
 +</WRAP>
 +
 +Supprimes les deux PersistentVolumeClaims :
 +
 +<code>
 +root@kubemaster:~# kubectl delete pvc --all
 +persistentvolumeclaim "pvc1" deleted
 +persistentvolumeclaim "pvc2" deleted
 +</code>
 +
 +Constatez ensuite que les deux PersistentVolumes ont été supprimés automatiquement :
 +
 +<code>
 +root@kubemaster:~# kubectl get pv,pvc
 +NAME                    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
 +persistentvolume/mypv   1Gi        RWO            Recycle          Available           localdisk               77d
 +</code>
 +
 +Connectez-vous au serveur NFS et constatez le contenu du répertoire **/srv/nfs/kubedata** :
 +
 +<code>
 +root@kubemaster:~# ssh -l trainee 10.0.2.45
 +trainee@10.0.2.45's password: 
 +Activate the web console with: systemctl enable --now cockpit.socket
 +
 +Last login: Wed Dec  7 13:15:49 2022 from 10.0.2.65
 +[trainee@centos8 ~]$ ls -lR /srv/nfs/kubedata/
 +/srv/nfs/kubedata/:
 +total 0
 +drwxrwxrwx. 2 root root 19 Dec  7 13:13 archived-default-pvc1-pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da
 +drwxrwxrwx. 2 root root  6 Dec  7 13:24 archived-default-pvc2-pvc-6dbce6de-e473-4e4c-99be-0fbea26576de
 +
 +/srv/nfs/kubedata/archived-default-pvc1-pvc-721f5ed3-88b1-41bb-82c2-9eab3b4464da:
 +total 0
 +-rw-r--r--. 1 root root 0 Dec  7 13:13 hello
 +
 +/srv/nfs/kubedata/archived-default-pvc2-pvc-6dbce6de-e473-4e4c-99be-0fbea26576de:
 +total 0
 +[trainee@centos8 ~]$ exit
 +logout
 +Connection to 10.0.2.45 closed.
 +</code>
 +
 +<WRAP center round important 60%>
 +**Important** : Notez que les répertoires ont un préfixe **archived-**
 +</WRAP>
 +
 +=====Helm Avancé=====
 +
 +Un chart est une collection de fichiers et de répertoires qui prennent la forme suivante :
 +
 +<file>
 +MyChart/
 +  Chart.yaml
 +  LICENSE
 +  README.md
 +  values.yaml
 +  values.schema.json
 +  charts/
 +  crds/
 +  templates/
 +  templates/NOTES.txt
 +</file>
 +
 +Le langage des templates de helm est basé sur le langage GO.
 +
 +Dans le LAB suivant, vous allez prendre les deux manifests suivants, **ghost.yaml** et **ghost-service.yaml** et créer un chart helm pour installer  **Ghost**, une plateforme de blogs gratuite, sous licence logiciel libre :
 +
 +<code>
 +root@kubemaster:~# vi ghost.yaml
 +root@kubemaster:~# cat ghost.yaml 
 +apiVersion: apps/v1
 +kind: Deployment
 +metadata:
 +  name: blog
 +  labels:
 +    app: blog
 +spec:
 +  replicas: 1
 +  selector:
 +    matchLabels:
 +      app: blog
 +  template:
 +    metadata:
 +      labels:
 +        app: blog
 +    spec:
 +      containers:
 +      - name: blog
 +        image: ghost:2.6-alpine
 +        imagePullPolicy: Always
 +        ports:
 +        - containerPort: 2368
 +        env:
 +        - name: url
 +          value: http://exampleblog.com
 +</code>
 +
 +<code>
 +root@kubemaster:~# vi ghost-service.yaml
 +root@kubemaster:~# cat ghost-service.yaml 
 +apiVersion: v1
 +kind: Service
 +metadata:
 +  name: blog
 +spec:
 +  type: NodePort
 +  selector:
 +    app: blog
 +  ports:
 +  - protocol: TCP
 +    port: 80
 +    targetPort: 2368
 +</code> 
 +
 +====LAB #3 - Création d'un Paquet Helm Simple====
 +
 +Commencez par créer le répertoire **~/ghost** et placez-vous dedans :     
 +
 +<code>
 +root@kubemaster:~# mkdir ghost
 +root@kubemaster:~# cd ghost
 +</code>
 +
 +Un chart necéssite la présence d'un fichier nommé **Chart.yaml** qui doit décrire le chart en question. Créez donc ce fichier :
 +
 +<code>
 +root@kubemaster:~/ghost# touch Chart.yaml
 +</code>
 +
 +===3.1 - Le Fichier values.yaml===
 +
 +Un chart a aussi besoin d'un fichier dénommé **values.yaml** qui contient des valeurs de configuration du chart en question. Créez donc le fichier values.yaml avec le contenu suivant :
 +
 +<code>
 +root@kubemaster:~/ghost# vi values.yaml
 +root@kubemaster:~/ghost# cat values.yaml
 +service:
 +  name: blog
 +  type: NodePort
 +  app: blog
 +  protocol: TCP
 +  port: 80
 +  targetPort: 2368
 +</code>
 +
 +===3.2 - Les Templates===
 +
 +Créez le sous-répertoire **templates** dans **ghost** :
 +
 +<code>
 +root@kubemaster:~/ghost# mkdir templates
 +</code>
 +
 +Copiez le contenu du fichier **~/ghost-service.yaml** et collez-le dans le fichier **~/ghost/templates/service.yaml** :
 +
 +<code>
 +root@kubemaster:~/ghost# vi templates/service.yaml
 +root@kubemaster:~/ghost# cat templates/service.yaml 
 +apiVersion: v1
 +kind: Service
 +metadata:
 +  name: blog
 +spec:
 +  type: NodePort
 +  selector:
 +    app: blog
 +  ports:
 +  - protocol: TCP
 +    port: 80
 +    targetPort: 2368
 +</code>
 +
 +Modifiez ensuite ce fichier pour lire les valeurs du fichier **values.yaml** :
 +
 +<code>
 +root@kubemaster:~/ghost# vi templates/service.yaml
 +root@kubemaster:~/ghost# cat templates/service.yaml
 +apiVersion: v1
 +kind: Service
 +metadata:
 +  name: {{ .Values.service.name }}
 +spec:
 +  type: {{ .Values.service.type }}
 +  selector:
 +    app: {{ .Values.service.app }}
 +  ports:
 +  - protocol: {{ .Values.service.protocol }}
 +    port: {{ .Values.service.port }}
 +    targetPort: {{ .Values.service.targetPort }}
 +</code>
 +
 +Naviguez vers le répertoire parent du répertoire **ghost** :
 +
 +<code>
 +root@kubemaster:~/ghost# cd ..
 +</code>
 +
 +Vérifiez que helm peut lire la liste des valeurs du fichier values.yaml :
 +
 +<code>
 +root@kubemaster:~# helm show values ghost
 +Error: validation: chart.metadata.name is required
 +</code>
 +
 +L'erreur obtenu fait référence au fichier **Chart.yaml**, actuellement vide. Editez donc ce fichier :
 +
 +<code>
 +root@kubemaster:~# vi ghost/Chart.yaml
 +root@kubemaster:~# cat ghost/Chart.yaml
 +name: ghost
 +version: 1
 +</code>
 +
 +Vérifiez maintenant que helm peut lire la liste des valeurs du fichier values.yaml :
 +
 +<code>
 +root@kubemaster:~# helm show values ghost
 +service:
 +  name: blog
 +  type: NodePort
 +  app: blog
 +  protocol: TCP
 +  port: 80
 +  targetPort: 2368
 +</code>
 +
 +Vérifiez maintenant que le manifest **service.yaml** qui sera créé par Helm est correct :
 +
 +<code>
 +root@kubemaster:~# helm install check ghost --dry-run
 +NAME: check
 +LAST DEPLOYED: Thu Dec  8 15:54:13 2022
 +NAMESPACE: default
 +STATUS: pending-install
 +REVISION: 1
 +TEST SUITE: None
 +HOOKS:
 +MANIFEST:
 +---
 +# Source: ghost/templates/service.yaml
 +apiVersion: v1
 +kind: Service
 +metadata:
 +  name: blog
 +spec:
 +  type: NodePort
 +  selector:
 +    app: blog
 +  ports:
 +  - protocol: TCP
 +    port: 80
 +    targetPort: 2368
 +</code>
 +
 +Copiez maintenant le contenu du fichier **~/ghost.yaml** et collez-le dans le fichier **~/ghost/templates/ghost.yaml** :
 +
 +<code>
 +root@kubemaster:~# vi ghost/templates/ghost.yaml
 +root@kubemaster:~# cat ghost/templates/ghost.yaml
 +apiVersion: apps/v1
 +kind: Deployment
 +metadata:
 +  name: blog
 +  labels:
 +    app: blog
 +spec:
 +  replicas: 1
 +  selector:
 +    matchLabels:
 +      app: blog
 +  template:
 +    metadata:
 +      labels:
 +        app: blog
 +    spec:
 +      containers:
 +      - name: blog
 +        image: ghost:2.6-alpine
 +        imagePullPolicy: Always
 +        ports:
 +        - containerPort: 2368
 +        env:
 +        - name: url
 +          value: http://exampleblog.com
 +</code>
 +
 +Modifiez ensuite ce fichier pour lire les valeurs du fichier **values.yaml** :
 +
 +<code>
 +root@kubemaster:~# vi ghost/templates/ghost.yaml
 +root@kubemaster:~# cat ghost/templates/ghost.yaml
 +apiVersion: apps/v1
 +kind: Deployment
 +metadata:
 +  name: {{ .Values.blog.name }}
 +  labels:
 +    app: {{ .Values.blog.label }}
 +spec:
 +  replicas: {{ .Values.blog.replicas }}
 +  selector:
 +    matchLabels:
 +      app: {{ .Values.blog.name }}
 +  template:
 +    metadata:
 +      labels:
 +        app: {{ .Values.blog.name }}
 +    spec:
 +      containers:
 +      - name: {{ .Values.blog.name }}
 +        image: {{ .Values.blog.image }}
 +        imagePullPolicy: {{ .Values.blog.imagePullPolicy }}
 +        ports:
 +        - containerPort: {{ .Values.blog.containerPort }}
 +        env:
 +        - name: {{ .Values.blog.url }}
 +          value: {{ .Values.blog.urlValue }}
 +</code>
 +
 +Completez maintenant le contenu du fichier values.yaml :
 +
 +<code>
 +root@kubemaster:~# vi ghost/values.yaml
 +root@kubemaster:~# cat ghost/values.yaml
 +service:
 +  name: blog
 +  type: NodePort
 +  app: blog
 +  protocol: TCP
 +  port: 80
 +  targetPort: 2368
 +blog:
 +  name: blog
 +  label: blog
 +  replicas: 1
 +  image: ghost:2.6-alpine
 +  imagePullPolicy: Always
 +  containerPort: 2368
 +  url: url
 +  urlValue: http://exampleblog.com
 +</code>
 +
 +Vérifiez maintenant que le manifest **ghost.yaml** qui sera créé par Helm est correct :
 +
 +<code>
 +root@kubemaster:~# helm install check ghost --dry-run
 +NAME: check
 +LAST DEPLOYED: Thu Dec  8 16:12:29 2022
 +NAMESPACE: default
 +STATUS: pending-install
 +REVISION: 1
 +TEST SUITE: None
 +HOOKS:
 +MANIFEST:
 +---
 +# Source: ghost/templates/service.yaml
 +apiVersion: v1
 +kind: Service
 +metadata:
 +  name: blog
 +spec:
 +  type: NodePort
 +  selector:
 +    app: blog
 +  ports:
 +  - protocol: TCP
 +    port: 80
 +    targetPort: 2368
 +---
 +# Source: ghost/templates/ghost.yaml
 +apiVersion: apps/v1
 +kind: Deployment
 +metadata:
 +  name: blog
 +  labels:
 +    app: blog
 +spec:
 +  replicas: 1
 +  selector:
 +    matchLabels:
 +      app: blog
 +  template:
 +    metadata:
 +      labels:
 +        app: blog
 +    spec:
 +      containers:
 +      - name: blog
 +        image: ghost:2.6-alpine
 +        imagePullPolicy: Always
 +        ports:
 +        - containerPort: 2368
 +        env:
 +        - name: url
 +          value: http://exampleblog.com
 +</code>
 +
 +Consultez maintenant l'organisation du chart **ghost** :
 +
 +<code>
 +root@kubemaster:~# tree ghost
 +ghost
 +├── Chart.yaml
 +├── templates
 +│   ├── ghost.yaml
 +│   └── service.yaml
 +└── values.yaml
 +
 +1 directory, 4 files
 +</code>
 +
 +===3.3 - Installation et Suppression===
 +
 +Installez le chart **ghost** :
 +
 +<code>
 +root@kubemaster:~# helm install live ghost
 +NAME: live
 +LAST DEPLOYED: Thu Dec  8 16:14:13 2022
 +NAMESPACE: default
 +STATUS: deployed
 +REVISION: 1
 +TEST SUITE: None
 +</code>
 +
 +Vérifiez l'état du service dans le cluster :
 +
 +<code>
 +root@kubemaster:~# kubectl get svc
 +NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
 +blog               NodePort    10.106.215.169   <none>        80:32070/TCP   52s
 +kubernetes         ClusterIP   10.96.0.1        <none>        443/TCP        95d
 +service-netshoot   ClusterIP   10.107.115.28    <none>        80/TCP         71d
 +</code>
 +
 +Vérifiez la présence du pod dans le cluster :
 +
 +<code>
 +root@kubemaster:~# kubectl get po
 +NAME                                               READY   STATUS      RESTARTS       AGE
 +blog-8545df8764-hk8rc                              1/1     Running                  105s
 +netshoot                                           1/    Running     3 (2d6h ago)   71d
 +nfs-subdir-external-provisioner-59b4b5c476-wxkp4   1/    Running     1 (28h ago)    29h
 +nginx-netshoot                                     1/    Running     3 (2d6h ago)   71d
 +postgresql-6f885d8957-tnlbb                        1/1     Running     3 (2d6h ago)   71d
 +sharedvolume                                       2/    Running     6 (2d6h ago)   79d
 +troubleshooting                                    1/1     Running     3 (2d6h ago)   71d
 +volumepod                                          0/1     Completed   0
 +</code>
 +
 +Vérifiez le statut du chart :
 +
 +<code>
 +root@kubemaster:~# helm status live
 +NAME: live
 +LAST DEPLOYED: Thu Dec  8 16:14:13 2022
 +NAMESPACE: default
 +STATUS: deployed
 +REVISION: 1
 +TEST SUITE: None
 +</code>
 +
 +Dernièrement, supprimez le chart :
 +
 +<code>
 +root@kubemaster:~# helm delete live
 +release "live" uninstalled
 +</code>
 +
 +=====Monitoring=====
 +
 +Le serveur Prometheus est composé de trois modules :
 +
 +  * **Data Retrieval Worker** qui récupére les métriques
 +  * **Time Series Database** qui stocke les métriques
 +  * **HTTP Server** qui accepte des requêtes PromQL et qui fournit un Web UI pour la consultation des données
 +
 +<WRAP center round important 60%>
 +**Important** : **[[https://prometheus.io/docs/prometheus/latest/querying/basics/|PromQL]]**, abréviation de Prometheus Querying Language, est le principal moyen d'interroger les métriques dans Prometheus. Vous pouvez afficher le retour d'une expression sous forme de graphique ou l'exporter à l'aide de l'API HTTP. PromQL utilise trois types de données : les scalaires, les vecteurs de plage et les vecteurs instantanés. Il utilise également des chaînes, mais uniquement en tant que littéraux.
 +</WRAP>
 +
 +Des alertes sont ensuite passées à l'**Alertmanager** qui informe des personnes en focntion de la configuration mise en place.
 +
 +====LAB #4 - Mise en Place d'une Solution Prometheus====
 +
 +Connectez-vous à la VM **Gateway_10.0.2.40_VNC**.
 +
 +===4.1 - Déploiement du Stack avec Helm===
 +
 +Ajoutez le dépôt **prometheus-community** :
 +
 +<code>
 +trainee@gateway:~$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
 +"prometheus-community" has been added to your repositories
 +
 +trainee@gateway:~$ helm repo update
 +</code>
 +
 +Installez ensuite le chart **kube-prometheus-stack** :
 +
 +<code>
 +trainee@gateway:~$ helm install prometheus prometheus-community/kube-prometheus-stack
 +NAME: prometheus
 +LAST DEPLOYED: Thu Dec  8 17:04:17 2022
 +NAMESPACE: default
 +STATUS: deployed
 +REVISION: 1
 +NOTES:
 +kube-prometheus-stack has been installed. Check its status by running:
 +  kubectl --namespace default get pods -l "release=prometheus"
 +
 +Visit https://github.com/prometheus-operator/kube-prometheus for instructions on how to create & configure Alertmanager and Prometheus instances using the Operator.
 +</code>
 +
 +Patientez jusqu'à ce que tous les pods soient dans un état de **Running** :
 +
 +<code>
 +trainee@gateway:~$ kubectl --namespace default get pods -l "release=prometheus"
 +NAME                                                   READY   STATUS    RESTARTS   AGE
 +prometheus-kube-prometheus-operator-689dd6679c-2th6f   1/    Running            4m12s
 +prometheus-kube-state-metrics-6cfd96f4c8-wrw2n         1/    Running            4m12s
 +prometheus-prometheus-node-exporter-8cb4s              1/1     Running            4m13s
 +prometheus-prometheus-node-exporter-ll4qp              1/1     Running            4m13s
 +prometheus-prometheus-node-exporter-x87f7              1/1     Running            4m13s
 +</code>
 +
 +Consultez maintenant l'ensemb le des objets Prometheus créés par l'installation :
 +
 +<code>
 +trainee@gateway:~$ kubectl get all -l "release=prometheus"
 +NAME                                                       READY   STATUS    RESTARTS   AGE
 +pod/prometheus-kube-prometheus-operator-689dd6679c-2th6f   1/    Running            13h
 +pod/prometheus-kube-state-metrics-6cfd96f4c8-wrw2n         1/    Running            13h
 +pod/prometheus-prometheus-node-exporter-8cb4s              1/1     Running            13h
 +pod/prometheus-prometheus-node-exporter-ll4qp              1/1     Running            13h
 +pod/prometheus-prometheus-node-exporter-x87f7              1/1     Running            13h
 +
 +NAME                                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
 +service/prometheus-kube-prometheus-alertmanager   ClusterIP   10.103.114.236   <none>        9093/TCP   13h
 +service/prometheus-kube-prometheus-operator       ClusterIP   10.107.174.218   <none>        443/TCP    13h
 +service/prometheus-kube-prometheus-prometheus     ClusterIP   10.108.124.100   <none>        9090/TCP   13h
 +service/prometheus-kube-state-metrics             ClusterIP   10.109.13.26     <none>        8080/TCP   13h
 +service/prometheus-prometheus-node-exporter       ClusterIP   10.103.100.124   <none>        9100/TCP   13h
 +
 +NAME                                                 DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
 +daemonset.apps/prometheus-prometheus-node-exporter                                    3           <none>          13h
 +
 +NAME                                                  READY   UP-TO-DATE   AVAILABLE   AGE
 +deployment.apps/prometheus-kube-prometheus-operator   1/               1           13h
 +deployment.apps/prometheus-kube-state-metrics         1/               1           13h
 +
 +NAME                                                             DESIRED   CURRENT   READY   AGE
 +replicaset.apps/prometheus-kube-prometheus-operator-689dd6679c                         13h
 +replicaset.apps/prometheus-kube-state-metrics-6cfd96f4c8                               13h
 +
 +NAME                                                                    READY   AGE
 +statefulset.apps/alertmanager-prometheus-kube-prometheus-alertmanager   1/    13h
 +statefulset.apps/prometheus-prometheus-kube-prometheus-prometheus       1/    13h
 +</code>
 +
 +Dans cette sortie on constate :
 +
 +  * 2 StatefulSets dont :
 +    * le serveur Prometheus **statefulset.apps/prometheus-prometheus-kube-prometheus-prometheus**
 +    * l'Alertmanager **statefulset.apps/alertmanager-prometheus-kube-prometheus-alertmanager**
 +  * 2 Deployments dont :
 +    * l'operator **deployment.apps/prometheus-kube-prometheus-operator** qui a créé les deux StatefulSets
 +    * le kube-state-metrics **deployment.apps/prometheus-kube-state-metrics** qui est une dépendance de Prometheus et donc un **Subchart** de ce dernier
 +  * 2 ReplicaSets créés par les Deployments :
 +    * **replicaset.apps/prometheus-kube-prometheus-operator-689dd6679c**
 +    * **replicaset.apps/prometheus-kube-state-metrics-6cfd96f4c8**
 +  * 1 DaemonSet **daemonset.apps/prometheus-prometheus-node-exporter ** :
 +    * les pods de ce DaemonSet sont responsables pour la transformation des métriques des noeuds en métriques Prometheus  
 +
 +L'installation a aussi créé un grand nombre de ConfigMaps :
 +
 +<code>
 +trainee@gateway:~$ kubectl get configmap -l "release=prometheus"
 +NAME                                                           DATA   AGE
 +prometheus-kube-prometheus-alertmanager-overview                    13h
 +prometheus-kube-prometheus-apiserver                                13h
 +prometheus-kube-prometheus-cluster-total                            13h
 +prometheus-kube-prometheus-controller-manager                  1      13h
 +prometheus-kube-prometheus-etcd                                1      13h
 +prometheus-kube-prometheus-grafana-datasource                  1      13h
 +prometheus-kube-prometheus-grafana-overview                    1      13h
 +prometheus-kube-prometheus-k8s-coredns                              13h
 +prometheus-kube-prometheus-k8s-resources-cluster                    13h
 +prometheus-kube-prometheus-k8s-resources-namespace                  13h
 +prometheus-kube-prometheus-k8s-resources-node                  1      13h
 +prometheus-kube-prometheus-k8s-resources-pod                        13h
 +prometheus-kube-prometheus-k8s-resources-workload              1      13h
 +prometheus-kube-prometheus-k8s-resources-workloads-namespace        13h
 +prometheus-kube-prometheus-kubelet                                  13h
 +prometheus-kube-prometheus-namespace-by-pod                    1      13h
 +prometheus-kube-prometheus-namespace-by-workload                    13h
 +prometheus-kube-prometheus-node-cluster-rsrc-use                    13h
 +prometheus-kube-prometheus-node-rsrc-use                            13h
 +prometheus-kube-prometheus-nodes                                    13h
 +prometheus-kube-prometheus-nodes-darwin                        1      13h
 +prometheus-kube-prometheus-persistentvolumesusage              1      13h
 +prometheus-kube-prometheus-pod-total                                13h
 +prometheus-kube-prometheus-prometheus                          1      13h
 +prometheus-kube-prometheus-proxy                                    13h
 +prometheus-kube-prometheus-scheduler                                13h
 +prometheus-kube-prometheus-workload-total                      1      13h
 +</code>
 +
 +ainsi que des Secrets :
 +
 +<code>
 +trainee@gateway:~$ kubectl get secrets 
 +NAME                                                                TYPE                 DATA   AGE
 +alertmanager-prometheus-kube-prometheus-alertmanager                Opaque                    13h
 +alertmanager-prometheus-kube-prometheus-alertmanager-generated      Opaque                    13h
 +alertmanager-prometheus-kube-prometheus-alertmanager-tls-assets-0   Opaque                    13h
 +alertmanager-prometheus-kube-prometheus-alertmanager-web-config     Opaque                    13h
 +my-secret                                                           Opaque                    88d
 +prometheus-grafana                                                  Opaque                    13h
 +prometheus-kube-prometheus-admission                                Opaque                    13h
 +prometheus-prometheus-kube-prometheus-prometheus                    Opaque                    13h
 +prometheus-prometheus-kube-prometheus-prometheus-tls-assets-0       Opaque                    13h
 +prometheus-prometheus-kube-prometheus-prometheus-web-config         Opaque                    13h
 +sh.helm.release.v1.nfs-subdir-external-provisioner.v1               helm.sh/release.v1        43h
 +sh.helm.release.v1.prometheus.v1                                    helm.sh/release.v1        13h
 +</code>
 +
 +des **Custom Resource Definitions** ou crd :
 +
 +<code>
 +trainee@gateway:~$ kubectl get crd
 +NAME                                                  CREATED AT
 +alertmanagerconfigs.monitoring.coreos.com             2022-12-08T16:04:14Z
 +alertmanagers.monitoring.coreos.com                   2022-12-08T16:04:14Z
 +bgpconfigurations.crd.projectcalico.org               2022-09-04T07:38:47Z
 +bgppeers.crd.projectcalico.org                        2022-09-04T07:38:47Z
 +blockaffinities.crd.projectcalico.org                 2022-09-04T07:38:48Z
 +caliconodestatuses.crd.projectcalico.org              2022-09-04T07:38:48Z
 +clusterinformations.crd.projectcalico.org             2022-09-04T07:38:48Z
 +felixconfigurations.crd.projectcalico.org             2022-09-04T07:38:48Z
 +globalnetworkpolicies.crd.projectcalico.org           2022-09-04T07:38:48Z
 +globalnetworksets.crd.projectcalico.org               2022-09-04T07:38:49Z
 +hostendpoints.crd.projectcalico.org                   2022-09-04T07:38:49Z
 +ipamblocks.crd.projectcalico.org                      2022-09-04T07:38:49Z
 +ipamconfigs.crd.projectcalico.org                     2022-09-04T07:38:49Z
 +ipamhandles.crd.projectcalico.org                     2022-09-04T07:38:50Z
 +ippools.crd.projectcalico.org                         2022-09-04T07:38:50Z
 +ipreservations.crd.projectcalico.org                  2022-09-04T07:38:50Z
 +kubecontrollersconfigurations.crd.projectcalico.org   2022-09-04T07:38:50Z
 +networkpolicies.crd.projectcalico.org                 2022-09-04T07:38:50Z
 +networksets.crd.projectcalico.org                     2022-09-04T07:38:50Z
 +podmonitors.monitoring.coreos.com                     2022-12-08T16:04:14Z
 +probes.monitoring.coreos.com                          2022-12-08T16:04:14Z
 +prometheuses.monitoring.coreos.com                    2022-12-08T16:04:14Z
 +prometheusrules.monitoring.coreos.com                 2022-12-08T16:04:14Z
 +servicemonitors.monitoring.coreos.com                 2022-12-08T16:04:15Z
 +thanosrulers.monitoring.coreos.com                    2022-12-08T16:04:15Z
 +</code>
 +
 +===4.2 - Consultation des Données avec Grafana===
 +
 +L'installation du chart helm a aussi installé **Grafana**.
 +
 +Grafana est une plate-forme de visualisation de données interactive open source, développée par Grafana Labs, qui permet aux utilisateurs de voir leurs données via des tableaux et des graphiques qui sont unifiés dans un tableau de bord (ou plusieurs tableaux de bord ) pour une interprétation et une compréhension plus faciles.
 +
 +Consultez les objets Grafana :
 +
 +<code>
 +trainee@gateway:~$ kubectl get all | grep grafana
 +pod/prometheus-grafana-5d9f5d6499-f4x6t                      3/3     Running     1 (13h ago)     14h
 +service/prometheus-grafana                        ClusterIP   10.109.207.199   <none>        80/TCP                       14h
 +deployment.apps/prometheus-grafana                    1/1                1           14h
 +replicaset.apps/prometheus-grafana-5d9f5d6499                    1                       14h
 +</code>
 +
 +Vérifiez le port utilisé par Grafana :
 +
 +<code>
 +trainee@gateway:~$ kubectl logs prometheus-grafana-5d9f5d6499-f4x6t -c grafana | grep HTTP
 +logger=http.server t=2022-12-08T16:16:51.215644746Z level=info msg="HTTP Server Listen" address=[::]:3000 protocol=http subUrl= socket=
 +</code>
 +
 +ainsi que le nom de l'utilisateur pour se connecter à Grafana :
 +
 +<code>
 +trainee@gateway:~$ kubectl logs prometheus-grafana-5d9f5d6499-f4x6t -c grafana | grep "user="
 +logger=sqlstore t=2022-12-08T16:16:50.536980031Z level=info msg="Created default admin" user=admin
 +</code>
 +
 +Le mot de passe par défaut de l'utilisateur **admin** peut être obtenu en consultant le contenu du fichier **[[https://github.com/prometheus-community/helm-charts/blob/main/charts/kube-prometheus-stack/values.yaml|values.yaml]]**
 +
 +<WRAP center round important 60%>
 +**Important** : Notez que le mot de passe est **prom-operator**.
 +</WRAP>
 +
 +Mettez en place une redirection de port :
 +
 +<code>
 +trainee@gateway:~$ kubectl port-forward deployment/prometheus-grafana 3000
 +Forwarding from 127.0.0.1:3000 -> 3000
 +Forwarding from [::1]:3000 -> 3000
 +
 +</code>
 +
 +Consultez maintenant la VM **Gateway_10.0.2.40_VNC** et lancez le navigateur web. Saisissez l'URL **http://127.0.0.1:3000** et connectez-vous à Grafana :
 +
 +{{ :elearning:workbooks:kubernetes:capture_d_ecran_du_2022-12-09_06-50-22.png?direct&800 |Image}}
 +
 +Cliquez ensuite sur **Dashboards > Browse > Kubernetes / Compute Resources / Node (Pods)** :
 +
 +{{ :elearning:workbooks:kubernetes:capture_d_ecran_du_2022-12-09_06-53-05.png?direct&800 |}}
 +
 +Dernièrement, cliquez ensuite sur **Dashboards > Browse > Node Exporter / Nodes** : 
 +
 +{{ :elearning:workbooks:kubernetes:capture_d_ecran_du_2022-12-09_07-06-14.png?direct&800 |}}
 +
 +===4.3 - Consultation des Alertes avec le Web UI de Prometheus===
 +
 +Pour consultez le Web UI de Prometheus, mettez en place une redirection de port :
 +
 +<code>
 +trainee@gateway:~$ kubectl port-forward prometheus-prometheus-kube-prometheus-prometheus-0 9090
 +Forwarding from 127.0.0.1:9090 -> 9090
 +Forwarding from [::1]:9090 -> 9090
 +</code>
 +
 +Retournez dans l'interface graphique de la VM **Gateway_10.0.2.40_VNC** et saisissez l'URL **http://127.0.0.1:9090** :
 +
 +{{ :elearning:workbooks:kubernetes:capture_d_ecran_du_2022-12-09_07-13-13.png?direct&800 |}}
 +
 +Pour consultez la liste des alertes, cliquez sur le lien Alerts dans le menu en haut de la page :
 +
 +{{ :elearning:workbooks:kubernetes:capture_d_ecran_du_2022-12-09_07-14-08.png?direct&800 |}}
 +
 +-----
 +Copyright © 2024 Hugh Norris
Menu