Meme Kubernetes, I just wrote a Kubernetes blog, AAAAnd is out of date

Kubernetes….

Les joies de Kubernetes ne s’arrêtent jamais, les pods, les deployments, les services, les ingress, les loadbalancers… Il y a tant de choses à apprendre et à comprendre. Et surtout, à déployer !

Dans cet article on va se pencher sur comment est-ce que le réseau fonctionne dans Kubernetes, surtout du côté exposition des applications. Une fois qu’on aura bien compris comment ça marche, on va mettre en place MetalLB. Qui va servir comme notre base pour exposer nos applications dans d’autres futurs articles.

Tenez-vous bien, car je vais essayer de vous expliquer ça de la manière la plus simple possible. Sans bien entendu tomber dans les travers de la simplification excessive.

C’est quoi un service ?

Avant de parler des services, il faut parler bien évidemment du cœur du problème que les services essayent de résoudre : l’exposition des pods (qui dit pods, dit application).

L’exposition des pods tant vers d’autres pods dans le cluster, que vers l’extérieur du cluster.

Car vous, en tant qu’administrateur de cluster, vous ne voulez pas seulement déployer une application pour que personne ne puisse y accéder. Sauf si vous êtes un admin sadique…

Il existe plusieurs types de services dans Kubernetes, mais on va se concentrer sur les trois principaux :

  1. ClusterIP : C’est le type de service par défaut. Il permet d’exposer un service à l’intérieur du cluster. C’est-à-dire que les autres pods dans le cluster peuvent accéder à ce service, mais pas l’extérieur du cluster. C’est utile pour les services internes, comme les bases de données ou les caches.
graph TD subgraph Cluster Kubernetes subgraph "Réseau Interne du Cluster" Svc_CI[Service ClusterIP
IP: 10.96.10.5
Port: 80] Pod_A(Pod A
IP: 10.244.1.2
Port Cible: 8080) Pod_B(Pod B
IP: 10.244.2.3
Port Cible: 8080) AutrePod(Autre Pod) AutrePod -- "Requête vers 10.96.10.5:80" --> Svc_CI Svc_CI -- "Redirige vers le Port Cible 8080" --> Pod_A Svc_CI -- "Redirige vers le Port Cible 8080" --> Pod_B end end style Svc_CI fill:#b3b4b5,stroke:#333,stroke-width:2px,color:#000000 style AutrePod fill:#b3b4b5,stroke:#333,stroke-width:1px,color:#000000
  1. NodePort : Ce type de service expose le service sur un port spécifique de chaque nœud du cluster. Cela permet d’accéder au service depuis l’extérieur du cluster en utilisant l’adresse IP d’un des nœuds et le port attribué. C’est une solution simple pour exposer des services, mais elle a ses limites en termes de scalabilité et de gestion des adresses IP.
graph TD Utilisateur[Utilisateur Externe] subgraph Cluster Kubernetes subgraph "Node 1 (IP: 192.168.1.101)" Port_N1("Port Ouvert
NodePort: 30080") end subgraph "Node 2 (IP: 192.168.1.102)" Port_N2("Port Ouvert
NodePort: 30080") end Svc_NP[Service NodePort
ClusterIP: 10.96.20.15
Port: 80] Pod_A(Pod A
Port Cible: 8080) Pod_B(Pod B
Port Cible: 8080) end %% Correction ici : "http://" a été retiré du texte des flèches %% Utilisateur -- "Requête vers 192.168.1.101:30080" --> Port_N1 Utilisateur -- "ou 192.168.1.102:30080" --> Port_N2 Port_N1 -- "Redirige vers le ClusterIP interne" --> Svc_NP Port_N2 -- "Redirige vers le ClusterIP interne" --> Svc_NP Svc_NP -- "Port 80 -> Port Cible 8080" --> Pod_A Svc_NP -- "Port 80 -> Port Cible 8080" --> Pod_B style Svc_NP fill:#cde4ff,stroke:#333,stroke-width:2px,color:#000000 style Utilisateur fill:#d5e8d4,stroke:#333,stroke-width:2px,color:#000000
  1. LoadBalancer : Ce type de service est utilisé dans les environnements de cloud. Il provisionne un load balancer externe qui distribue le trafic vers les pods du service. Cela permet d’avoir une adresse IP stable et d’exposer facilement le service au monde extérieur. Cependant, cela peut engendrer des coûts supplémentaires en fonction du fournisseur de cloud.
