===== 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 ... **