Photo metallb

Dans kubernetes on va avoir différentes facon d’exposer un service:

  • ClusterIP
  • NodePort
  • LoadBalancer
  • Ingress Controler

On va laisser le dernier de côté et s’interesser au 3 premiers puis mettre en place un LoadBalancer qui est un service natif dans kubernetes mais on va devoir utiliser un service externe pour assigner des adresses IPs à ce dernier → MetalLB

Imaginons ce déploiement:

# web-app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: lst
  labels:
    name: service-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      name: service-demo
  template:
    metadata:
      labels:
        name: service-demo
    spec:
      containers:
      - image: nginx
        name: web-app
        command: 
          - /bin/sh
          - -c
          - "echo 'Bienvenu dans la salle du temps !!' > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"
$ kubectl apply -f web-app.yml

Photo deploiment

01. ClusterIP

Ce service permet d’acceder à notre service au sein du cluster, à partir de n’importe quel noeud ou control-plane. Ce qui permet de toujours avoir accès au service même si ce dernier est relancé sur un autre noeud.

$ kubectl expose deployments web-app --namespace lst --name web-app-svc --port 80 

Photo deploiment_service

On accède bien à notre service à travers un autre pod dans le cluster.

Photo curl_service

C’est bien tout ca, mais si je souhaite y accèder à partir de ma machine ?

Ouvrons un port sur les noeuds qui nous permettra cela.

02. NodePort

Ce service permet d’ouvrir un port sur chacun des noeuds compris entre 30000 et 32767 par défaut.

Il est déconseillé d’utiliser directement ce service en production car sa gestion peut vite devenir complex d’un point de vu sécurité et disponibilité.

Indirectement lorsqu’on crée un NodePort, kubernetes va également créer un ClusterIP et faire la connection entre les deux pour nous.

Cette fois je vais simplement le déclarer à la suite de notre déploiement.

On supprime rapidement le ClusterIP précédemment créé et on enchaine.

$ kubectl delete service --namespace lst web-app-svc
# web-app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: lst
  labels:
    name: service-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      name: service-demo
  template:
    metadata:
      labels:
        name: service-demo
    spec:
      containers:
      - image: nginx
        name: web-app
        command: 
          - /bin/sh
          - -c
          - "echo 'Bienvenu dans la salle du temps !!' > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"

---

apiVersion: v1
kind: Service
metadata:
  name: web-app-svc
  namespace: lst
  labels:
    name: service-demo
spec:
  type: NodePort
  selector:
    name: service-demo
  ports:
  - port: 80  # Port exposé par le Pod nginx
    targetPort: 80  # Port exposé par le ClusterIP
    nodePort: 30007  # Port exposé par le NodePort
$ kubectl apply -f web-app.yml

Photo curl_service_nodeport

On voit bien que nous avons accès depuis une machine exterieur au cluster à notre service via chacun des noeuds worker seulement.

Maintenant si je souhaite éviter la gestion des ports, on peut passer au LoadBalancer.

On supprime et on repart.

$ kubectl delete -f web-app.yml

03. LoadBalancer

Ce service est encore un niveau au dessus de ClusterIP et NodePort. D’ailleurs il utilise également ces services pour son fonctionnement.

# web-app.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: lst
  labels:
    name: service-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      name: service-demo
  template:
    metadata:
      labels:
        name: service-demo
    spec:
      containers:
      - image: nginx
        name: web-app
        command: 
          - /bin/sh
          - -c
          - "echo 'Bienvenu dans la salle du temps !!' > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"

---

apiVersion: v1
kind: Service
metadata:
  name: web-app
  namespace: lst
  labels:
    name: service-demo
spec:
  type: LoadBalancer
  selector:
    name: service-demo
  ports:
  - name: http
    port: 80  # Port de notre service Nginx
    protocol: TCP
    targetPort: 80  # Port que l'on souhaite utiliser
$ kubectl apply -f web-app.yml
$ kubectl get service -n lst

Sur ma machine MetalLB est installé donc je ne peux pas vous mettre de capture, cependant vous verez qu’aucune adresse IP externe ne sera assigné à votre service LoadBalancer.

Pour cela, on va utiliser MetalLB pour créer une pool d’IP que notre LB pourra utiliser.

On supprime notre déploiement juste avant.

$ kubectl delete -f web-app.yml
  • Installer MetalLB via Helm
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb

Pour choisir les ip à assigner, si vous utilisez kind par exemple, il faudra voir le CIDR associé à votre réseau docker kind. Si vous êtes sur votre réseau local, vérifier l’adresse de votre réseau ainsi que la range de votre DHCP.

Par exemple, comme vous voyez sur les captures chez moi c’est 192.168.1.0/24 et j’ai une range de 192.168.1.2-192.168.1.200

En conséquence pour l’exemple, je vais créer la pool sur 192.168.1.195-192.168.1.199 car je sais qu’aucune de mes machines sur mon réseau n’est sur ces IPs.

# first-pool.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.195-192.168.1.199  # Définissez votre pool en fonction de votre ŕéseau et disponibilité

Avec cette jolie piscine d’IP disponible pour nos futures LoadBalancer, il faut également déployer un service qui va se charger de les annoncer.

# l2-advertisement.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: advertisement-demo
  namespace: metallb-system
spec:
  ipAddressPools:
  - first-pool  # S'assurer que c'est bien le nom de notre IPAddressPool

On applique tout ca.

$ kubectl apply -f first-pool.yml
$ kubectl apply -f l2-advertisement.yaml
$ kubectl apply -f web-app.yml

Photo curl_service_loadbalancer

Félicitation, vous avez votre service accessible depuis l’exterieur de votre cluster proprement !

Maintenant, si on souhaite utiliser qu’une seule IP est bien rediriger le traffic au sein de nos noeuds, utiliser un ingress controler est pour moi la prochaine étape.

Enjoy o/