Un volume ‘emptyDir‘ existe seulement à l’intérieur d’un Pod et peut-être utilisé par les conteneurs du Pod. Voici un exemple de trois conteneurs utilisant le même volume:
Action 1.1 – Renseigner et appliquer le manifeste suivant:
# ------------------------------------------------------------- # Fichier: exemple1.1.yml # Auteur: Alain Boudreault # Projet: 420-4D4-Semaine 10 # Date: 2021.04.13 # ------------------------------------------------------------- # Exemple d'un manifeste pour un Pod nginx avec un emptyDir # ------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: exemple1-1 spec: containers: - name: nginx image: nginx volumeMounts: - mountPath: /usr/share/nginx/html # Ceci est le dossier web de nginx name: volume-web - name: une-debian image: debian command: ["sleep", "1000"] volumeMounts: - mountPath: /petit-coquin name: volume-web - name: une-alpine image: alpine command: ['sh', '-c', 'echo "Je suis 420-4D4 ;)-" > /misere/index.html'] volumeMounts: - mountPath: /misere name: volume-web # restartPolicy: Never # Définition des volumes volumes: - name: volume-web emptyDir: {}
kubectl apply -f exemple1.1.yml kubectl get pods kubectl get pods -o=jsonpath="{range .items[*]}{\"\n\"}{.metadata.name}{\":\t\"}{range .spec.containers[*]}{.name}{\", \"}{end}{end}"
Note: Le Pod ‘alpine’ va créer le fichier ‘index.html‘ puis va passer en état ‘CrashLoopBackOff’.
Action 1.2 – Tester le contenu du volume du conteneur ‘une-debian’
kubectl exec -it exemple1-1 --container=une-debian -- bash root@exemple1-1:/# ls bin dev home lib64 mnt petit-coquin root sbin sys usr boot etc lib media opt proc run srv tmp var root@exemple1-1:/# cat petit-coquin/index.html Je suis 420-4D4 ;)-
Action 1.3 – Tester le contenu du serveur web
kubectl exec -it exemple1-1 --container=nginx -- bash root@example1-1:/# curl localhost Je suis 420-4D4 ;)-
Il est possible de monter les volumes ‘emptyDir‘ en mémoire vive:
- name: volume-web emptyDir: medium: Memory
Note: Sous Minikube, les Pods sont stockés dans la VM de minikube dans le dossier ‘cd /var/lib/kubelet/pods/’. Pour avoir accès à la VM de minikube il suffit de taper la commande: ‘minikube ssh‘.
Action 2.1 – Renseigner le manifeste suivant:
# ------------------------------------------------------------- # Fichier: exemple2.1.yml # Auteur: Alain Boudreault # Projet: 420-4D4-Semaine 09 # Date: 2021.04.03 # ------------------------------------------------------------- # Exemple d'un manifeste pour un Pod nginx avec un volume local # ------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: serveur-web spec: containers: - name: nginx image: nginx volumeMounts: - mountPath: /usr/share/nginx/html name: volume-web # Définition des volumes volumes: - name: volume-web hostPath: # chemin du dossier sur l'hôte # Il faut renseigner le chemin en utilisant l'adressage absolu. # Sur une infrastructure K8S, le dossier doit exister sur le noeud ou roule le Pod. path: /Users/alain/420-4D4/semaine09/web-data/ # ce champ est optionnel type: Directory
Note: Sous minikube, le dossier sera monté dans la VM de minikube.
Référence sur le site de Kubernetes
Référence sur la grotte du Barbu
Les volumes persistants sont des ressources, à créer, Kubernetes. Ils proposent une abstraction sur un volume de stockage. Le volume peut être local ou bien distant, c-a-d, sur un autre serveur.
L’utilisation d’un PV est réalisée en deux étapes:
PersistentVolume
PersistentVolumeClaim
Action 3.1 – Renseigner le manifeste PersistentVolume
– PV – suivant:
# Fichier: exemple3.1.yml apiVersion: v1 kind: PersistentVolume metadata: name: mypv spec: capacity: storage: 1Gi volumeMode: Filesystem accessModes: # ReadWriteOnce -- le volume peut être monté en lecture-écriture par un seul nœud # ReadOnlyMany -- le volume peut être monté en lecture seule par plusieurs nœuds # ReadWriteMany -- le volume peut être monté en lecture-écriture par de nombreux nœuds - ReadWriteOnce # persistentVolumeReclaimPolicy: Retain # Valeur par défaut, les données des PVC seront préservées. persistentVolumeReclaimPolicy: Recycle storageClassName: local hostPath: path: "/mnt/pv"
NOTE: Sous Minikube, le hostPath pointe dans la VM de cette dernière. Il est possible d’en consulter le contenu avec la commande: minikube ssh.
Voici une liste des types de stockages supportés par K8S:
Note: Les types en rouge sont couverts par cet atelier 😉
Il existe des pilotes tierces pour d’autres types de stockage. Par exemple, csi-driver-smb.
Action 3.1.1 – Créer le volume persistant (PV)
kubectl apply -f exemple3.1.yml kubectl get pv
Action 3.1 – Renseigner le manifeste PersistentVolumeClaim
– PVC – suivant:
# Fichier: exemple3.2.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc spec: storageClassName: local resources: requests: storage: 500Mi accessModes: - ReadWriteOnce
Note: Voir la rubrique suivante pour l’explication de la clé ‘storageClassName‘
Action 3.2.1 – Créer le PersistentVolumeClaim
– PVC
kubectl apply -f exemple3.2.yml kubectl get pvc
NOTE IMPORTANTE: Un seul PVC par PV. Si le PVC ne réclame pas 100% de l’espace disponible du PV alors cet espace sera perdu durant toute la durée de vie du PVC.
Action 3.3 – Utiliser un PVC, renseigner le manifeste suivant:
# ------------------------------------------------------------- # Fichier: exemple3.3.yml # Auteur: Alain Boudreault # Projet: 420-4D4-Semaine 10 # Date: 2021.04.13 # ------------------------------------------------------------- # Exemple d'un manifeste pour un Pod nginx avec un PVC # ------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: example3-3 spec: containers: - name: nginx image: nginx volumeMounts: - mountPath: /usr/share/nginx/html # Ceci est le dossier web de nginx name: volume-web # Définition des volumes volumes: - name: volume-web persistentVolumeClaim: claimName: mypvc
Action 3.3.1 – Se connecter au Pod et créer un nouveau fichier:
exec -it example3-3 -- bash cd /usr/share/nginx/html/ echo "Ici la voix des Misterons!" > index.html exit
Action 3.3.2 – Effacer puis relancer le Pod. Tester le serveur Web:
kubectl delete pod example3-3 kubectl apply -f exemple3.3.yml curl localhost --- Résultat: Ici la voix des Misterons!
Volume NFS
4.1 – Mise en place d’un volume NFS sur un serveur Ubuntu 20.04
# Installer le service nfs sur le serveur $ sudo apt update $ sudo apt install nfs-kernel-server # Créer un répertoire de partage $ sudo mkdir /var/nfs/420-4D4 -p $ sudo chown nobody:nogroup /var/nfs/420-4D4 $ sudo echo "Ici la voix des Mistérons" > /var/nfs/420-4D4/coucou.txt # Publier le dossier de partage $ sudo nano /etc/exports /var/nfs/420-4D4 *(rw,sync,no_subtree_check,all_squash,anonuid=65534,anongid=65534,insecure) /nfs *(rw,sync,no_subtree_check,all_squash,anonuid=65534,anongid=65534,insecure) # Redémarrer le service nfs $ sudo systemctl restart nfs-kernel-server # Ou: $ sudo exportfs -a # Si le pare feu est activé alors ouvrir le port nfs: $ sudo ufw allow from client_ip to any port nfs
Vérification de l’état du serveur NFS:
alain@k8s:/var/nfs/420-4D4$ sudo systemctl status nfs-kernel-server ● nfs-server.service - NFS server and services Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; vendor preset: enabled) Active: active (exited) since Tue 2021-04-20 13:35:40 UTC; 1h 30min ago Process: 37210 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS) Process: 37211 ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS (code=exited, status=0/SUCCESS) Main PID: 37211 (code=exited, status=0/SUCCESS)
4.2 – Connexion à un partage NFS (À partir de MacOS):
Note: Ne fonctionne plus à partir de MacOS 11. Utiliser plutôt le terminal:
sudo mkdir /Volumes/test-nfs sudo mount -o vers=4,resvport -t nfs 192.168.2.131:/var/nfs/420-4D4 /Volumes/test-nfs
Ou bien, ajouter la ligne suivante dans le fichier ‘/etc/nfs.conf’ du Mac:
# # nfs.conf: the NFS configuration file # nfs.client.mount.options = vers=4
4.3 – Connexion à un partage NFS (À partir de Linux):
# Au besoin, installer le client NFS: $ sudo apt update $ sudo apt install nfs-common # Monter le volume désiré sur un dossier existant: alain@srv02:~$ sudo mount -t nfs k8s:/var/nfs/420-4D4 ~/420-4d4 alain@srv02:~$ ls -l 420-4d4/ total 4 drwxr-xr-x 2 nobody nogroup 4096 Apr 20 15:01 'Test a partir de MacOS'
4.4 – Connexion à un partage NFS à partir de Minikube:
ATTENTION, LA SECTION 4.4 NE S’APPLIQUE PAS AU PROJET DE SESSION!!!
√ semaine10 % minikube ssh _ _ _ _ ( ) ( ) ___ ___ (_) ___ (_)| |/') _ _ | |_ __ /' _ ` _ `\| |/' _ `\| || , < ( ) ( )| '_`\ /'__`\ | ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )( ___/ (_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____) $ ping 192.168.2.185 PING 192.168.2.185 (192.168.2.185): 56 data bytes 64 bytes from 192.168.2.185: seq=0 ttl=63 time=7.435 ms 64 bytes from 192.168.2.185: seq=1 ttl=63 time=5.655 ms $ sudo mount -t nfs 192.168.2.185:/var/nfs/420-4D4 /tmp $ ls /tmp 'Test a partir de MacOS' $
Note: Les volumes externes de type NFS ne fonctionne pas bien sous Minikube. Il est préférable d’expérimenter avec un cluster Kubernetes.
4.4.2 – IMPORTANT – Le client NFS doit-être installé sur tous les noeuds de l’infrastructure Kubernetes:
apt install nfs-common
Indice que nfs-common est manquant sur les noeuds:
kubectl describe pod example4-6 Warning FailedMount 4m55s (x8 over 5m59s) kubelet MountVolume.SetUp failed for volume "pv-nfs" : mount failed: exit status 32
ATTENTION, LA SECTION 4.4 NE S’APPLIQUE PAS AU PROJET DE SESSION!!!
4.5 – Renseigner un PV à partir d’un partage NFS:
# Fichier: exemple4.5.yml # Exemple d'un PV pointant sur un volume NFS apiVersion: v1 kind: PersistentVolume metadata: name: pv-nfs spec: capacity: storage: 1Gi volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Recycle storageClassName: nfs nfs: server: 192.168.2.185 path: /var/nfs/420-4D4
4.6 – Renseigner un PVC à partir d’un PV.NFS:
# Fichier: exemple4.6.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-nfs spec: storageClassName: nfs resources: requests: storage: 500Mi accessModes: - ReadWriteMany
4.7 – Consommer le PVC.NFS
# ------------------------------------------------------------- # Fichier: exemple4.7.yml # Auteur: Alain Boudreault # Projet: 420-4D4-Semaine 10 # Date: 2021.04.20 # ------------------------------------------------------------- # Exemple d'un manifeste pour un Pod nginx avec un PVC.NFS # ------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: exemple4-7 spec: containers: - name: nginx image: nginx volumeMounts: - mountPath: /usr/share/nginx/html # Ceci est le dossier web de nginx name: volume-web # Définition des volumes volumes: - name: volume-web persistentVolumeClaim: claimName: pvc-nfs
4.8 – Créer un fichier sur le volume NFS
alain@k8s:/var/nfs/420-4D4$ echo "Je suis totalement NFS ;-)" > index.html
4.9 – Tester le volume NFS via une Nginx
vagrant@k8s-master:~/k8s-lesVolumes$ kubectl exec -it example4-6 -- bash root@example4-6:/# curl localhost Je suis totalement NFS ;-)
# Diagnostique: kubectl get events
4.9.1. – NOTE —> Pour un partage NFS sur un service en nuage, il faut penser à ouvrir les ports 111 et 2049 en TCP et UDP du pare-feu du projet.
Par exemple, sur Google Cloud:
Et sur AWS d’Amazon:
5 – Voici un exemple d’un déploiement nginx avec un PV à partir d’une VM sur le cloud de Google:
# Exemple d'un service web qui utilise un dossier de partage NFS # d'un serveur qui roule sur le cloud de Google. # # Note: Le partage NFS sur ve2cuy.com ne fonctionne qu'à partir # d'adresses IP autorisées. Il est possible que ce # manifeste ne fonctionne pas de chez vous. apiVersion: v1 kind: PersistentVolume metadata: name: pv-nfs-ve2cuy spec: capacity: storage: 1Gi volumeMode: Filesystem accessModes: - ReadWriteMany # persistentVolumeReclaimPolicy: Recycle # Le contenu du volune sera effacé sur un delete du PV persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: server: ve2cuy.com path: /var/nfs/420-4D4 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-nfs-ve2cuy spec: storageClassName: nfs resources: requests: storage: 1Gi accessModes: - ReadWriteMany --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx-app spec: replicas: 4 selector: matchLabels: app: nginx-app-label template: metadata: labels: app: nginx-app-label spec: containers: - name: conteneur-nginx image: nginx ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html # Ceci est le dossier web de nginx name: volume-web volumes: - name: volume-web persistentVolumeClaim: claimName: pvc-nfs-ve2cuy --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx-app-label type: LoadBalancer ports: - protocol: TCP # Port à exposer au reseau local K8s port: 80 # Port du conteneur targetPort: 80 # ajout 2 - port externe. Doit être entre 30000 et 32767 nodePort: 30080
# ls -l total 140552 -rw-rw---- 1 mysql mysql 18046976 Apr 28 14:46 aria_log.00000001 -rw-rw---- 1 mysql mysql 52 Apr 28 14:46 aria_log_control -rw-rw---- 1 mysql mysql 9 Apr 28 14:46 ddl_recovery.log -rw-rw---- 1 mysql mysql 868 Apr 28 14:46 ib_buffer_pool -rw-rw---- 1 mysql mysql 100663296 Apr 28 14:46 ib_logfile0 -rw-rw---- 1 mysql mysql 12582912 Apr 28 14:46 ibdata1 -rw-rw---- 1 mysql mysql 12582912 Apr 28 14:46 ibtmp1 -rw-rw---- 1 mysql mysql 0 Apr 28 14:46 multi-master.info drwx------ 2 mysql mysql 4096 Apr 28 14:46 mysql -rw-r--r-- 1 mysql mysql 14 Apr 28 14:46 mysql_upgrade_info drwx------ 2 mysql mysql 4096 Apr 28 14:46 performance_schema drwx------ 2 mysql mysql 12288 Apr 28 14:46 sys drwx------ 2 mysql mysql 4096 Apr 28 14:46 wordpress
Le Pod qui roule le SGBD va tenter un ‘chown’ sur le dossier de partage NFS. Ce qui va provoquer un ‘CrashLoopBackOff’ du Pod et un log :
$ k logs mariadb 2022-04-28 16:44:13+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.7.3+maria~focal started. chown: changing ownership of '/var/lib/mysql/': Operation not permitted chown: changing ownership of '/var/lib/mysql/misterons.txt': Operation not permitted
Pour solutionner ce problème, il faut rouler le conteneur du Pod avec le UID du propriétaire du dossier de partage sur le serveur NFS.
Pour obtenir le UID, il faut utiliser la commande suivante sur le serveur distant:
root@serveur-distant:/# id nobody uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
Ici, le UID de nobody est 65534.
Note: Dans cet exemple, nous prenons pour acquis que ‘nobody’ est propriétaire du dossier de partage NFS.
Pour exécuter le conteneur avec les droits de ce propriétaire, il faut ajouter ceci dans le manifeste:
containers: - name: mysql image: mysql securityContext: runAsUser: 65534 allowPrivilegeEscalation: false
La création des fichiers requis, sur le volume NFS, pour le fonctionnement du SGBD peut prendre de nombreuses minutes selon le lien réseau liant le Pod au volume NFS. Par exemple, le délai sera plus court si le volume est disponible dans le réseau local du Pod mais plus long si le volume NFS est situé dans le réseau Internet.
Cet atelier comporte un bon niveau de difficulté…
Bonus pour ceux et celles qui se sont rendus jusqu’ici 😉:
minikube dashboard