graph TD Utilisateur[Utilisateur Externe] LB[Load Balancer Externe - ex: MetalLB - IP Publique: 88.99.100.1] Utilisateur -- "Requête sur le port 80" --> LB subgraph Cluster Kubernetes Node1["Node 1 - IP: 192.168.1.101 - Écoute sur NodePort 30080"] Node2["Node 2 - IP: 192.168.1.102 - Écoute sur NodePort 30080"] Svc_LB[Service LoadBalancer - Agit comme un aiguilleur interne] PodA[Pod A - Port Cible: 8080] PodB[Pod B - Port Cible: 8080] Node1 -- "Transfère au service interne" --> Svc_LB Node2 -- "Transfère au service interne" --> Svc_LB Svc_LB -- "Équilibre la charge vers le port cible d'un Pod - 8080" --> PodA Svc_LB -- " " --> PodB end LB -- "Redirige le trafic vers un des nœuds sur son NodePort - 30080" --> Node1 LB -- " " --> Node2 %% Styles pour la clarté style Utilisateur fill:#d5e8d4,stroke:#333,stroke-width:2px,color:#000000 style LB fill:#dae8fc,stroke:#6c8ebf,stroke-width:2px,color:#000000 style Svc_LB fill:#cde4ff,stroke:#333,stroke-width:2px,color:#000000

Voilà un exemple de définition simple d’un service lorsque on veut exposer une application en NodePort :

apiVersion: v1
kind: Service
metadata:
  name: mon-service-nodeport
spec:
  type: NodePort
    selector:
        app: mon-application
    ports:
      - port: 80
        targetPort: 8080
        nodePort: 30080

Dans cet exemple, deux éléments sont importants :

Le sélecteur app: mon-application qui permet de lier le service aux pods qui ont cette étiquette. Et le port nodePort: 30080 qui est le port sur lequel le service sera exposé sur chaque nœud du cluster.

Maintenant lorsque vous allez faire une requête vers l’un des nœuds du cluster sur le port 30080, la requête sera redirigée vers le service, qui lui redirigera la requête vers les pods qui ont l’étiquette app: mon-application sur le port cible 8080.

Si vous avez bien compris, vous allez me dire pourquoi on a besoin d’un service LoadBalancer si on a déjà un service NodePort ?

C’est une très bonne question, la réponse est que le service LoadBalancer offre des fonctionnalités supplémentaires qui ne sont pas disponibles avec un service NodePort. Par exemple, un service LoadBalancer fournit une adresse IP externe stable, car un nœud peut changer d’adresse IP si jamais on le supprime ou le remplace. Cela permet d’avoir une interface stable pour mettre nos entrées DNS, et de ne pas avoir à se soucier des changements d’adresse IP des nœuds du cluster.

Et MetalLB dans tout ça ?

Les loadBalancers marchent super bien dans le cloud, mais dans un cluster Kubernetes qu’on héberge nous-mêmes en bare-metal (ou VM’s) on n’a pas de load balancer, on n’a pas cette couche logicielle qui va nous attribuer une adresse IP externe stable. C’est là où MetalLB entre en jeu.

MetalLB est une implémentation de load balancer pour les clusters Kubernetes bare-metal. Il permet d’attribuer des adresses IP externes aux services de type LoadBalancer, en utilisant des protocoles de routage standard comme BGP ou ARP. Cela permet d’exposer facilement les services Kubernetes au monde extérieur, tout en conservant la flexibilité et la scalabilité de Kubernetes.

MetalLB fonctionne en deux modes principaux :

Layer 2 mode : Dans ce mode, MetalLB utilise le protocole ARP pour annoncer les adresses IP externes aux nœuds du cluster. Car comme vous savez, dans un réseau local, les adresses IP sont résolues en adresses MAC pour pouvoir acheminer les paquets.

Donc dans chaque nœud du cluster, on va avoir un genre d’agent (speaker) MetalLB qui va envoyer des annonces ARP gratuites pour les adresses IP externes qu’il gère. Cela permet aux routeurs ou autres clients de savoir que ces adresses IP sont disponibles sur le réseau local et comme quoi il y a une machine qui répondra à ces adresses IP.

Schema explicatif de MetalLB

Dans ce schéma, on voit un nouveau composant, le Kube-Proxy. C’est un composant de Kubernetes qui est responsable de la gestion du trafic entrant et sortant des services. Il va rediriger le trafic vers les pods qui sont en train de tourner dans le cluster.

Donc avec MetalLB, on donne à un nœud du cluster la capacité d’annoncer une adresse IP externe. Et donc si vous êtes des magiciens du réseau, vous vous rendez vite compte de la limitation de ce mode. Car vous dépendez de la bande passante d’un seul et unique nœud du cluster. Donc si vous avez un gros trafic, vous allez vite saturer la bande passante de ce nœud…

C’est une limitation connue par MetalLB, et qui peut poser des problèmes de performance si vous avez beaucoup de trafic entrant sur votre service. Mais pour la plupart des cas d’utilisation, cela fonctionne très bien.

