Kubernetes : loadbalancer

Bonjour,

Aujourd'hui, un billet portant sur le passage du mode NodePort avec un seul node master a un mode LoadBalancer avec deux nodes master.

Contexte : cluster avec 2 nodes ( un master Ubuntu 22 et un Flatcar) et 3 nodes workers.

Actuellement, j'utilise ingress-nginx en mode NodePort pour accéder aux différents services. Cela amène une coupure si le node en question (le master) est coupé ou reboot pour upgrade.

L'objectif est de passer sur un mode LoadBalancer de type L2 via MetalLB pour pouvoir s'affranchir de cette problématique.

Très bonne vidéo à ce sujet :
https://www.youtube.com/watch?v=k8bxtsWe9qw

Installation de MetalLB via helm :

helm repo add metallb https://metallb.github.io/metallb
kubectl create ns metallb-system
helm install metallb metallb/metallb --namespace metallb-system

En l'état, metallb reste en idle car il faut le configurer.

Mais avant, il faut modifier l'ingress-nginx pour passer de nodeport à loadbalancer (ce qui amène une coupure de l'accès aux services le temps de finir la configuration) :

kubectl edit service ingress-nginx-controller -n ingress-nginx

Retirer externalIP et modifier spec.type de NodePort à LoadBalancer :

apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: ingress-nginx
    meta.helm.sh/release-namespace: ingress-nginx
    metallb.universe.tf/ip-allocated-from-pool: vip-ingress-nginx
  creationTimestamp: "2024-07-12T08:16:21Z"
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.11.0
    helm.sh/chart: ingress-nginx-4.11.0
  name: ingress-nginx-controller
  namespace: ingress-nginx
  resourceVersion: "51393888"
  uid: df9d612c-de4d-4010-a6ae-1c749b12b8fd
spec:
  allocateLoadBalancerNodePorts: true
  clusterIP: 10.105.228.153
  clusterIPs:
  - 10.105.228.153
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - appProtocol: http
    name: http
    nodePort: 30158
    port: 80
    protocol: TCP
    targetPort: http
  - appProtocol: https
    name: https
    nodePort: 30899
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer: {}

On vérifie ensuite son état :

kubectl get svc -n ingress-nginx
ingress-nginx    ingress-nginx-controller             LoadBalancer   10.105.228.153   <pending>     80:30158/TCP,443:30899/TCP   99m
ingress-nginx    ingress-nginx-controller-admission   ClusterIP      10.100.199.101   <none>        443/TCP                      99m

Il est en pending, c'est normal car il n'y a pas encore de service LoadBalancer de configuré.

Pour configurer MetalLB, il faut créer deux fichiers de configuration :

  • pool.yaml : contient le/les pools d'adresses IP (qui peut être une unique ip en /32)
  • l2advertisement.yaml : spécifie le/les pools d'adresses IP à utiliser

pool.yaml

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: vip-ingress-nginx
  namespace: metallb-system
spec:
  addresses:
  - 192.168.0.26/32

l2advertisement.yaml

apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-vip-ingress-nginx
  namespace: metallb-system
spec:
  ipAddressPools:
  - vip-ingress-nginx

Application des fichiers de conf :

kubectl apply -f pool.yaml 
kubectl apply -f l2advertisement.yaml 

On vérifie que tout est bon côté conf :

kubectl get IPAddressPool -A
NAMESPACE        NAME                AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
metallb-system   vip-ingress-nginx   true          false             ["192.168.0.26/32"]
kubectl get L2Advertisement -A
NAMESPACE        NAME                   IPADDRESSPOOLS          IPADDRESSPOOL SELECTORS   INTERFACES
metallb-system   l2-vip-ingress-nginx   ["vip-ingress-nginx"] 

Si tout est bon, on vérifie le service nginx :

kubectl get svc -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.105.228.153   192.168.0.26   80:30158/TCP,443:30899/TCP   105m
ingress-nginx-controller-admission   ClusterIP      10.100.199.101   <none>         443/TCP                      105m

On voit que le service en mode LoadBalancer utilise bien l'adresse IP du pool que l'on a défini précédemment.

Dans ce mode L2 il y aura quand même une légère interruption de service lors d'une bascule, le temps que le nouveau "master" MetalLB soit promu.

Have fun.