Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Architectures Microservices : mise en oeuvre avec Kubernetes

Architectures Microservices : mise en oeuvre avec Kubernetes

Ce support de cours présente l'orchestrateur Kubernetes (K8s). Après une présentation rapide de la problématique adressée par Kubernetes, nous commencerons par décrire l'architecture d'un cluster Kubernetes et des différentes distributions disponibles pour mettre en place un cluster K8s.

Nous détaillerons ensuite les principaux concepts de Kubernetes à savoir Pod, Deployment, Service et Volume.

Un cluster K3s en bare metal servira de base pour illustrer les différents concepts. Tous les exemples du support de cours sont disponibles à cette adresse : https://github.com/mickaelbaron/kubernetes-examples.

Mickael BARON

January 30, 2022
Tweet

More Decks by Mickael BARON

Other Decks in Programming

Transcript

  1. SOA – Microservices Mickaël BARON – 2022 mailto:baron.mickael@gmail.com ou mailto:baron@ensma.fr

    @mickaelbaron mickael-baron.fr Kubernetes (K8s)
  2. mickael-baron.fr @mickaelbaron Microservices - K8S Page 2 Licence Creative Commons

    Contrat Paternité Partage des Conditions Initiales à l'Identique 2.0 France creativecommons.org/licenses/by-sa/2.0/fr
  3. mickael-baron.fr @mickaelbaron Microservices - K8S Page 3 À propos de

    l’auteur … † Mickaël BARON † Ingénieur de Recherche au LIAS † www.lias-lab.fr † Equipe : Ingénierie des Données et des Modèles † Responsable des plateformes logicielles, « coach » technique † Ancien responsable Java de Developpez.com (2011-2021) † Communauté Francophone dédiée au développement informatique † java.developpez.com † 4 millions de visiteurs uniques et 12 millions de pages vues par mois † 750 00 membres, 2 000 forums et jusqu'à 5 000 messages par jour @mickaelbaron mickael-baron.fr
  4. mickael-baron.fr @mickaelbaron Microservices - K8S Page 4 Plan du cours

    † K8s c’est quoi ? † Architecture cluster † Unité de base d’exécution (POD) † Nommage, namespace et sélection † Déploiement (Deployment, StatefulSets, DaemonSet, Job) † Communication (Services, Ingress, Proxy, Port Forwarding) † Volume et stockage (NFS, CIFS…) † Composants d’un cluster † Outils
  5. mickael-baron.fr @mickaelbaron Microservices - K8S Page 5 Déroulement du cours

    : mise en œuvre K8s † Pédagogie du cours † Comparaison avec Docker † Utilité des microservices † Bases pour démarrer tout seul † Bonnes pratiques † Exemples minimalistes basés sur des images Docker classiques † Pré-requis † Cours architectures orientées services † Introduction aux microservices † Microservices et mise en œuvre avec Docker † Exemples † github.com/mickaelbaron/kubernetes-examples
  6. mickael-baron.fr @mickaelbaron Microservices - K8S Page 6 Ressources : liens

    sur le Web † Sites † kubernetes.io † kube.academy † Blogs † k33g.gitlab.io/KUBERNETES.html † Articles † medium.com/stakater/k8s-deployments-vs-statefulsets-vs-daemonsets-60582f0c62d4 † betterprogramming.pub/local-k3s-cluster-made-easy-with-multipass-108bf6ce577c † Chaînes Youtube † www.youtube.com/c/AurelieVache † www.youtube.com/c/xavki-linux † www.youtube.com/c/TechWorldwithNana † Réseaux sociaux † Ataxya : discord.gg/MgKyx26Kfk † discuss.kubernetes.io
  7. mickael-baron.fr @mickaelbaron Microservices - K8S Page 7 Ressources : bibliothèque

    † Kubernetes – Up & Running † Auteurs : Brendan Burns, Joe Beda et Kelsey Hightower † Éditeur : O’Reilly † Edition : Oct. 2019 - 278 pages – ISBN-13 : 978-1492046530 † Kubernetes: A Step-by-step Guide to Learn and Master Kubernetes † Auteurs : Brayden Smith † Éditeur : Independently published † Edition : Mars. 2019 - 61 pages – ISBN-13 : 978-1090401632 † Kubernetes in Action † Auteurs : Marko Luksa † Éditeur : Manning Publications † Edition : Déc. 2017 - 552 pages – ISBN-13 : 978-1617293726
  8. mickael-baron.fr @mickaelbaron Microservices - K8S Page † Docker est un

    gestionnaire d’images et de conteneurs † Site web : www.docker.com † Documentation : docs.docker.com † Installation : docs.docker.com/engine/installation † L’image permet de packager un microservice † L’image est référencée dans un registre d’images (hub.docker.com) † Le conteneur permet d’instancier un microservice (depuis l’image) † Plusieurs conteneurs d’une même image peuvent être créés † Docker ne fonctionne que sur une machine (Docker Daemon) 8 Docker : rappel Serveur Matériel Système d’Exploitation (OS) Docker Daemon Binaires Bibliothèques Application 1 Binaires Bibliothèques Application 1 Conteneurs
  9. mickael-baron.fr @mickaelbaron Microservices - K8S Page † Les principales problématiques

    rencontrées et comment les résoudre ? † Serveur hôte indisponible ? † « Utiliser plusieurs serveurs hôtes » † Ressources (mémoire, CPU, disque) insuffisantes ? † « Déployer sur le serveur qui dispose des ressources suffisantes » † Charge du conteneur insuffisante ? † « Augmenter le nombre de conteneurs » † Conteneur en défaut ? † « Redémarrer le conteneur » † Nouvelle version application ? † « Déployer la nouvelle image Docker => App + Bibliothèque » † Comment gérer ces problématiques => utilisation d’un orchestrateur 9 Problématiques avec Docker (le pourquoi de K8s)
  10. mickael-baron.fr @mickaelbaron Microservices - K8S Page † Kubernetes est un

    orchestrateur de conteneurs « en complément à Docker » † Développé initialement par Google † Projet open source depuis 2014 géré par † Kubernetes du grec ancien (κυβερνήτης) pour capitaine ou pilote † Acronyme souvent utilisé : K8s => K........s † Sites web de référence † kubernetes.io † Documentation ❤ : kubernetes.io/docs † API : kubernetes.io/docs/reference/kubernetes-api † Quelques alternatives † Swarm (Docker inc.) † Nomad (HashiCorp => www.nomadproject.io) † Mesos (Apache => mesos.apache.org) 10 Kubernetes (K8s)
  11. mickael-baron.fr @mickaelbaron Microservices - K8S Page 11 Kubernetes (K8s) :

    OS du Cloud
  12. mickael-baron.fr @mickaelbaron Microservices - K8S Page 12 Kubernetes (K8s) :

    les principaux concepts Objets Pour nommer et identifier Pods Pour représenter logiquement les conteneurs Déploiement Pour représenter logiquement les Pods Services Pour accéder aux Pods Volumes Pour stocker et partager les données Cluster Composants Kubectl Pour décrire l’architecture physique Pour motoriser K8s Pour communiquer avec le cluster
  13. mickael-baron.fr @mickaelbaron Microservices - K8S Page † Un cluster K8s

    est composé d’un maître et de nœuds de travail † Maître (Master) † Également appelé « Control Pane » † Responsable de la gestion du cluster † Point d’entrée du développeur † Possibilité d’avoir plusieurs maîtres (éviter SPOF) † Nœud de travail (Worker Node) † Également appelé « Minion » † Héberge les conteneurs † Nécessite un moteur de conteneurs : Docker, containerd, CRI-O † Point d’entrée des appels clients † Préférables d’avoir plusieurs nœuds de travail 13 Architecture Cluster Kubernetes : Maître et nœuds de travail Cluster Kubernetes Maître Nœud de travail Single Point of Failure
  14. mickael-baron.fr @mickaelbaron Microservices - K8S Page 14 Architecture Cluster Kubernetes

    : où créer mon cluster ? Solutions cloud clés en main (Turnkey) Solutions Hébergées sur site (On-Premise) ou pas Solutions Locales † Usage : production † Avantages † K8s déjà installé prêt à l’emploi † Administration simplifiée † Inconvénients † Distribution K8s spécifique † Ressources matérielles partagées † Usage : production † Avantages † Choix de la distribution † Ressources non partagées † Inconvénients † Installation K8s † Configuration réseau † Usage : test † Avantage † Installation K8s rapide † Inconvénient † Ressources limitées Serveur bare metal (hypervisé ou pas)
  15. mickael-baron.fr @mickaelbaron Microservices - K8S Page 15 Architecture Cluster Kubernetes

    : construire sa distribution ? † Kubernetes est disponible en téléchargement : github.com/kubernetes/kubernetes † Fonctionne exclusivement sous Linux † Possibilité de télécharger de compiler et de l’installer depuis le dépôt Git † Limites d’une distribution faite « main » ? † Temps de compilation † Des configurations complexes † De nombreux composants à construire avec leurs dépendances † Pourquoi ne pas utiliser une distribution prête à l’emploi ?
  16. mickael-baron.fr @mickaelbaron Microservices - K8S Page 16 Architecture Cluster Kubernetes

    : distributions du marché Distributions « pures » Distributions customisées Distributions cloud Distributions minimalistes † Stricte minimum † Spécifiques aux fournisseurs Cloud † Installation facilitée avec des modules supplémentaires † Légères et souvent déployées via « DockerInDocker »
  17. mickael-baron.fr @mickaelbaron Microservices - K8S Page 17 Architecture Cluster Kubernetes

    : distribution K3s ❤ † K3s est une distribution k8s légère (k3s.io) † Développée pour IoT, outils d’intégration continue, processeur ARM † Un seul binaire de ~ 50 Mo † Distribution qui n’est pas complète † Fonctionnalités K8s « legacy » et « alpha » ne sont pas présentes † SQLite3 est utilisé pour stocker l’état de K8s (au lieu de etcd) † Outil supplémentaire K3d (k3d.io) † Exécuter K3s dans Docker † K3s et K3d seront utilisés dans le tutoriel de manipulation de Kubernetes
  18. mickael-baron.fr @mickaelbaron Microservices - K8S Page 18 Architecture Cluster Kubernetes

    : mon cluster 167.53.81.116 Maître 167.53.81.117 167.53.81.118 Cluster Kubernetes (2 nœuds de travail + 1 maître) † Cluster K8s (1 maître 2 nœuds de travail) utilisé pour les exemples † Bare metal Dell R740, 2 CPUs Intel Xeon Gold 5218 2.3GHz † Hyperviseur XCP-NG (xcp-ng.org) † Description VM : 2 cœurs 4 Go mémoire et 100 Go disque dur † Distribution : Rancher K3s
  19. mickael-baron.fr @mickaelbaron Microservices - K8S Page 19 kubectl l’outil indispensable

    † kubectl est un outil † pour administrer un cluster K8s † en ligne de commande (CLI) † utilisé par l’administrateur d’un cluster K8s † qui communique avec le maître † kubectl n’est pas un outil † pour accéder aux microservices exposés par les conteneurs † Disponible sur tous les systèmes d’exploitation † Aide mémoire : kubernetes.io/docs/reference/kubectl/cheatsheet Maître Nœud de travail Cluster Kubernetes (nœuds de travail + maître)
  20. mickael-baron.fr @mickaelbaron Microservices - K8S Page 20 kubectl l’outil indispensable

    : interroger mon cluster # Configurer l’accès au cluster K8s $ export KUBECONFIG=./k3s.yaml # 🧐 # Le fichier k3s.yaml contient toutes les informations pour accéder au cluster # IP, droits d’accès... # Obtenir des informations sur les ressources utilisées (CPU/mémoire) par les nœuds du cluster $ kubectl top nodes NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% kubernetes-cluster-1 190m 9% 2007Mi 51% kubernetes-cluster-2 78m 3% 1690Mi 43% kubernetes-cluster-3 59m 2% 1712Mi 43% # Obtenir des informations sur les configurations des nœuds du cluster $ kubectl get nodes NAME STATUS ROLES AGE VERSION INTERNAL-IP CONTAINER-RUNTIME kubernetes-cluster-1 Ready control-plane,master 61d v1.21.2+k3s1 167.53.81.116 containerd://1.4.4-k3s2 kubernetes-cluster-2 Ready <none> 60d v1.21.2+k3s1 167.53.81.117 containerd://1.4.4-k3s2 kubernetes-cluster-3 Ready <none> 60d v1.21.2+k3s1 167.53.81.118 containerd://1.4.4-k3s2 # Obtenir des informations détaillées d’un nœud (maître et nœud de travail) $ kubectl describe nodes kubernetes-cluster-1 Name: kubernetes-cluster-1 Roles: control-plane,master Conditions: ... Addresses: ... ... † Options kubectl : top nodes, get nodes, describe nodes
  21. mickael-baron.fr @mickaelbaron Microservices - K8S Page † Pod est †

    l’entité de référence dans K8s † l’entité qui implémente un microservice † Représentation logique de un ou plusieurs conteneurs † Les Pods sont localisés dans les nœuds † Chaque Pod a une adresse IP unique † La communication entre les conteneurs d’un même Pod se font par localhost † Les conteneurs d’un même Pod doivent avoir des ports différents † Chaque Pod déclare des ressources (CPU, mémoire) † La communication entre conteneurs de Pods différents se fait via les services (voir plus tard) 21 Pod : généralités
  22. mickael-baron.fr @mickaelbaron Microservices - K8S Page 22 Pod : représentation

    graphique Nœud de travail d’un cluster Kubernetes avec quatre Pods Pod 1 conteneur 3 conteneurs 2 conteneurs
  23. mickael-baron.fr @mickaelbaron Microservices - K8S Page 23 Pod : exemple

    # Créer un Pod « nginx » basé sur l’image nginx $ kubectl run myfirstpod --image=nginx:1.21.1 pod/myfirstpod created # Lister l’ensemble des Pods (l’option –o configure la sortie, wide est une configuration prédéfinie) # K8s choisit le nœud de travail où sera créé le Pod (kubernetes-cluster-2) $ kubectl get pods –o wide NAME READY STATUS RESTARTS AGE IP NODE myfirstpod 1/1 Running 0 3m31s 10.42.1.36 kubernetes-cluster-2 # 🧐 # 10.42.1.36 est l’IP du Pod # kubernetes-cluster-2 est le nœud où est déployé le Pod # Accéder au conteneur d’un Pod (comme il y a un seul conteneur c’est assez simple) # et affichage du contenu de la page html par défaut de NGINX $ kubectl exec myfirstpod -- more /usr/share/nginx/html/index.html ... <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working...</p> </body> ... </html> † Options kubectl : run, get pods, exec
  24. mickael-baron.fr @mickaelbaron Microservices - K8S Page 24 Pod : exemple

    (suite) † Options kubectl : describe pods, port-forward # Afficher les informations détaillées d’un Pod (contient beaucoup d’information) $ kubectl describe pods myfirstpod Name: myfirstpod Namespace: default ... IP: 10.42.1.37 IPs: IP: 10.42.1.37 Containers: ... Conditions: ... Volumes: ... Events: ... # Rediriger un port du poste local vers un Pod (à des fins de tests, ne pas utiliser en prod !!!) $ kubectl port-forward myfirstpod 8080:80 Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80 # 🧐 # Un « pont » est réalisé entre la machine locale (depuis port 8080) et le Pod (vers port 80) # Processus bloquant, nécessite l’ouverture d’un autre terminal # Tester la redirection de port (depuis l’ordinateur qui exécute les commandes kubectl) $ curl 127.0.0.1:8080
  25. mickael-baron.fr @mickaelbaron Microservices - K8S Page 25 Kubernetes (K8s) :

    système déclaratif † Système Déclaratif ? † L’utilisateur décrit l’état désiré et c’est le système qui fait le travail depuis l’état actuel † Exemple : « j’aimerais une crêpe au sucre » † Système Impératif ? † L’utilisateur réalise des actions pour atteindre l’état désiré depuis un état actuel † Exemple : « avec la pate vous faites une crêpe et vous mettez du sucre dessus » † Docker : déclaratif ou impératif ? † Docker est un système impératif † Docker-compose est un système déclaratif † Kubernetes est un système impératif et déclaratif pour la création d’objets † impératif (création à la volée d’objets) : kubectl create, kubectl delete et kubectl replace † déclaratif (via des fichiers de configuration) : kubectl apply et kubectl diff
  26. mickael-baron.fr @mickaelbaron Microservices - K8S Page 26 Objets : généralités

    apiVersion: v1 kind: Pods metadata: name: mypod labels: environment: production spec: ... † Utilisation de fichiers de configuration pour décrire des objets † Un objet peut décrire † les microservices (conteneurs) à démarrer † les ressources de ces microservices (volumes, réseaux…) † les stratégies liées au comportement de ces microservices (redémarrage, montée en charge…) Version de l’API Kubernetes de cet objet Type d’objet à créer Pods, Deployment, Service, DaemonSet, Jobs, Cronjob… Métadonnées pour identifier l’objet name et labels L’état désiré spécifique à chaque type d’objet
  27. mickael-baron.fr @mickaelbaron Microservices - K8S Page 27 Objets : exemple

    apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer-1 image: nginx:1.21 ports: - containerPort: 80 - name: mycontainer-2 image: alpine:3.14 command: ["watch", "wget", "-qO-", "localhost"] † Description d’un Pod avec deux conteneurs Conteneur web accessible depuis l’intérieur du Pod à l’adresse localhost:80 Second conteneur qui accède au premier conteneur via l’adresse localhost:80 toutes les deux secondes (watch) Le Pod est nommé simplepod Fichier de configuration object/mypod.yaml L’objet est de type Pod
  28. mickael-baron.fr @mickaelbaron Microservices - K8S Page 28 Objets : exemple

    (suite) # Créer un objet Pod à partir d’un fichier de configuration $ kubectl apply –f objects/mypod.yaml pod/mypod created # Lister le Pod nouvellement créé $ kubectl get pods –o wide NAME READY STATUS RESTARTS AGE IP NODE mypod 2/2 Running 0 27m 10.42.1.38 kubernetes-cluster-2 # Afficher les logs du conteneur « mycontainer-1 » $ kubectl logs mypod mycontainer-1 ... ::1 - - [14/Sep/2021:06:51:51 +0000] "GET / HTTP/1.1" 200 615 "-" "Wget" "-" ::1 - - [14/Sep/2021:06:51:53 +0000] "GET / HTTP/1.1" 200 615 "-" "Wget" "-" ::1 - - [14/Sep/2021:06:51:55 +0000] "GET / HTTP/1.1" 200 615 "-" "Wget" "-" # 🧐 # Comme le Pod « mypod » contient deux conteneurs # il faut préciser le conteneur qui affichera les logs # Supprimer un Pod avec ses deux conteneurs $ kubectl delete pods mypod pod "mypod" deleted † Options kubectl : apply, logs et delete pods
  29. mickael-baron.fr @mickaelbaron Microservices - K8S Page 29 Objets : nommage

    † Pourquoi nommer un objet ? † objets qui dépendent d’objets (Selector) † filtrage depuis Kubectl † Identification via name ou les labels † Labels † Une paire de clé/valeur attachée à un objet † Optionnel † Plusieurs labels par objet † Libre de noms † Convention : release, environment, tier, version, app apiVersion: v1 kind: Pod metadata: name: mypodwithlabels labels: release: stable environment: production tier: frontend version: "1.21" spec: containers: - name: mycontainer-1 image: nginx:1.21 ports: - containerPort: 80 ... Fichier de configuration object/mypodwithlabels.yaml
  30. mickael-baron.fr @mickaelbaron Microservices - K8S Page 30 Objets : exemple

    nommage † Options kubectl : get pods, delete pods, delete # Créer un objet Pod à partir d’un fichier de configuration $ kubectl apply –f objects/mypodwithlabels.yaml pod/mypodwithlabels created # Lister les Pods avec les labels (option –show-labels) $ kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS mypodwithlabels 2/2 Running 0 34m release=stable,tier=frontend,version=1.2... # Lister les Pods qui ont des labels avec des valeurs exacts (= ou !=) $ kubectl get pods –l release=stable,version=1.2 NAME READY STATUS RESTARTS AGE mypodwithlabels 2/2 Running 0 36m # Lister les Pods qui ont des labels avec des expressions (in, notin ou exists) $ kubectl get pods –l release=stable,"tier in (frontend)" NAME READY STATUS RESTARTS AGE mypodwithlabels 2/2 Running 0 53m # Supprimer des Pods à partir des labels $ kubectl delete pods –l release=stable pod "mypodwithlabels" deleted # Supprimer tous les objets (pas seulement les Pods) à partir des labels $ kubectl delete –l release=stable error: the server doesn't have a resource type "release=stable"
  31. mickael-baron.fr @mickaelbaron Microservices - K8S Page 31 Objets : namespace

    † Un namespace permet l’isolation des objets pour les regrouper † par projet † par équipe † par famille de composants † Un namespace est un objet (création impérative ou déclarative) † Comment associer un objet à un namespace ? † Dans la déclaration de l’objet † Lors de la commande avec kubectl † Si un namespace est supprimé tous les objets associé seront supprimés † L’utilisation d’un namespace n’est pas obligatoire, mais fortement recommandé † Un namespace n’est pas contenu dans un namespace apiVersion: v1 kind: Namespace metadata: name: mynamespace Fichier de configuration object/mynamespace.yaml
  32. mickael-baron.fr @mickaelbaron Microservices - K8S Page 32 Objets : exemple

    namespace † Options kubectl : get pods, delete pods, delete # Créer un objet Namespace à partir d’un fichier de configuration $ kubectl apply –f objects/mynamespace.yaml namespace/mynamespace created # Lister l’ensemble des Namespaces $ kubectl get namespaces NAME STATUS AGE ... kube-system Active 70d mynamespace Active 15m # 🧐 # Des Namespaces pour le système K8s sont déjà présents # Créer un objet Pod dans un Namespace (option –n) $ kubectl apply –f objects/mypodwithlabels.yaml –n mynamespace pod/mypodwithlabels created # Lister les Pods d’un Namespace $ kubectl get Pod -n mynamespace NAME READY STATUS RESTARTS AGE mypodwithlabels 2/2 Running 0 45s # Définir un namespace par défaut $ kubectl config set-context --current --namespace=mynamespace # Supprimer le namespace par défaut $ kubectl config set-context --current --namespace=mynamespace # Supprimer un Namespace (ainsi que tous les objets associés) $ kubectl delete mynamespace
  33. mickael-baron.fr @mickaelbaron Microservices - K8S Page 33 Objets : nommage,

    namespace et Bonnes Pratiques † Fichier de déclaration † Possibilité de mettre plusieurs déclarations d’objets en séparant par --- † Appliquer toutes les configurations d’un répertoire : kubectl –f apply . † Namespace † Toujours utiliser un namespace lors de la création des objets avec kubectl (option –f) † Éviter de spécifier le namespace dans la déclaration des objets † Label † release : stable, snapshot † environment : dev, qa, production † tier : front, backend, proxy, gateway † version : "1.21" † kubernetes.io/docs/concepts/overview/working-with-objects/common-labels
  34. mickael-baron.fr @mickaelbaron Microservices - K8S Page 34 Les objets pour

    déployer † Nous avons vu précédemment comment créer des Pods manuellement † Problématiques de gérer manuellement des Pods † Comment recréer des Pods si un nœud de travail s’arrête brusquement ? † Comment démarrer des Pods à intervalle régulier ? † Comment réaliser une mise à jour progressive des microservices ? † Utilisation d’un objet de « déploiement » qui est une représentation logique de un ou plusieurs Pods † Différents types d’objets de déploiement † Deployment* † StatefulSets † DaemonSet † Jobs et Cronjob * = étudié par la suite
  35. mickael-baron.fr @mickaelbaron Microservices - K8S Page 35 Deployment † Un

    Deployment est responsable des Pods qui gère 1) Si un Pod ne fonctionne pas correctement 2) Un nouveau Pod sera créé 3) Le Pod qui ne fonctionnait pas correctement sera arrêté † Deployment est à privilégier pour le déploiement de microservices stateless † Gestion de la montée en charge d’un microservice † Création implicite d’un objet ReplicaSet pour gérer le nombre d’instances d’un Pod (replicas) † Gestion de la montée en version d’un microservice (détaillée par la suite)
  36. mickael-baron.fr @mickaelbaron Microservices - K8S Page 36 Deployment : représentation

    graphique Cluster Kubernetes (3 nœuds + 1 maître) Deployment 2 1 conteneur replicas = 1 Deployment 1 2 conteneurs replicas = 3 1 2 1 Pod géré par le déploiement 2 3 Pods gérés par le déploiement 1 Nœud de travail Maître
  37. mickael-baron.fr @mickaelbaron Microservices - K8S Page 37 Deployment : un

    point sur la configuration apiVersion: v1 kind: Deployment metadata: name: mydeployment spec: replicas: 3 selector: matchLabels: app: mypod template: metadata: labels: apps: mypod spec: containers: - name: mycontainer image: nginx:1.19 ports: - containerPort: 80 † Description d’un objet Deployment avec un conteneur L’objet est de type Deployment Trois instances du Pod décrit ci-dessous seront créées Permet la sélection des Pods concernés par ce Deployment Description du Pod à créer Correspondance entre la sélection et le nommage du Pod Obligation de passer par un nommage par label (la sélection se fait obligatoirement par les labels) Fichier de configuration deployment/mydeployment.yaml
  38. mickael-baron.fr @mickaelbaron Microservices - K8S Page 38 Deployment : exemple

    de création † Options kubectl : apply, scale, get et delete # Créer un objet Namespace à partir d’un fichier de configuration $ kubectl apply –f deployment/mynamespace.yaml # Créer un objet Deployment à partir d’un fichier de configuration (déploiement de trois microservice NGINX 1.19) $ kubectl apply -n mynamespace –f deployment/mydeployment.yaml deployment.apps/mydeployment created # Ajouter un microservice (passage de 3 à 4 Pods) depuis la ligne de commande $ kubectl scale -n mynamespace deployment mydeployment --replicas 4 deployment.apps/mydeployment scaled # Lister les Pods gérés par l’objet Deployment $ kubectl get all -n mynamespace NAME READY STATUS RESTARTS AGE pod/mydeployment-dd7856d87-dk5fx 1/1 Running 0 111s pod/mydeployment-dd7856d87-9rnck 1/1 Running 0 111s pod/mydeployment-dd7856d87-6gj5m 1/1 Running 0 111s pod/mydeployment-dd7856d87-r47sm 1/1 Running 0 107s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/mydeployment 4/4 4 4 111s NAME DESIRED CURRENT READY AGE replicaset.apps/mydeployment-dd7856d87 4 4 4 111s # Supprimer le Namespace et tous les objets associés : Pod, Deployment et ReplicaSet (gros intérêt d’un namespace) $ kubectl delete namespace mynamespace namespace "mynamespace" deleted
  39. mickael-baron.fr @mickaelbaron Microservices - K8S Page 39 Deployment : montée

    en version d’un microservice † Des modifications sur un Deployment provoque un enroulement (rollup) † Image : nginx:1.19 => nginx:1.20 † Variable d’environnement † Ressources : requests/limits † Possibilité de consulter l’historique de l’enroulement de déploiement (history) † Possibilité de revenir sur un déploiement précédent (rollback) † Choix de la stratégie de déploiement (construire des nouvelles versions de Pods) † Rolling Update (défaut) : création d’un Pod 2.0, suppression d’un Pod 1.0 et ainsi de suite † Recreate (brute) : suppression de tous les Pod 1.0 et création de Pod 2.0 † Blue/Green (nécessite Istio) : deux versions de Pod (2.0 et 1.0) en même temps † Canary (nécessite Istio) : migration progressive (1.0 vers 2.0)
  40. mickael-baron.fr @mickaelbaron Microservices - K8S Page 40 Deployment : exemple

    de montée en version † Options kubectl : set, rollout history, rollout undo # Créer un objet Namespace à partir d’un fichier de configuration $ kubectl apply –f deployment/mynamespace.yaml # Appliquer une configuration Deployment (image nginx:1.19) $ kubectl apply -f deployment/mydeployment.yaml -n mynamespace $ kubectl annotate deployment -n mynamespace mydeployment kubernetes.io/change-cause="Image en 1.19" # Modification d’un élément de la configuration (image nginx:1.20) $ kubectl set image -n mynamespace deployment mydeployment mycontainer=nginx:1.20 $ kubectl annotate deployment -n mynamespace mydeployment kubernetes.io/change-cause="Image en 1.20" # Appliquer une nouvelle version de la configuration Deployment (image nginx:1.21) $ kubectl apply -f deployment/mydeployment-1.21.yaml -n mynamespace $ kubectl annotate deployment -n mynamespace mydeployment kubernetes.io/change-cause="Image en 1.21" # Visualiser l’enroulement complet (rollout) $ kubectl rollout history deployment mydeployment -n mynamespace REVISION CHANGE-CAUSE 1 Image en 1.19 2 Image en 1.20 3 Image en 1.21 # 🧐 # kubectl annotate ... a permis d’avoir des informations dans CHANGE-CAUSE sinon <none> # Rollback sur une révision précédente $ kubectl rollout undo deployment mydeployment -n mynamespace --to-revision=1
  41. mickael-baron.fr @mickaelbaron Microservices - K8S Page 41 Deployment : encore

    plein de choses à découvrir † Montée en charge † Horizontal Pod Autoscaling (HPA) : conditionnelle en fonction de métrique † Vertical Pod Autoscaling (VPA) : faire varier les ressources (CPU, mémoire) † Ressources d’un Pod : demandes et les limites † requests : minimum pour un Pod (pour répartir la charge dans le cluster) † limits : maximum pour un Pod (pour la santé d’un Pod) † État de santé d’un Pod † readinessProbe : savoir quand votre microservice a fini de démarrer † livenessProbe : savoir si votre microservice est toujours fonctionnel
  42. mickael-baron.fr @mickaelbaron Microservices - K8S Page † StatefulSets † Pour

    créer des Pods avec des identifiants uniques † Usage : bases de données † DaemonSet † Pour créer des Pods sur tous les nœuds de travail † Pas de montée en charge † Usage : monitoring et gestion des logs † Jobs, Cronjob † Pour créer des Pods à certains moments † Usage : créer des dumps de bases de données † La plupart des concepts précédents : Rollout, HPA, VPA, ressources (Requests, Limits) et Probe sont valables pour les autres objets de déploiement 42 Les objets pour déployer : et les autres ? StatefulSets DaemonSet Jobs CronJob
  43. mickael-baron.fr @mickaelbaron Microservices - K8S Page 43 Services : généralités

    † Les services permettent de communiquer avec les Pods de l’intérieur et de l’extérieur d’un cluster † Problématiques † Comment accéder à l’IP d’un Pod qui peut souvent changer ? † Comment accéder à plusieurs instances d’un Pod (ReplicaSet) ? † Comment accéder aux instances d’un Pod hébergées plusieurs nœuds ? † Les besoins de communication † Communication « Inter Pod » (communication entre conteneurs) => déjà vu via localhost † Pod à Pod (Exemple : backend => base de données) † De l’extérieur vers Pod (Exemple : client => frontend ; frontend => backend) † Pod vers l’extérieur
  44. mickael-baron.fr @mickaelbaron Microservices - K8S Page † K8s propose plusieurs

    objets de type Service † ClusterIP* : exposer le service sur une IP interne au cluster (Pod à Pod) † NodePort* : exposer le service sur l'IP de chaque nœud sur un port statique (Ext. vers Pod) † LoadBalancer : exposer le service via un équilibreur de charge d’un Cloud (Ext. vers Pod) † ExternalName : associe le service au contenu du champ externalName (Pod vers Ext.) † Dépendances entre type de Service (boites gigognes) † Un service LoadBalancer va créer un service NodePort et ClusterIP † Un service NodePort va créer un service ClusterIP † Ingress est une solution qui n’est pas un Service, mais permet de communiquer 44 Services : généralités * = étudié par la suite ClusterIP Ex :10.10.9.1 NodePort LoadBalancer
  45. mickael-baron.fr @mickaelbaron Microservices - K8S Page 45 Services : représentation

    graphique Cluster Kubernetes (3 nœuds de travail + 1 maître) 1 objet de type Service exposant 3 Pods Nœud de travail Maître 1 objet de type Service exposant 1 Pod 2 objets de type Deployment Pod Pod
  46. mickael-baron.fr @mickaelbaron Microservices - K8S Page 46 Services : ClusterIP

    † Un service ClusterIP est le service par défaut dans K8s † ClusterIP un service accessible uniquement à l’intérieur du cluster † Pas d’accès depuis l’extérieur † Communication entre Pod (microservice) † Principe de fonctionnement † Exposer le service sur une IP et un CNAME qui distribue les requêtes vers l’adresse IP d’un Pod † Si plusieurs Pods, le service ClusterIP distribue aléatoirement les requêtes † L’utilisation du CNAME du service (nom) impose que les Pods soient dans le même NAMESPACE myclusterip 10.10.9.1 10.10.10.1 10.10.10.2 10.10.10.3 https://iamaashishpatel.medium.com
  47. mickael-baron.fr @mickaelbaron Microservices - K8S Page 47 Services : exemple

    ClusterIP apiVersion: v1 kind: Service metadata: name: myclusteripservice spec: selector: app: mypod type: ClusterIP ports: - protocol: TCP targetPort: 7000 port: 8080 externalIPs: - 80.11.12.10 - 80.11.12.11 † Description d’un objet Service de type ClusterIP Fichier de configuration service/myclusteripservice.yaml L’objet est de type Service Le nom est important car c’est un nom canonique pour une entrée dans le DNS Le service va rediriger les requêtes vers les Pods identifiés dans cette sélection Il s’agit d’un service de type ClusterIP (valeur optionnelle car valeur par défaut) Le protocole pour la communication (valeur par défaut = TCP) Le port utilisé par les Pods (identifiés par la sélection) Le port utilisé pour communiquer avec le service (Sous Docker ~ 8080:80) Possibilité de définir des IP alternatives pour le service
  48. mickael-baron.fr @mickaelbaron Microservices - K8S Page 48 Services : exemple

    ClusterIP † Options kubectl : apply, get, run, exec # Créer des objets Namespace et Deployment pour construire 3 Pods de même image : mickaelbaron/simple_nodejs $ kubectl apply –f services/mynamespace.yaml $ kubectl apply -f services/mydeployment.yaml -n mynamespace # Appliquer une configuration service ClusterIP qui va exposer en interne (uniquement dans le cluster) les 3 pods $ kubectl apply –f services/myclusteripservice.yaml –n mynamespace # Récupérer l’information du service pour avoir l’IP $ kubectl get service –n mynamespace NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE myclusteripservice ClusterIP 10.43.10.236 80.11.12.10,80.11.12.11 8080/TCP 118m # 🧐 # Le service est en écoute sur le port 8080 depuis # - les adresses IP : 10.43.10.236, 80.11.12.10, 80.11.12.11 # - le CNAME : myclusteripservice # Accéder aux 3 Pods via l’IP du service depuis un autre Pod basé sur l’image Docker NGINX $ kubectl run myfirstpod --image=nginx:1.21.1 –n mynamespace $ kubectl exec -it myfirstpod -n mynamespace -- /bin/bash -c "for i in {1..4}; do curl -s http://10.43.10.236:8080 && echo ""; done" Hello World from: Host mydeployment-55f6b7c8f5-5zp4r Hello World from: Host mydeployment-55f6b7c8f5-xwx2l Hello World from: Host mydeployment-55f6b7c8f5-bkjg7 Hello World from: Host mydeployment-55f6b7c8f5-bkjg7 # 🧐 # La distribution des requêtes se fait de manière aléatoire
  49. mickael-baron.fr @mickaelbaron Microservices - K8S Page 49 Services : exemple

    ClusterIP (suite) † Options kubectl : scale, exec, delete # L’ajout d’une nouvelle instance d’un Pod est automatiquement géré par le service $ kubectl scale -n mynamespace deployment mydeployment --replicas 4 $ kubectl exec -it myfirstpod -n mynamespace -- /bin/bash -c "for i in {1..4}; do curl -s http://10.43.10.236:8080 && echo ""; done" Hello World from: Host mydeployment-55f6b7c8f5-xwx2l ... # Accéder aux 4 Pods via le CNAME du service depuis un autre Pod (nécessite d’être dans le même namespace) $ kubectl exec -it myfirstpod –n mynamespace -- /bin/bash -c "for i in {1..4}; do curl -s http://myclusteripservice:8080 && echo ""; done" Hello World from: Host mydeployment-55f6b7c8f5-xwx2l ... # 🧐 # Cette solution via le CNAME est à utiliser en priorité. # Possibilité d’accéder au service depuis un nœud du cluster (uniquement via l’IP) $ ssh ubuntu@167.53.81.116 'for i in {1..4}; do curl -s http://10.43.10.236:8080 && echo ""; done’ Hello World from: Host mydeployment-55f6b7c8f5-xwx2l ... # 🧐 # Le DNS qui expose le CNAME du service n’est pas connu des nœuds (maître + nœuds de travail). # Le DNS est un Pod exposé également par un service de type ClusterIP # Supprimer le Namespace et tous les objets associés (Pods, Deployment, Service et Namespace) $ kubectl delete namespace mynamespace
  50. mickael-baron.fr @mickaelbaron Microservices - K8S Page 50 Services : exemple

    ClusterIP (suite) † Options kubectl : proxy # Créer des objets Namespace et Deployment pour construire 3 Pods de même image : mickaelbaron/simple_nodejs $ kubectl apply -f services/mynamespace.yaml $ kubectl apply -f services/mydeployment.yaml -n mynamespace # Création d’un proxy du poste local vers le cluster (à des fins de tests, ne pas utiliser en prod !!!) $ kubectl proxy –port=8080 Starting to serve on 127.0.0.1:8080 # 🧐 # Un « reverse proxy » est démarré sur la machine locale (à l’écoute du port 8080) et permet d’accéder à l’API de K8s # A noter que port-forward ne permettait que de rediriger un port du poste local vers un Pod # Processus bloquant, nécessite l’ouverture d’un autre terminal # Lister l’ensemble des namespaces du cluster $ curl -s http://localhost:8080/api/v1/namespaces | jq -r '.items[].metadata.name' default kube-system Mynamespace ... # Accéder à un Pod depuis un service ClusterIP $ curl http://localhost:8080/api/v1/namespaces/mynamespace/services/myclusteripservice:8080/proxy/ Hello World from: Host mydeployment-55f6b7c8f5-xwx2l # 🧐 # L’accès au service ne peut se faire que par son identifiant K8s. L’adresse IP n’est pas un identifiant. # Supprimer le Namespace et tous les objets associés (Pods, Deployment, Service et Namespace) $ kubectl delete namespace mynamespace
  51. mickael-baron.fr @mickaelbaron Microservices - K8S Page † NodePort un service

    accessible depuis l’extérieur du cluster † Principe de fonctionnement † Exposer le service sur une IP et un CNAME qui distribue les requêtes vers l’adresse IP d’un Pod † Exposer le service sur l’IP de chaque nœud à un port statique (nodePort) † Un service NodePort s’appuie sur un service ClusterIP † Plage du nodePort : 30000 – 32767 † Pour accéder au service NodePort depuis l’extérieur † <IP Nœud>:<nodePort> 51 Services : NodePort mynodeport 10.10.9.1 10.10.10.1 10.10.10.2 10.10.10.3 port : 3000 port : 3000 16.53.81.116 16.53.81.117 https://iamaashishpatel.medium.com
  52. mickael-baron.fr @mickaelbaron Microservices - K8S Page 52 Services : exemple

    NodePort † Description d’un objet Service de type NodePort apiVersion: v1 kind: Service metadata: name: mynodeportservice spec: selector: app: mypod type: NodePort ports: - protocol: TCP targetPort: 7000 port: 8080 nodePort: 30001 externalIPs: - 80.11.12.12 L’objet est de type Service Le nom est important car c’est un nom canonique pour une entrée dans le DNS Il s’agit d’un service de type NodePort Le port utilisé par les Pods (identifiés par la sélection) Le port utilisé pour communiquer avec le service en interne (ClusterIP) Le port qui sera exposé au niveau de chaque nœud du Cluster Fichier de configuration service/mynodeipservice.yaml
  53. mickael-baron.fr @mickaelbaron Microservices - K8S Page 53 Services : exemple

    NodePort # Créer des objets Namespace et Deployment pour construire 3 Pods de même image : mickaelbaron/simple_nodejs $ kubectl apply -f services/mynamespace.yaml $ kubectl apply -f services/mydeployment.yaml -n mynamespace # Appliquer une configuration service NodePort qui va exposer en interne et en externe les 3 pods $ kubectl apply –f services/mynodeportipservice.yaml –n mynamespace # Récupérer l’information du service pour avoir l’IP $ kubectl get service –n mynamespace NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mynodeportservice NodePort 10.43.166.110 80.11.12.12 8080:30001/TCP 23m # Accéder aux 3 Pods via l’IP du service depuis un autre Pod (comme pour ClusterIP) $ kubectl run myfirstpod --image=nginx:1.21.1 –n mynamespace $ kubectl exec -it myfirstpod -n mynamespace -- /bin/bash -c "for i in {1..4}; do curl -s http://mynodeportservice:8080 && echo ""; done" Hello World from: Host mydeployment-7cd754c9bd-54t5g ... # Accéder aux 3 Pods via l’IP d’un nœud (maître et nœud de travail) for i in {1..4}; do curl -s http://167.53.81.116:30001 && echo ""; done Hello World from: Host mydeployment-7cd754c9bd-54t5g ... # 🧐 # Le service n’est pas accessible depuis son CNAME puisque le DNS n’est accessible que dans les Pods du cluster K8s # Supprimer le Namespace et tous les objets associés (Pods, Deployment, Service et Namespace) $ kubectl delete namespace mynamespace † Options kubectl : apply, get, run, exec, delete
  54. mickael-baron.fr @mickaelbaron Microservices - K8S Page 54 Services : LoadBalancer

    myloadbalancer 10.10.9.1 10.10.10.1 10.10.10.2 10.10.10.3 port : 3000 port : 3000 16.53.81.116 16.53.81.117 Load Balancer † LoadBalancer un service accessible depuis l’extérieur du cluster † Principe de fonctionnement † Créer des services ClusterIP et NodePort † Exposer le service sur un équilibreur de charge d’un fournisseur de Cloud † Problématique : ne fonctionne que sur les fournisseurs de Cloud (AWS, Azure et GCP) † Solutions alternatives † MetalLB (metallb.universe.tf) † kube-vip (kube-vip.io) https://iamaashishpatel.medium.com
  55. mickael-baron.fr @mickaelbaron Microservices - K8S Page 55 Services : Bonnes

    Pratiques † Concaténer les configurations de services et de déploiements dans un même fichier séparés par des --- † Ne pas utiliser Service pour tester les Pods, des solutions existent † kubectl port-forward : redirige un port du poste local vers un Pod † kubectl proxy : crée un proxy du poste local vers le cluster kind: Service apiVersion: v1 metadata: name: myclusteripservice1 ... --- kind: Deployment apiVersion: v1 metadata: name: mydeployment1 ... Rappel : éviter de spécifier un namespace dans le fichier de configuration Permet de séparer la configuration des objets
  56. mickael-baron.fr @mickaelbaron Microservices - K8S Page 56 Ingress † Contraintes

    pour accéder à un objet Service (synthèse) † ClusterIP : non accessible depuis l’extérieur † NodePort : nécessite de réserver un port sur tout le cluster même si aucun Pod ne s’exécute † LoadBalancer : pas disponible sur un cluster bare metal (réserver aux fournisseurs de Cloud) † C’est quoi un Ingress ? † Règle qui permet de relier une URL à un objet service † Un contrôleur Ingress permet de piloter un Reverse Proxy pour implémenter les règles † Ce n’est pas un objet de type Service † Plus besoin de passer par un service NodePort, un service de type ClusterIP suffit
  57. mickael-baron.fr @mickaelbaron Microservices - K8S Page 57 Ingress 16.53.81.116/mypath1 16.53.81.117/mypath2

    mydomain.test *.mydomain.test https://iamaashishpatel.medium.com
  58. mickael-baron.fr @mickaelbaron Microservices - K8S Page 58 Ingress : exemple

    (Fanout) apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress spec: rules: - http: paths: - path: /mypath1 pathType: Prefix backend: service: name: myclusteripservice1 port: number: 8080 - path: /mypath2 pathType: Prefix backend: service: name: myclusteripservice2 port: number: 8080 † Description d’un objet Ingress via configuration Fanout Fichier de configuration service/myingress.yaml L’objet est de type Ingress Le service myclusteripservice1 est accessible depuis l’URL http://<IP_NODE>/mypath1 Le service myclusteripservice2 est accessible depuis l’URL http://<IP_NODE>/mypath2
  59. mickael-baron.fr @mickaelbaron Microservices - K8S Page 59 Ingress : exemple

    (Fanout) # Créer 1 objet Namespace, 4 objets Deployment/Service pour déployer 12 Pods de même image : mickaelbaron/simple_nodejs $ kubectl apply -f services/mynamespace.yaml $ kubectl apply -f services/myfulldeployment.yaml -n mynamespace # Appliquer une configuration Ingress qui va exposer en externe les services myclusteripservice1 et myclusteripservice2 $ kubectl apply –f services/myingress.yaml –n mynamespace # Obtenir des informations de l’objet Ingress $ kubectl describe ingress –n mynamespace myingress Name: myingress Namespace: mynamespace Address: 167.53.82.116,167.53.82.117,167.53.82.118 Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) Rules: Host Path Backends ---- ---- -------- * /mypath1 myclusteripservice1:8080 (10.42.2.128:7000,10.42.2.129:7000,10.42.2.130:7000) /mypath2 myclusteripservice2:8080 (10.42.1.121:7000,10.42.1.122:7000,10.42.2.131:7000) ... # Les Pods diffusés par le service myclusteripservice1 sont accessibles depuis les URLs suivantes $ curl 167.53.82.116/mypath1 Hello World from: Host mydeployment1-6695f84f6-tqvp2/mypath1 First microservice # Les Pods diffusés par le service myclusteripservice2 sont accessibles depuis les URLs suivantes $ curl 167.53.82.116/mypath2 Hello World from: Host mydeployment2-557f66bcdb-wjjp4/mypath2 Second microservice † Options kubectl : apply, describe
  60. mickael-baron.fr @mickaelbaron Microservices - K8S Page 60 Ingress : exemple

    (Hôtes virtuels) † Description d’un objet Ingress pour des hôtes virtuels apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress spec: rules: - host: "mydomain.test" http: paths: - path: / pathType: Prefix backend: service: name: myclusteripservice3 port: number: 8080 - host: "*.mydomain.test" http: paths: - path: / pathType: Prefix backend: service: name: myclusteripservice4 port: number: 8080 Fichier de configuration service/myingresswithhosts.yaml L’objet est de type Ingress Le service myclusteripservice3 est accessible depuis l’URL http://mydomain.test Le service myclusteripservice4 est accessible depuis l’URL http://*.mydomain.test
  61. mickael-baron.fr @mickaelbaron Microservices - K8S Page 61 Ingress : exemple

    (Hôtes virtuels) † Options kubectl : apply, describe # Appliquer une configuration Ingress qui va exposer en externe les services myclusteripservice3 et myclusteripservice4 $ kubectl apply –f services/myingresswithhosts.yaml –n mynamespace # Obtenir des informations de l’objet Ingress $ kubectl describe ingress –n mynamespace myingresswithhosts Name: myingresswithhosts Namespace: mynamespace Address: 167.53.82.116,167.53.82.117,167.53.82.118 Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) Rules: Host Path Backends ---- ---- -------- mydomain.test / myclusteripservice3:8080 (10.42.0.58:7000,10.42.1.119:7000,10.42.2.133:7000) *.mydomain.test / myclusteripservice4:8080 (10.42.0.59:7000,10.42.1.120:7000,10.42.2.132:7000) ... # 🧐 # Configuration d’un DNS en local pour répondre aux requêtes sur les hôtes virtuels # Les Pods diffusés par le service myclusteripservice3 sont accessibles depuis l’URL suivante $ curl mydomain.test Hello World from: Host mydeployment3-79b56f8454-4mt9x Third microservice # Les Pods diffusés par le service myclusteripservice4 sont accessibles depuis l’URL suivante $ curl dev.mydomain.test Hello World from: Host mydeployment4-d5fdfd86-plhb8 Fourth microservice
  62. mickael-baron.fr @mickaelbaron Microservices - K8S Page 62 Contrôleur Ingress du

    marché † Un contrôleur Ingress pilote un Reverse Proxy (RP) pour implémenter des règles qui relient une URL à un objet service † Contrôleur Ingress installé par défaut au niveau des distributions k8s † Contrôleurs Ingress disponibles basés sur les principaux Reverse Proxy (RP) † Traefik : disponible dans K3s (doc.traefik.io/traefik/providers/kubernetes-ingress) † NGINX : basé sur le RP très répandu (www.nginx.com/products/nginx-ingress-controller) † HAProxy : différentes implémentations disponibles † haproxy-ingress.github.io † github.com/haproxytech/kubernetes-ingress † voyagermesh.com
  63. mickael-baron.fr @mickaelbaron Microservices - K8S Page 63 Stockage via les

    volumes : problématique † Les données d’un Pod sont volatiles : toutes les données produites par un Pod (depuis ses conteneurs) sont perdues lors de sa destruction † Type de données † données applicatives (base de données) † logs † fichiers de configuration † fichiers de partage… † Comment s’assurer que si un Pod est recréé, les données précédentes soient restaurées ? => Utilisation des Volumes
  64. mickael-baron.fr @mickaelbaron Microservices - K8S Page 64 Stockage via les

    volumes : généralités † Un Volume représente un espace de stockage contenant des données et accessible à travers plusieurs conteneurs d’un même Pod ou de Pods différents † Où est monté l’espace de stockage du Volume ? † Local : hébergé sur le système de fichiers d’un nœud du cluster K8s † Distant : utilise un protocole de communication (NFS, SMB/CIFS…) † Quels sont les besoins de partage de l’espace de stockage ? † Inter-Pod (conteneurs d’un même Pod) † Inter-nœud (Pod à Pod)
  65. mickael-baron.fr @mickaelbaron Microservices - K8S Page 65 Stockage via les

    volumes : généralités † K8s fournit de nombreux types de volumes † hostPath : monte un dossier ou un fichier depuis le système de fichiers du nœud hôte du Pod † emptyDir : monte un dossier vide pour la communication des conteneurs d’un même nœud † Dossier réseau : NFS, CIFS, Ceph, Google Compute Engine Persistent Disk…) † PersistentVolumeClaim : pour réutiliser des espaces de stockage existants sur le Cluster † L’ensemble des types de volumes sont disponibles 👇 † kubernetes.io/docs/concepts/storage/volumes † Comment déclarer un type de volume et ses paramètres éventuels ? † Dans la description du Pod (exemples avec hostPath et emptyDir 👉) † En créant des Volumes persistants (PersistentVolume)
  66. mickael-baron.fr @mickaelbaron Microservices - K8S Page 66 Stockage via les

    volumes : représentation graphique Nœud de travail d’un cluster Kubernetes avec quatre Pods et des volumes Pod 1 conteneur 3 conteneurs 2 conteneurs 1 volume 2 volumes 1 volume
  67. mickael-baron.fr @mickaelbaron Microservices - K8S Page 67 Stockage via les

    volumes : déclaration dans un Pod apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer image: nginx:latest ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html name: myvolume volumes: - name: myvolume <TYPE VOLUME>: PARAMETRE_1: ... PARAMETRE_2: ... Volume déclaré à l’intérieur du Pod Le chemin où ce Volume sera accessible depuis le Pod Le nom du Volume Début de la déclaration du Volume En fonction du type de Volume différents paramètres disponibles
  68. mickael-baron.fr @mickaelbaron Microservices - K8S Page 68 Type Stockage hostPath

    † Un volume de type hostPath permet de monter une ressource depuis le système de fichiers du nœud hôte du Pod † Une ressource peut être un fichier ou un répertoire † Cas d’usage † accéder aux éléments internes du nœud (/var/lib/dock ou /sys) => Docker dans Docker † accéder à un répertoire distant monté sur les systèmes hôtes de tous les nœuds † Précaution † Difficulté d’utiliser un volume hostPath sur un environnement multi-nœuds † Ne pas oublier qu’il n’est pas possible de choisir le nœud d’un Pod
  69. mickael-baron.fr @mickaelbaron Microservices - K8S Page 69 Type Stockage :

    exemple hostPath apiVersion: v1 kind: Deployment metadata: name: mydeploymentwithhostpath spec: replicas: 5 selector: ... template: ... spec: containers: - name: mynginx image: nginx:1.21 ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html name: myhostpathvolume volumes: - name: myhostpathvolume hostPath: path: /myhostpath type: DirectoryOrCreate † Déclarer un volume de type hostPath dans un Pod Fichier de configuration volumes/myhostpath.yaml Déclaration d’une configuration Deployment pour créer 3 Pods (1 conteneur) La déclaration du Volume de type hostPath path : attribut précisant le chemin sur le système de fichier du hôte type : pour préciser que le dossier doit être créé
  70. mickael-baron.fr @mickaelbaron Microservices - K8S Page 70 Type Stockage :

    exemple hostPath † Options kubectl : apply, get # Appliquer une configuration Deployment+Service (NodePort = 30001) dans le Namespace mynamespace $ kubectl apply –f volumes/myhostpath.yaml –n mynamespace # Lister les Pods créés (Pods disponibles sur deux nœuds) $ kubectl get pods -n mynamespace -o wide NAME READY STATUS RESTARTS AGE IP NODE mydeploymentwithhostpath-776c7487f6-25gn2 1/1 Running 0 81m 10.42.1.123 kubernetes-cluster-2 mydeploymentwithhostpath-776c7487f6-qplmp 1/1 Running 0 81m 10.42.1.124 kubernetes-cluster-2 mydeploymentwithhostpath-776c7487f6-jhbmr 1/1 Running 0 79m 10.42.2.136 kubernetes-cluster-3 # Accéder au contenu web d’un Pod (accessible depuis le service NodePort) $ curl 167.53.81.116:30001 => Erreur 403 # 🧐 # Il n’y a pas de contenu dans le dossier /usr/share/nginx/html de ce Pod (problème pour tous les Pods) # Ajouter un fichier index.html dans le dossier /myhostpath du nœud kubernetes-cluster-2 $ ssh ubuntu@167.53.81.117 "sudo sh -c 'echo "Bonjour depuis le noeud 2" > /myhostpath/index.html'" # Accéder au contenu web d’un Pod $ curl 167.53.81.116:30001 => Bonjour depuis le noeud 2 $ curl 167.53.81.116:30001 => Erreur 403 # 🧐 # Seul le nœud kubernetes-cluster-2 fonctionne, nécessite d’impacter tous les nœuds où le Pod est déployé $ ssh ubuntu@167.53.81.118 "sudo sh -c 'echo "Bonjour depuis le noeud 3" > /myhostpath/index.html'" $ curl 167.53.81.116:30001 => Bonjour depuis le noeud 2 $ curl 167.53.81.116:30001 => Bonjour depuis le noeud 3 $ curl 167.53.81.116:30001 => Bonjour depuis le noeud 3
  71. mickael-baron.fr @mickaelbaron Microservices - K8S Page 71 Type Stockage emptyDir

    † Un volume de type emptyDir est non persistant et permet de partager des données entre les conteneurs d’un même Pod † Le contenu d’un volume emptyDir est vide à sa création † Cas d’usage † un espace de travail commun entre différents conteneurs d’un même Pod † un point de reprise après un arrête brutal (crash) lors d’un traitement long † Où sont stockées les données ? † Sur disque (par défaut), si redémarrage du nœud les données conservées † En mémoire, si redémarrage du nœud les données ne sont pas conservées
  72. mickael-baron.fr @mickaelbaron Microservices - K8S Page 72 Type Stockage :

    exemple emptyDir † Déclarer un volume de type emptyDir dans un Pod apiVersion: apps/v1 kind: Deployment metadata: name: mydeploymentwithemptydir spec: replicas: 1 selector: matchLabels: app: mypodforemptydir template: metadata: labels: app: mypodforemptydir spec: containers: - name: myweb image: nginx:1.21 ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html name: myemptydirvolume - name: mywork image: alpine:3.14 command: ["/bin/sh","-c"] args: - while true; do date > /temp/index.html; sleep 1; done volumeMounts: - mountPath: /temp name: myemptydirvolume volumes: - name: myemptydirvolume emptyDir: medium: Memory Fichier de configuration volumes/myemptydir.yaml La déclaration du Volume de type emptyDir Le Volume de type emptyDir est géré en mémoire Création d’un fichier toutes les 1 seconde
  73. mickael-baron.fr @mickaelbaron Microservices - K8S Page 73 Type Stockage :

    exemple emptyDir † Options kubectl : apply, get # Appliquer une configuration Deployment+Service (NodePort = 30002) dans le Namespace mynamespace $ kubectl apply –f volumes/myhostpath.yaml –n mynamespace # Lister les Pods créés (Pods disponibles sur deux nœuds) $ kubectl get pods -n mynamespace -o wide NAME READY STATUS RESTARTS AGE IP NODE mydeploymentwithemptydir-796cf7c49d-vxlt8 2/2 Running 0 81m 10.42.1.153 kubernetes-cluster-3 # Accéder au contenu web d’un Pod (accessible depuis le service NodePort) $ curl 167.53.81.116:30001 => Wed Dec 8 11:20:08 UTC 2021 # 🧐 # L’accès au contenu du Pod se fait via l’intermédiaire du conteneur myweb dont le contenu (index.html) a été alimenté # par le conteneur mywork $ kubectl exec -it mydeploymentwithemptydir-796c... -n mynamespace -c myweb -- more /usr/share/nginx/html/index.html Wed Dec 8 11:30:46 UTC 2021 $ kubectl exec -it mydeploymentwithemptydir-796c... -n mynamespace -c mywork -- more /temp/index.html Wed Dec 8 12:18:27 UTC 2021 # 🧐 # Les deux conteneurs partagent le même contenu du dossier temporaire qui est détruit si le Pod est supprimé.
  74. mickael-baron.fr @mickaelbaron Microservices - K8S Page 74 Type Stockage :

    NFS et CIFS † Les types de stockage emptyDir et hostPath atteignent leurs limites quand il faut conserver les données sur plusieurs nœuds † Solution : préférer l’utilisation de dossiers réseaux apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer image: nginx:latest ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html name: mynfsvolume volumes: - name: mynfsvolume nfs: server: 1.2.3.4 path:"nfs/test" apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer image: nginx:latest ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html name: mycifsvolume volumes: - name: mycifsvolume flexVolume: driver: "fstab/cifs" fsType: "cifs" secretRef: name: "cifs-secret" options: networkPath: "//1.2.3.5/dir" mountOptions: "dir_mode=0755, file_mode=0644,noperm" Le type de stockage NFS est géré nativement par K8s NFS CIFS Le type de stockage CIFS n’est pas géré nativement => github.com/fstab/cifs
  75. mickael-baron.fr @mickaelbaron Microservices - K8S Page 75 Stockage via les

    volumes persistants : problématique † Actuellement dans la configuration d’un Pod, nous devons définir † Le type de Volume utilisé (hostPath, emptyDir, NFS, CIFS…) † Les paramètres de configuration du Volume (IP, droits d’accès…) † Le développeur doit uniquement préciser ses besoins † La volumétrie † La politique d’accès (lecture, écriture, lecture/écriture) par un ou plusieurs nœuds du Cluster † L’administrateur du cluster doit configurer les éléments suivants sur le cluster † Le type de Volume † Les paramètres de configuration du Volume † La volumétrie disponible † La restriction sur la politique d’accès
  76. mickael-baron.fr @mickaelbaron Microservices - K8S Page 76 Stockage via les

    volumes persistants : généralités † Solution proposée par K8s † Fournir une configuration de besoin => PersistentVolumeClaim † Fournir une configuration de stockage => PersistentVolume † Comment créer des objets PersistentVolume ? † Statiquement : explicitement par l’administrateur (étudié dans ce cours) † Dynamiquement : par l’intermédiaire d’un StorageClass (non étudié dans ce cours) † Un PersistentVolume ne peut être associé à un namespace † StorageClass, c’est quoi ? † Une abstraction qui permet d’éviter de créer explicitement un PersistentVolume † Nécessite un « Provisioner » par type de Volume † kubernetes.io/docs/concepts/storage/storage-classes
  77. mickael-baron.fr @mickaelbaron Microservices - K8S Page 77 Stockage via les

    volumes persistants : PV et PVC NFS Administrateur Développeur Persistent Volume 1 Configuration d’un stockage réseau depuis le Cluster K8s 2 Création d’un PersistentVolume (PV) La mise à disposition Persistent VolumeClaim 3 Création d’un PersistentVolumeClaim (PVC) Les besoins du Pod 4 K8s cherche un PV en fonction du besoin exprimé dans le PVC 5 Création d’un Pod référençant PVC Schéma basé sur Kubernetes in Action Page 176
  78. mickael-baron.fr @mickaelbaron Microservices - K8S Page 78 Stockage via les

    volumes persistants : exemple † Définition d’un objet PersistentVolume (en mode statique) Administrateur kind: PersistentVolume apiVersion: v1 metadata: name: mypv labels: owner: mickaelbaron spec: storageClassName: "" capacity: storage: 1Gi accessModes: - ReadOnlyMany nfs: server: 1.2.3.4 path: "/nfs/test" Fichier de configuration volumes/mypv.yaml Le mode d’accès à ce module persistant (lecture seulement depuis plusieurs nœuds) ReadWriteOnce ReadOnlyMany ReadWriteMany ReadWriteOncePod Indique la capacité de ce volume persistant (Gibibyte ~ Gigabyte) En mode statique, la valeur du storageClassName doit être vide Utilisation des labels pour définir des contraintes supplémentaires
  79. mickael-baron.fr @mickaelbaron Microservices - K8S Page 79 Stockage via les

    volumes persistants : exemple † Définition du besoin en volume persistant via PersistentVolumeClaim Développeur kind: PersistentVolumeClaim apiVersion: v1 metadata: name: mypvc spec: storageClassName: "" accessModes: - ReadOnlyMany resources: requests: storage: 1Gi selector: matchLabels: owner: mickaelbaron En mode statique, la valeur du storageClassName doit être vide Recherche un volume persistant qui peut être monté par plusieurs nœuds Recherche un volume persistant qui a au moins 1Gi (Gibibyte ~ Gigabyte) Fichier de configuration volumes/mypv.yaml † Recherche un volume persistant † Autorisé à être utilisé par x nœuds † D’une capacité de 1 Gi † Le propriétaire est mickaelbaron
  80. mickael-baron.fr @mickaelbaron Microservices - K8S Page 80 Stockage via les

    volumes persistants : exemple apiVersion: v1 kind: Deployment metadata: name: mydeploymentwithpvc spec: replicas: 5 selector: matchLabels: app: mypodforpvc template: metadata: labels: app: mypodforpvc spec: containers: - name: myweb image: nginx:1.21 ports: - containerPort: 80 volumeMounts: - mountPath: /usr/share/nginx/html name: mypvcvolume volumes: - name: mypvcvolume persistentvolumeclaim: claimName: mypvc † Déclarer un volume de type PersistentVolumeClaim dans un Pod Fichier de configuration volumes/mydeploymentwithpvc Développeur Cinq Pods seront créés pour s’assurer qu’au moins deux nœuds sont utilisés Utilisation de l’objet PersistentVolumeClaim précédent
  81. mickael-baron.fr @mickaelbaron Microservices - K8S Page 81 Stockage via les

    volumes persistants : exemple # Créer un objet PersistentVolume avec le type de Volume NFS $ kubectl apply –f volumes/mypv.yaml # Lister les objets de type PersistentVolume $ kubectl get persistentvolume NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv 1Gi ROX Retain Available 96s # 🧐 # Ce volume persistant n’est pas encore revendiqué (CLAIM) par un objet PersistentVolumeClaim # Créer un objet PersistentVolumeClaim avec des besoins en volume compatible avec le volume persistant « mypv » $ kubectl apply –f volumes/mypvc.yaml –n mynamespace # Lister les objets de type PersistentVolume pour voir les changements effectués $ kubectl get persistentvolume NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv 1Gi ROX Retain Bound mynamespace/mypvc 16m # 🧐 # Ce volume persistant est maintenant revendiqué (CLAIM) par le PersistentVolumeClaim « mynamespace/mypvc » # Ajouter un fichier index.html dans le volume NFS NFS:$ echo "Bonjour depuis NFS" > index.html # Créer cinq Pods $ kubectl apply -f volumes/mydeploymentwithpvc.yaml -n mynamespace # Accéder au contenu web d’un Pod (accessible depuis le service NodePort) $ curl 167.53.81.116:30001 => Bonjour depuis NFS † Options kubectl : apply, get
  82. mickael-baron.fr @mickaelbaron Microservices - K8S Page 82 Composants † Rappel

    : un cluster Kubernetes est composé d’un maître et de nœuds † Ce cloisonnement maître / nœuds n’a pas lieu d’être car un maître est un nœud qui exécute des Pods spécifiques => composants internes de K8s API Server Controller Manager Scheduler etcd Kubelet Proxy Kubelet Proxy Administrateur Développeur Utilisateur Nœud de travail Maître
  83. mickael-baron.fr @mickaelbaron Microservices - K8S Page 83 Composants hébergés sur

    le nœud « Maître » † API Server : expose l’API d’un cluster K8s (kubectl) † Scheduler : recherche le meilleurs nœuds pour accueillir un Pod † Controller Manager : gère de l’état du cluster (exemple : augmenter le nombre de replicaset) † etcd : stocke l’état du cluser dans une base de données distribuée (pour K3s, il s’agit de SQLite) API Server Controller Manager Scheduler etcd Maître
  84. mickael-baron.fr @mickaelbaron Microservices - K8S Page 84 Composants hébergés sur

    un nœud Worker † Proxy : maintenir les règles réseaux sur les nœuds et permet une communication vers les Pods † Kubelet : responsable de l’état d’exécution sur chaque nœud en s’assurant que tous les conteneurs fonctionnent dans un Pod † Container Runtime (Docker) : responsable de l’éxécution des conteneurs Kubelet Proxy
  85. mickael-baron.fr @mickaelbaron Microservices - K8S Page 85 Outils : ma

    liste au papa 🎅 † kubectl † Outil de référence pour manipuler l’API de K8s † kubernetes.io/docs/tasks/tools/#kubectl † Helm † Outil pour package ses applications (à la « apt-get install ») † helm.sh † K9s † Gestionnaire d’un cluster K8s (application dans le terminal) † github.com/derailed/k9s † Lens † Gestionnaire d’un cluster K8s (application web) † k8slens.dev † Stern † Pour suivre les logs de plusieurs Pods † github.com/wercker/stern † dashboard † Gestionnaire officiel d’un cluster K8s (web) † kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard
  86. mickael-baron.fr @mickaelbaron Microservices - K8S Page † Où ? github.com/mickaelbaron/microservices-kubernetes-tutorial

    † Prérequis † Connaître les concepts de conteneur † Aimer écrire du YAML † Vous allez apprendre à … † créer un cluster K8s sur son poste développeur † gérer son cluster avec k9s et exécuter des commandes avec kubectl † écrire des configurations d’objet K8s † créer un Pod et Deployment sur son cluster † manipuler les différents types de Service : ClusterIP, NodePort, Ingress* (n’est pas un service) † créer des volumes et des volumes persistants (PersistentVolume et PersistentVolumeClaim) 86 Tutoriel découverte : les objectifs
  87. mickael-baron.fr @mickaelbaron Microservices - K8S Page 87 Allez plus loin

    : l’écosystème K8s est très vaste … † Gérer les mots de passes avec les objets Secret † Approfondir les notions de cycle de vie d’un Pod † Configurer l’équilibrage de la montée en charge horizontale † Créer dynamiquement des PersistentVolume avec StorageClass † Gérer la sécurité et le contrôle d’accès via ServiceAccount et Role † Configurer des logs pour le monitoring de vos applications † Bonnes pratiques pour gérer des applications avec états (objet StatefulSets) † …
  88. mickael-baron.fr @mickaelbaron Microservices - K8S Page 88 Liens en vrac

    • https://geekflare.com/fr/kubernetes-best-practices • https://blog.wescale.fr/2018/08/16/kubernetes-comment-ecrire-un-deployment • https://www.tutorialworks.com/kubernetes-pod-communication • https://medium.com/kubernetes-tutorials/kubernetes-dns-for-services-and-pods-664804211501 • https://matthewpalmer.net/kubernetes-app-developer/articles/kubernetes-networking-guide-beginners.html • https://kubernetes.io/docs/concepts/services-networking/dns-pod-service • https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0 • https://medium.com/devops-mojo/kubernetes-service-types-overview-introduction-to-k8s-service-types-what-are-types-of-kubernetes-services-ea6db72c3f8c • https://wiki.sfeir.com/kubernetes/architecture/composants/services • https://blog.ovhcloud.com/getting-external-traffic-into-kubernetes-clusterip-nodeport-loadbalancer-and-ingress • https://blog.zwindler.fr/2018/03/06/exposer-des-applications-kubernetes-en-dehors-des-cloud-providers-nginx-ingress-controller • https://medium.com/devops-mojo/kubernetes-ingress-overview-what-is-kubernetes-ingress-introduction-to-k8s-ingress-b0f81525ffe2 • https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nginx-ingress-with-cert-manager-on-digitalocean-kubernetes • https://www.youtube.com/watch?v=T4Z7visMM4E • https://devopssec.fr/category/apprendre-kubernetes • https://www.linuxtechi.com/setup-private-docker-registry-kubernetes