BGP mode : Dans ce mode, MetalLB utilise le protocole BGP pour annoncer les adresses IP externes aux routeurs du réseau. Cela permet de distribuer la charge entre plusieurs nœuds du cluster, car chaque nœud peut annoncer une adresse IP externe différente. Cela permet également de gérer des adresses IP externes qui ne sont pas sur le même sous-réseau que les nœuds du cluster.

Nous dans cet article, on va se concentrer sur le mode Layer 2, car c’est le plus simple à mettre en place et à comprendre. Mais si vous voulez en savoir plus sur le mode BGP, je vous invite à consulter la documentation de MetalLB.

Installation de MetalLB

Meme deux

Pour installer MetalLB, vous pouvez suivre ces étapes :

  1. Appliquer les manifests de MetalLB :
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml
  1. Configurer MetalLB : Vous devez créer un ConfigMap pour configurer MetalLB. Voici un exemple de configuration en mode Layer 2 :
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.100.40-192.168.100.50
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system

Il faut bien vérifier que les adresses IP que vous avez spécifiées dans la configuration sont disponibles sur votre réseau.

Enregistrez ce fichier sous le nom metallb-config.yaml et appliquez-le avec la commande suivante :

kubectl apply -f metallb-config.yaml
  1. Vérifier l’installation : Vous pouvez vérifier que MetalLB est bien installé et fonctionne en exécutant la commande suivante :
kubectl get pods -n metallb-system

Vous devriez voir les pods controller et speaker de MetalLB en cours d’exécution.

mohamad@Mohamad-PC:~$ kubectl get pods -n metallb-system
NAME                          READY   STATUS    RESTARTS   AGE
controller-58fdf44d87-4f7fm   1/1     Running   0          38h
speaker-46pkk                 1/1     Running   0          38h
speaker-kc4hg                 1/1     Running   0          38h
speaker-n9xs2                 1/1     Running   0          38h

Maintenant on va tester MetalLB en créant un service de type LoadBalancer. Mais avant ça, on va déployer une application simple pour pouvoir l’exposer.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1-deploy
  labels:
    name: app1-deploy
    type: tier1
spec:
  replicas: 2
  selector:
    matchLabels:
      name: app1
  template:
    metadata:
      labels:
        name: app1
    spec:
      containers:
      - name: app1
        image: ealen/echo-server
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: loadbalancer-app1
spec:
  type: LoadBalancer
  selector:
    name: app1
  ports:
  - port: 80
    targetPort: 80

Donc cette application est un simple serveur HTTP qui va répondre aux requêtes HTTP sur le port 80. On va l’exposer en tant que service de type LoadBalancer, ce qui va permettre à MetalLB de lui attribuer une adresse IP externe.

Pour appliquer cette configuration, enregistrez-la dans un fichier app1.yaml et exécutez la commande suivante :

kubectl apply -f app1.yaml

Vous pouvez vérifier que le service a bien été créé et que MetalLB lui a attribué une adresse IP externe en exécutant la commande suivante :

# kubectl get svc loadbalancer-app1
NAME                TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
loadbalancer-app1   LoadBalancer   10.43.51.195   192.168.9.41   80:32370/TCP   26h

Et si on fait un curl sur l’adresse IP :

curl http://192.168.9.41

# curl http://192.168.9.41


StatusCode        : 200
StatusDescription : OK
Content           : {"host":{"hostname":"192.168.9.41","ip":"::ffff:10.42.0.0","ips":[]},"http":{"method":"GET","baseUr
                    l":"","originalUrl":"/","protocol":"http"},"request":{"params":{"0":"/"},"query":{},"cookies":{},"b
                    od...
RawContent        : HTTP/1.1 200 OK
                    Connection: keep-alive
                    Keep-Alive: timeout=5
                    Content-Length: 1200
                    Content-Type: application/json; charset=utf-8
                    Date: Thu, 10 Jul 2025 09:39:45 GMT
                    ETag: W/"4b0-T+p8x1RXYDP+WvXU2...
Forms             : {}
Headers           : {[Connection, keep-alive], [Keep-Alive, timeout=5], [Content-Length, 1200], [Content-Type,
                    application/json; charset=utf-8]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 1200

Lets go GIF

Conclusion

MetalLB est une solution puissante pour exposer des services Kubernetes dans un environnement bare-metal. Il permet de gérer facilement les adresses IP externes et d’exposer les services au monde extérieur, tout en conservant la flexibilité et la scalabilité de Kubernetes.

Dans cet article, nous avons vu comment fonctionne le réseau dans Kubernetes, comment les services permettent d’exposer les applications, et comment MetalLB peut être utilisé pour gérer les adresses IP externes dans un cluster bare-metal.

Si vous avez des questions ou des suggestions, n’hésitez pas à m’envoyer un message. Et sur ce, je vous dis à la prochaine !