Avant de commencer...

Le but de cet article est bien évidemment de vous présenter MetalLB et de vous permettre de l'installer facilement, mais avant toutes choses, cet article est la suite de Kubeadm avec Vagrant et Ansible, idéal pour réviser votre certification ! et Faire de votre cluster Kubeadm, un vrai simulateur accessible à distance. Je vous conseille fortement de lire ces articles, car nous allons installer MetalLB sur notre cluster Kubeadm.

Petite mise en garde par rapport à ce qui suit, MetalLB reste un projet très jeune, il n'est peut-être pas adapté pour tous les usages à l'heure actuelle notamment la production (il est toujours en beta).

Mais d'abord qu'est-ce que MetalLB ?

Comme vous le savez, il existe plusieurs types quand on parle de service côté Kubernetes. Il y a le ClusterIP, le NodePort mais surtout le LoadBalancer. Cependant, ce dernier type n'est pas disponible sur les orchestrateurs Kubernetes installés sur des machines virtuelles. On le retrouve évidemment sur les services managés dans le Cloud, car les fournisseurs de Cloud comme GCP ou AWS utilisent leurs propres équilibreurs de charge (loadbalancer) physiques à travers leurs infrastructures.

MetalLB vient combler ce manque sur les clusters Kubernetes sur les machines virtuelles ou bare metal en permettant aux utilisateurs de déployer de vrais services de type LoadBalancer.

En effet, lorsque vous créez votre Pod et que vous souhaitez l'exposer avec un service de type LoadBalancer, rien ne se passe :

$ kubectl run nginx --image=nginx --restart=Never
$ kubectl expose pod nginx --type=LoadBalancer --port=80
$ kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          54s

$ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1      <none>        443/TCP        7m21s
nginx        LoadBalancer   10.98.188.48   <pending>     80:31852/TCP   45s

$ kubectl describe svc nginx
Name:                     nginx
Namespace:                default
Labels:                   run=nginx
Annotations:              <none>
Selector:                 run=nginx
Type:                     LoadBalancer
IP Families:              <none>
IP:                       10.98.188.48
IPs:                      10.98.188.48
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  31852/TCP
Endpoints:                10.244.194.65:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

Comme vous pouvez le constater, il n'y a pas d'Events et le statut reste à pending pour avoir une ip externe. C'est tout à fait normal. L'installation de MetalLB permettra de résoudre ce problème.

Installation de MetalLB

Comme toujours dans ce genre d'article, un playbook Ansible permettra d'installer notre outil et de le configurer. La page d'installation de MetalLB est très complète et vous guidera sur différentes méthodes d'installation, l'utilisation du chart Helm a été choisi.

Petit point d'attention ici, en fonction de l'addon réseau utilisé par l'orchestrateur Kubernetes, il peut y avoir des incompatibilités ou des restrictions sur certaines fonctionnalités. Cette page permet de les répertorier. Dans notre cas, flannel est utilisé et, est pleinement supporté.

Le voici :

- hosts: master
  gather_facts: true
  become: true
  vars:
    helm_version: 3.8.0
    metallb_chart_version: 2.6.2
  pre_tasks:
  # Vérification de la présence de Helm
  - name: Find if helm binary is installed
    ansible.builtin.command: 
      cmd: which helm
    register: helm_installed
    ignore_errors: true
    changed_when: false

  # Si Helm n'est pas présent on télécharge le binaire...
  - name: Download helm binary
    ansible.builtin.unarchive:
      src: "https://get.helm.sh/helm-v{{ helm_version }}-linux-amd64.tar.gz"
      dest: /tmp
      remote_src: true
    when: helm_installed.failed

  # ... et on le met dans le répertoire /usr/local/bin
  - name: Install helm binary
    ansible.builtin.copy:
      src: /tmp/linux-amd64/helm
      dest: /usr/local/bin/helm
      mode: 0755
      remote_src: true
    when: helm_installed.failed

  tasks:
  # Installation de MetalLB via le chart de bitnami
  - name: Install metallb chart
    kubernetes.core.helm:
      release_name: metallb
      chart_ref: metallb
      chart_version: "{{ metallb_chart_version }}"
      chart_repo_url: https://charts.bitnami.com/bitnami
      release_namespace: metallb-system
      create_namespace: true
      values:
        configInline:
          address-pools:
          - name: generic-cluster-pool
            protocol: layer2
            addresses:
            - 192.168.1.230-192.168.1.250
    become: false

Dans la tâche Install metallb chart, nous allons déployer les deux composants dans le namespace metallb-system qui sont :

  • Le metallb-system/controller de type Deployment gère l'attribution des adresses IP ;
  • Le metallb-system/speaker de type DaemonSet permettra de rendre le service disponible en fonction du protocol choisi.

A cela s'ajoute un ensemble de comptes de service et d'autorisations RBAC pour rendre les composants opérationnels.

De plus, dans la partie values, on utilisera la configuration layer2 qui fait partie d'un ensemble de configuration qui permet de faire fonctionner MetalLB que vous pouvez retrouver à cette adresse.

C'est la configuration la plus simple qui permet d'attribuer une plage d'adresses IP pour nos équilibreurs de charge sans avoir besoin que cette même plage soit attachée à une carte réseau.

Juste avant d'exécuter notre playbook, il est nécessaire d'installer la collection Ansible qui permet de manipuler les objets Kubernetes et par conséquent les charts Helm :

ansible-galaxy collection install kubernetes.core

Exécutons notre playbook avec l'inventaire de Vagrant :

ansible-playbook install_metallb.yml -i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory

Juste après l'installation de MetalLB, on peut voir que notre service de type LoadBalancer a changé de statut :

$ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
nginx        LoadBalancer   10.98.188.48   192.168.1.230   80:31852/TCP   33m

Avec des événements associés :

$ kubectl describe svc nginx
(...)
Events:
  Type    Reason        Age    From                Message
  ----    ------        ----   ----                -------
  Normal  IPAllocated   3m39s  metallb-controller  Assigned IP "192.168.1.230"
  Normal  nodeAssigned  3m39s  metallb-speaker     announcing from node "k8s-worker1"

On peut même faire un curl sur l'adresse IP externe de notre LoadBalancer et avoir la page d'accueil de nginx :

$ curl 192.168.1.230
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Ce qui montre que notre service est totalement opérationnel !

Conclusion

MetalLB se révéle donc indispensable pour disposer de service LoadBalancer sur un orchestrateur Kubernetes qui n'est pas managé ou dans le Cloud. De plus, comme vous avez pu le constater, il est très rapide à installer et à configurer.

Cela est très pratique pour compléter notre cluster Kubernetes et en faire un vrai simulateur permettant de créer l'ensemble des objets et services dont on a besoin. :)