===== K3S : kubernetes ultra léger ===== ==== Rappel : kubernetes, c'est quoi ==== Après l'avènement de docker, qui permettait de compiler des images d'os hébergeant une application spécifique et de la partager pour faire en sorte que n'importe qui, à partir de son client docker, puisse la tirer et l'exécuter, est arrivé docker-compose, puis kubernetes. * docker-compose permet d'orchestrer une ensemble d'image, de "volumes" de données, de routes réseau, mais reste très spécifique docker et local * Les outillages kubernetes sont arrivés pour "remplacer" docker-compose, et le rendre beaucoup plus accessible, pour créer/gérer beaucoup plus d'instances, et ce depuis n'importe ou sur un réseau ; une distribution kubernetes héberge le système qui permet d'instancier des containers (exécutant des images docker, kubernetes s'appuie généralement sur containerd, tout comme docker ), mais aussi d'en gérer pleins, de gérer aussi des volumes de données, persistants ou non, des routes, des configMaps, et des secrets. Pour cela, le système kubernetes est pilotable depuis un petit programme appelé kubectl, du moment que ce kubectl arrive à se connecter à la distribution kubernetes ( un fichier KUBECONFIG que lit kubectl permet de dire comment s'y connecter ). Je connais 3 distribution kubernetes (d'ailleurs récemment cotoyées / utilisées chez maincare) : - Openshift ( OC, client en CLI équivalent de kubectl ) - RKE - K3s : (distribution kubernetes très légère) Les distributions Openshift et RKE sont souvent installées avec une IHM web qui permet de faire de surveiller et gérer les composants directement dans un navigateur. **Et HELM, c'est quoi ?** Par dessus kubernetes, une couche supplémentaire, HELM, un gestionnaire de packages, dont je parlerai un peu plus dans une autre doc, permet de d'automatiser l'installation d'applications (on parle de release) une ligne de commande Chaque application est décrite dans un chart et contient l'ensemble des ressources à déployer, dont les services tirant des images, des volumes, des configsMap, des secrets ), et l'articulation entre tous ces trucs. Présentation du service k3s. Je l'ai installé sur l'hyper VM Ubuntu mon Windows 11 Pro ==== Rappel : notion kubernetes à maitriser ==== === Cluster, namespaces, pod, service, deploiement, statefullset, ingress, secret, configMap === * Un cluster contient des namespaces = ensemble de machines (nœuds) qui exécutent des applications conteneurisées, c'est mon serveur k3s * Un namespace contient : * **pod** : c'est la plus petite unité déployable ; c'est l'unité d'exécution ; elle contient un ou plusieurs containers docker, qui exécute une app tirée d'une image * **service** : abstraction qui expose un ensemble de pods comme un service réseau ; il fournit une adresse IP stable et un nom DNS pour accéder aux pods * **deployment** : défini une application ou un logiciel à faire tourner, en indiquant une image docker, et comment elle doit fonctionner, comment elle doit être configurée * **replicaset** (ne concerne que les deployment) ; il est créé uniquement par un deployment ; un deployment peut en créer plusieurs pour que l'app soit plus robuste ; ** chaque replicaset gère 1 et 1 seul pod ** ; c'est le service qui jouera le rôle de loadbalancer * **statefullset** = deployment sans replicaset * **ingress** : route qui permet de définir un accès à un service depuis l'extérieur * **secret** : ensemble des credentials qui peuvent être utilisés par les services/pods * **configMap** : ensemble de paires clé/valeur qui peuvent être utilisés par les services/pods ( variable d'environnement ou fichiers de config ). 3 méthodes sont possibles : ** Voilà ce qu'on doit mettre dans son objet Deployment : selon les méthodes ** - Methode1 : La ConfigMap est injectée comme ** variables d'environnement dans le conteneur désiré ** containers: - name: query env: - name: GREETING_MESSAGE valueFrom: configMapKeyRef: name: query # Nom de la ConfigMap key: GREETING_MESSAGE # La clé dans la ConfigMap - Methode 2 : La ConfigMap est ** montée comme un fichier ** dans le système de fichiers du conteneur désiré containers: - name: query volumeMounts: - name: config-volume mountPath: /config # Où le fichier sera monté volumes: - name: config-volume configMap: name: query # Nom de la Conf - Methode 3 : La ConfigMap est passée comme ** un argument de la ligne de commande ** au conteneur apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - name: query volumeMounts: # Étape 1 : Monter le volume - name: config-volume mountPath: /config args: # Étape 2 : Utiliser le fichier monté - "--spring.config.location=/config/application.yaml" volumes: # Étape 3 : Définir la source du volume - name: config-volume configMap: name: query # ← ICI la référence à la ConfigMap ! sachant la configMap query serait apiVersion: v1 kind: ConfigMap metadata: name: query namespace: siakhooi-query data: application.yaml: | # ← La clé est un nom de fichier app: defaultGreetingMessage: Earth # On pourrait avoir plusieurs fichiers logback-spring.xml: | GREETING_MESSAGE: "Earth" LOG_LEVEL: "DEBUG" On retrouve dans la configMap query les objets identifié par les clé GREETING_MESSAGE, LOG_LEVEL et application.yaml. ** Attention : ** - Role d'un Deployment/StatefulSet : Créer et gérer les pods c'est avec lui qu'on peut scaler ; le service gérera alors le loadbalancing entre les pods répliqués - Role d'un Service : Exposer les pods en réseau === Contexte/cluster et namespace === kubectl fonctionne un peu comme une tête de lecture de disque. Il ne peut travailler qu'à un endroit : le contexte. Le contexte est une information qui permet de se connecter à un un cluster et les paramètres qui définissent comment on y accède (url user et credential). **1 contexte** pointe sur 1 cluster et 1 namespace ; en s'étant identifié avec 1 user * Exemple 1: en général un k3s ou autre serveur kubernetes sur son serveur, qui correspond au context nommé 'default'. * Exemple 2: un autre service kubernetes, sur une autre VM, potentielle distante, dans le cloud, ou son réseau d'entreprise. Avec kubectl, on définit l'ensemble des contextes avec lesquels il peut travailler dans un fichier qui s'appele KUBE_CONFIG. ** C'est dans ce fichier qu'on définit tous les contextes dont on a besoin.** ==== k3s : service kubernetes léger ==== C'est une distrib légère de kubernetes qui s'appuie sur containerd (équivalent de docker) pour tirer les images docker, et les lancer dans un container. En fait, docker s'appuie aussi sur containerd, mais contient tout un outillage complémentaire. ==== Mise en place ==== === J'ai installé kubernetes / helm sur === - mon hyper VM Ubuntu ( dans mon windows 11 pro, mon pc xms-fixe ) - mon xms-foxe-ubuntu === Installation === curl -sfL https://get.k3s.io | sh - === Config === K3s utilise par défaut la config /etc/rancher/k3s/k3s.yaml pour tout les client sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config export KUBECONFIG=~/.kube/config --> à mettre dans .bashrc sudo chmod 644 $KUBECONFIG sudo chown $USER:$USER ~/.kube/config === kubectl.exe pour windows/powershell et k3s kubectl depuis sa VM === Attention : kubectl.exe est fourni par windows mais n'utilise absolument pas le $KUBECONFIG. Que ce soit pour le k3s qu'on installe sur l'Hyper VM, ou qu'on installerait sur une distribution Linux de sa WSL (WSL2) 'k3s kubectl' est la commande kubectl la plus judicieuse à utiliser puisqu'elle est livrée avec/dans k3s J'ai fait un alias dans mon .bashrc pour ne pas avoir à taper k3s à chaque fois Visiblement, sur mon hyper VM Ubuntu installée à partir d'un ISO 24 Server, j'ai déjà kubectl installé, donc je n'ai pas besoin de l'alias 'k3s kubectl' === K9s === C'est un client pseudo-graphique de kubernetes. Ca permet de consulter les pods, les namespaces etc ... * Installation : sudo snap install k9s * Utilisation : Attention k9s n'est pas dans /snap/bin/k9s donc il est pas dans le $PATH find /snap -name k9s -type f 2>/dev/null Remarque : k9s s'appuie sur le dernier context et namespace sélectionné par kubectl. ==== kubernetes-dashboard ==== === Présentation === C'est une IHM Web qui permet de piloter tous les namespaces du cluster sur lequel il est installé. === Installation === kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml Mon kubernetes-dashboard tourne bien. Il écoute en https sur 8443 kubectl debug -it kubernetes-dashboard-6c7b75ffc-z6rlw -n kubernetes-dashboard --image=busybox --target=kubernetes-dashboard === Accéder à l'appli kubernetes-dashboard Pour ouvrir une session ssh dessus, kubectl exec -it kubernetes-dashboard-6c7b75ffc-z6rlw -n kubernetes-dashboard -- /bin/sh La commande suivante permet de l'exposer sur un navigateur web à l'url suivante : * url : http://127.0.0.1:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login * commande : kubectl proxy ou kubectl proxy --address='0.0.0.0' --port 8001 --accept-hosts='.*' == Créer un compte d'accès == Creer un ServiceAccount : kubectl apply -f - < Le ServiceAccount fournit le token, et ce token est injecté dans le kubeconfig. L'accès à l'IHM web de kubernetes-dashboard peut se faire : * par token kubectl -n kubernetes-dashboard create token admin-user * via un fichier kubeconfig dédié à l'accès à kubernetes-dashboard et tiré du fichier global kubeconfig : Adresse de l’API kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' Certificat CA kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' nano ~/.kube/dashboard-admin.conf Y mettre : apiVersion: v1 kind: Config clusters: - name: k3s cluster: server: https://127.0.0.1:6443 certificate-authority-data: users: - name: dashboard-admin user: token: contexts: - name: dashboard-context context: cluster: k3s user: dashboard-admin namespace: dashboard current-context: dashboard-context === Exposer l'appli kubernetes-dashboard === Il faut savoir sur quoi le service qu'on souhaite exposer écoute, pour ca on tape : kubectl get svc -n kubernetes-dashboard kubernetes-dashboard ClusterIP ... 443/TCP dashboard-metrics-scraper (celui là on s'en fout) On peut aussi voir le port d'écoute dans le dashboard, en éditant le service kubernetes-dashboard ports: - protocol: TCP port: 443 targetPort: 8443 qui tappera sur le pod kubernetes-dashboard-... qui est déployé à partir du Deployment kubernetes-dashboard (qui tire l'image docker kubernetesui/dashboard:v2.7.0 ) qui spécifie bien le port d'écoute 8443 puis on remplit le fichier kubernetes-dashboard-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: kubernetes-dashboard namespace: kubernetes-dashboard annotations: kubernetes.io/ingress.class: traefik traefik.ingress.kubernetes.io/service.serversscheme: https spec: rules: - host: dashboard.local http: paths: - path: / pathType: Prefix backend: service: name: kubernetes-dashboard port: number: 443 Le ingress Remarque : la ligne suivante du fichier permet de forcer traefik à parler au service kubernetes-dashboard en HTTPS traefik.ingress.kubernetes.io/service.serversscheme: https puis kubectl apply -f kubernetes-dashboard-ingress.yaml ==== Accès au kubernetes-dashboard depuis Windows ou l'extérieur ==== Impossible d'accéder au dashboard depuis mon navigateur chrome sous W11 Pro. Mon serveur k3s est sous une hyper vm ubuntu 24 hébergée par mon w11 pro Votre problème est classique : le dashboard Kubernetes tourne sur votre VM Ubuntu, et vous cherchez à y accéder depuis votre navigateur sur Windows 11. Voici comment résoudre cela en utilisant la méthode recommandée et sécurisée. === Solution S1 : kubectl port-forward === La méthode la plus simple et sécurisée est d'utiliser kubectl port-forward pour créer un tunnel entre votre machine Windows et le dashboard dans votre VM. == S1.E1 : S'assurer d'avoir kubectl sur son os W11pro ou l'installer == winget install -e --id Kubernetes.kubectl == S1.E2 : créer le fichier kube config pour pouvoir lier kubectl au service kubernetes distant == * E2.1 : récupérer le /etc/rancher/k3s/k3s.yaml du service k3s de la VM et le copier dans %USERPROFILE%\.kube\config * E2.2 : remplacer localhost dans le fichier %USERPROFILE%\.kube\config par l'IP du service du PC qui héberge le service kubernetes (ou le nom DNS ou mDNS peut être) Exemples (dans le fichier %USERPROFILE%\.kube\config) : rqe : attention à l'indentation !!! server: https://172.24.144.233:6443 # si l'ip de la VM est 172.24.144.233 ou server: https://xms-fixe-ubuntu:6443 Remarque : on peut peut être remplacer par l'IP, qui change régulièrement par un host de la VM dans C:\Windows\System32\drivers\etc\hosts ou encore mieux : normalement lors de l'installation de l'hyper VM, on fournit un nom d'ordinateur (moi par exemple : xms-fixe-vm-ubuntu), et quand vm est démarrée, depuis mon windows, je ping bien xms-fixe-vm-ubuntu ! == S1.E3 : Créer le tunnel avec port-forward == Sur Windows, dans PowerShell ou CMD kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard 8443:443 ou kubectl -n kubernetes-dashboard port-forward --address 0.0.0.0 svc/kubernetes-dashboard 10443:443 kubectl -n kubernetes-dashboard port-forward --address 0.0.0.0 svc/kubernetes-dashboard [PORT WINDOWS]:[PORT INTERNE K3S] pour aller plus loin, si on a plusieurs fichier kube config, pour préciser lequel on veut utiliser : kubectl --kubeconfig=/chemin/vers/fichier/kube_config port-forward -n kubernetes-dashboard service/kubernetes-dashboard 10443:443 Cette commande va créer un tunnel sécurisé de votre Windows (port 8443, windows écoute dessus) vers le service kubernetes-dashboard, qui à priori écoute sur le port 443 dans mon espace k3s. L'accès au dashboard se fera alors à partir d'un webbrowser de windows à l'url : https://127.0.0.1:10443/#/service?namespace=kubernetes-dashboard Attention !!! il faut bien comprendre qu'**il ne s'agit pas du port 443 sur la VM**, mais dans l'espace kubernetes, donc on ne le verra pas sur la VM avec un : sudo netstat -tlnp Depuis la VM, "sudo netstat -tlnp" ne montrera que le port 6443 ouvert. Effectivement, c'est biensur kubectl (le client kubernetes) qui fait le lien entre windows et k3s ; une fois que le lien est fait, **le port 443 et le service svc/kubernetes-dashboard sont des éléments internes à kubernetes**. Le service kubernetes-dashboard dans votre cluster écoute sur le port 443 (HTTPS standard). C'est son port "interne" configuré dans le service Kubernetes. Dans l'IHM de kubernetes-dashboard, si on va voir la définition du service kubernetes-dashboard, on verra : ports: - protocol: TCP port: 443 # Le port du SERVICE kubernetes-dashboard targetPort: 8443 # Le port du POD kubernetes-dashboard Si on va voir la définition du pod dans l'IHM containers: - name: kubernetes-dashboard image: kubernetesui/dashboard:v2.7.0 args: - '--auto-generate-certificates' - '--namespace=kubernetes-dashboard' ports: - containerPort: 8443 # le container créé pour mettre en oeuvre le pod kubernetes-dashboard écoute bien sur 8443. protocol: TCP Remarque : k3s expose ici 2 ports tcp : - 1 pour le controle de kubectl ; en général c'est 6443 (dès fois 8443) ; on appelle ça le port de l'API Server - 1 pour exposer le service Remarque Pour éviter le port-forward === Solution S2 : NodePort fixe === Rédéfinir le service kubernetes-dashboard pour le forcer à écouter sur le port 32000 de la VM ( en plus du port 443 de k3s ) cat < 8000/TCP 19h kubernetes-dashboard NodePort 10.43.194.213 443:32000/TCP 19h === Solution 3 : Utiliser un Ingress avec Traefik (Le plus propre) === ==== Quelques commandes utiles ==== # Redémarrer une application suite à une modif de son deployment, d'une de ses configMap, secret, ou autre : kubectl rollout restart deployment my-query-query -n siakhooi-query # Voir les infos des composants kubectl get ingressroute -A kubectl describe ingressroute ingress-route-dashboard -n kubernetes-dashboard kubectl get ingressroute ingress-route-dashboard -n kubernetes-dashboard -o yaml kubectl delete ingressroute ingress-route-dashboard -n kubernetes-dashboard kubectl describe pod -n siakhooi-query -l app.kubernetes.io/instance=my-query | grep -A5 -E "Liveness|Readiness|Startup" # Voir l'état de santé des pods d'un namespace : kubectl get pods -n siakhooi-query -w # Voir les dernier events d'un pod : kubectl get events -n siakhooi-query --field-selector involvedObject.name=my-query-query-5d4fc694c6-pd2tt --watch # Supprimer un replicatset kubectl delete replicaset my-query-query-56c4d6fdf7 -n siakhooi-query # Voir les endpoints exposés par l'application (si Spring Boot Actuator est actif) kubectl exec -n siakhooi-query -it deployment/my-query-query -- curl -s http://localhost:8080/actuator/mappings | jq . 2>/dev/null || echo "Pas de actuator mappings" # Voir tous les endpoints Actuator exposés curl http://192.168.1.54:32001/actuator ou toujours pareil : kubectl exec -n siakhooi-query -it deployment/my-query-query -- curl -s http://localhost:8080/actuator # Voir les logs kubectl logs -n siakhooi-query -l app.kubernetes.io/instance=my-query --tail=50 # Voir les variables d'environnement de l'application kubectl exec -n siakhooi-query -it deployment/my-query-query -- env | sort Les logs (entre autre) permettent de mettre en évidence que le module actuator de springboot est activé. Ce module permet de mettre à disposition plein d'information de monitoring, sous la forme de endpoint dont le path commence par /actuator/desInfos. D'ailleurs les probes de kubernetes ont été configurés pour aller consommer un endpoint défini par actuator : health !!! A partir des logs, et de quelques commandes suivantes, curl http://192.168.1.54:32001/actuator/info curl http://192.168.1.54:32001/actuator/env | grep -i query curl http://192.168.1.54:32001/actuator/beans | grep -i query curl http://192.168.1.54:32001/actuator/mappings | jq '. | keys' sudo apt install jq curl http://192.168.1.54:32001/actuator/mappings | jq '. | keys' curl -s http://192.168.1.54:32001/actuator/mappings | grep -i query on arrive à en déduire (avec l'aide de l'IA deepseek), que : La release my-query tirée du chart siakhooi/query est une application Spring Boot qui permet d'exécuter des requêtes SQL via une API REST. Elle a trois contrôleurs principaux : - QueryController - Pour exécuter des requêtes - QueryConfigController - Pour configurer les requêtes - DatasourceConfigController - Pour configurer les sources de données Swagger : [[http://192.168.1.54:32001/swagger-ui/index.html#/query-config-controller/getQueryConfig]] Remarque pour comprendre encore plus l'application : Elle utilise spring.cloud.kubernetes.enabled:true Ce truc de spring permet de se connecter à kubernetes pour lire et monter directement dans la JVM les configMaps, les volumes, etc ... donc les volumes, configMaps visibles dans kubernetes (via k9s, kubernetes-dashboard, ou via des describe en CLI) ne sont pas ceux utilisé par l'app ... Mais ça permet de savoir ce que l'app utilise !!! Cette commande : * créé un service+pod en tirant l'image mysql dans le namespace siakhooi-query * puis (après --) se connecte en mysql au SGBD 10.42.0.18 ( ip d'un autre pod ) * liste les bases kubectl run -it --rm test-mysql \ --image=mysql:8.0 \ --restart=Never \ -n siakhooi-query \ -- mysql -h 10.42.0.18 \ -P 3306 \ -u fruituser \ -puserpassword \ --ssl-mode=DISABLED \ -e "SHOW DATABASES;" ** Attention : APPUYER 2 fois sur ENTER après la commande pour avoir la sortie standard ... **