Aller au contenu

Kubernetes LoadBalancer et Octavia

Lorsque vous exposez une application Kubernetes sur Internet, vous utilisez généralement un Service de type: LoadBalancer. Sur notre plateforme, cela crée automatiquement un véritable Octavia Load Balancer dans votre projet OpenStack. Comprendre cette intégration est essentiel pour diagnostiquer les problèmes réseau et gérer le quota.

Fonctionnement

Lorsque vous créez un Service avec type: LoadBalancer dans votre shoot cluster, le cloud-controller-manager, qui s'exécute dans le control plane du shoot sur le Seed, provisionne un load balancer Octavia dans OpenStack et le relie à vos worker nodes.

%%{init: {'themeVariables': {'textColor': '#333333', 'edgeLabelBackground': '#ffffff', 'clusterBkg': 'transparent', 'clusterBorder': '#999999'}}}%%
flowchart LR
    Internet["Internet"]
    FIP["Floating IP<br>(public network)"]

    subgraph OS ["OpenStack"]
        LB["Octavia Load Balancer<br>Listener · Pool · Health Monitor"]
    end

    subgraph K8s ["Kubernetes Shoot Cluster"]
        W1["Worker Node 1"]
        W2["Worker Node 2"]
        Pod1["Pod: nginx"]
        Pod2["Pod: nginx"]
    end

    Internet --> FIP
    FIP --> LB
    LB --> W1
    LB --> W2
    W1 --> Pod1
    W2 --> Pod2

    classDef ext fill:#fce4ec,stroke:#c62828,color:#b71c1c;
    classDef fip fill:#e3f2fd,stroke:#1565c0,color:#0d47a1;
    classDef lb fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20;
    classDef worker fill:#fff3e0,stroke:#e65100,color:#bf360c;
    classDef pod fill:#f3e5f5,stroke:#6a1b9a,color:#4a148c;
    class Internet ext;
    class FIP fip;
    class LB lb;
    class W1,W2 worker;
    class Pod1,Pod2 pod;
    linkStyle 0,1 stroke:#c62828,stroke-width:2px;
    linkStyle 2,3 stroke:#2e7d32,stroke-width:2px;
    linkStyle 4,5 stroke:#e65100,stroke-width:2px;
%%{init: {'themeVariables': {'textColor': '#e0e0e0', 'edgeLabelBackground': '#2a2a2a', 'clusterBkg': 'transparent', 'clusterBorder': '#666666'}}}%%
flowchart LR
    Internet["Internet"]
    FIP["Floating IP<br>(public network)"]

    subgraph OS ["OpenStack"]
        LB["Octavia Load Balancer<br>Listener · Pool · Health Monitor"]
    end

    subgraph K8s ["Kubernetes Shoot Cluster"]
        W1["Worker Node 1"]
        W2["Worker Node 2"]
        Pod1["Pod: nginx"]
        Pod2["Pod: nginx"]
    end

    Internet --> FIP
    FIP --> LB
    LB --> W1
    LB --> W2
    W1 --> Pod1
    W2 --> Pod2

    classDef ext fill:#3e1e1e,stroke:#ef5350,color:#ffcdd2;
    classDef fip fill:#1a3a5c,stroke:#64b5f6,color:#e3f2fd;
    classDef lb fill:#1b3a2a,stroke:#66bb6a,color:#c8e6c9;
    classDef worker fill:#3e2723,stroke:#ff9800,color:#ffe0b2;
    classDef pod fill:#2a1a3a,stroke:#ab47bc,color:#e1bee7;
    class Internet ext;
    class FIP fip;
    class LB lb;
    class W1,W2 worker;
    class Pod1,Pod2 pod;
    linkStyle 0,1 stroke:#ef5350,stroke-width:2px;
    linkStyle 2,3 stroke:#66bb6a,stroke-width:2px;
    linkStyle 4,5 stroke:#ff9800,stroke-width:2px;

Le flux de provisionnement

  1. Vous créez un Service avec type: LoadBalancer dans votre shoot cluster.
  2. Le cloud-controller-manager (CCM) détecte le nouveau service.
  3. Le CCM appelle l'API OpenStack Octavia pour provisionner :
    • Un load balancer avec une VIP sur le réseau des worker nodes.
    • Un listener pour le port spécifié dans le Service K8s.
    • Un pool avec les worker nodes comme membres.
    • Un health monitor qui vérifie chaque worker node.
  4. Une floating IP est créée sur le réseau public et associée à la VIP du load balancer.
  5. Le CCM réécrit la floating IP dans le statut du Service en tant que EXTERNAL-IP.
  6. kubectl get svc affiche désormais l'IP externe : votre application est accessible depuis Internet.

Ce qui apparaît dans OpenStack

Le load balancer Octavia est une véritable ressource OpenStack dans votre projet. Vous pouvez le voir dans :

  • OpenStack Horizon → Network → Load Balancers
  • OpenStack CLI : openstack loadbalancer list

Chaque service K8s LoadBalancer crée :

Ressource Octavia Rôle
Load Balancer L'objet LB de niveau supérieur avec une VIP sur le réseau des workers
Listener Écoute sur le port spécifié dans le Service K8s
Pool Contient les worker nodes comme membres
Members Un par worker node, redirige vers le NodePort
Health Monitor Vérifie l'état de santé des worker nodes via le NodePort

Exemple pratique

Déployez nginx avec un service LoadBalancer :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.27
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx

Appliquez et vérifiez le service :

kubectl apply -f nginx.yaml
kubectl get svc nginx

Pendant le provisionnement par Octavia, l'IP externe s'affiche comme <pending> :

NAME    TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx   LoadBalancer   10.97.246.12   <pending>     80:31234/TCP   5s

Une fois Octavia prêt (généralement 30 à 60 secondes) :

NAME    TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
nginx   LoadBalancer   10.97.246.12   192.0.2.50     80:31234/TCP   45s

Le EXTERNAL-IP est la floating IP attribuée par Octavia. Votre application est désormais accessible à l'adresse http://192.0.2.50.

Vérifier dans OpenStack

Le load balancer et la floating IP sont visibles dans OpenStack :

openstack loadbalancer list
openstack floating ip list

Cycle de vie des floating IP

La floating IP appartient toujours au service LoadBalancer, et non à l'objet Ingress. Il en résulte le comportement suivant :

Action Ce qui arrive à la floating IP
Supprimer le service LoadBalancer La floating IP est supprimée et quitte votre projet
Supprimer uniquement l'objet Ingress La floating IP est conservée : elle appartient au service du contrôleur Ingress
Désinstaller le contrôleur Ingress (par ex. helm uninstall) La floating IP est supprimée, car le service du contrôleur l'est aussi
Supprimer puis recréer un service LoadBalancer Une nouvelle floating IP avec une adresse différente : les adresses IP ne sont pas persistantes

Conserver une floating IP de façon permanente

Avec l'annotation loadbalancer.openstack.org/keep-floatingip: "true", la floating IP reste dans votre projet lorsque le service est supprimé. Elle est alors dissociée (openstack floating ip list l'affiche sans port) et peut être réutilisée plus tard :

apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    loadbalancer.openstack.org/keep-floatingip: "true"
spec:
  type: LoadBalancer
  loadBalancerIP: 192.0.2.50   # free floating IP from your project
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80

La réutilisation passe par spec.loadBalancerIP : le nouveau service adopte l'adresse existante dès qu'elle est libre (dissociée).

Définir l'annotation sur chaque service

L'annotation s'applique par service et n'est pas liée à l'adresse IP elle-même. Un nouveau service qui adopte une floating IP existante via spec.loadBalancerIP doit aussi définir l'annotation, sinon l'IP est supprimée en même temps que ce service.

Les adresses réservées ne peuvent pas être récupérées

Si vous devez conserver une adresse IP précise (par ex. pour des enregistrements DNS ou des listes d'autorisation de pare-feu sur des systèmes distants), la réserver avec l'annotation est le seul moyen fiable. Une floating IP supprimée ne peut pas être réobtenue sous la même adresse.

NodePort vs LoadBalancer vs Ingress

NodePort LoadBalancer Ingress
Expose Un seul service sur un port élevé (30000 à 32767) Un seul service sur un port standard Plusieurs services via routage HTTP(S)
IP externe IP du worker node + port du node Floating IP dédiée Dépend du type de service du contrôleur Ingress
LB Octavia Non Oui, un par service Uniquement si le contrôleur Ingress utilise LoadBalancer
Terminaison TLS Non Possible avec des annotations Oui (le contrôleur Ingress gère le TLS)
Quota Aucun 1 LB Octavia + 1 floating IP par service 1 LB Octavia (pour le contrôleur Ingress)
Idéal pour Accès interne / débogage Un seul service exposé sur Internet Plusieurs services HTTP(S) sur une seule IP

Recommandation

Pour plusieurs services HTTP(S), utilisez un contrôleur Ingress (par ex. nginx-ingress) avec un seul service LoadBalancer. Cela ne consomme qu'un seul LB Octavia et vous offre la terminaison TLS et le routage basé sur le chemin.

Considérations sur le quota

Chaque Service de type LoadBalancer crée un load balancer Octavia dans votre projet OpenStack. Cela consomme :

  • Load balancers Octavia : vérifiez le quota de votre projet.
  • Floating IP : une par service LoadBalancer.
  • Ports : sur le réseau des worker nodes.

Si vous atteignez la limite de quota, les nouveaux services LoadBalancer restent en état <pending>. Vérifiez votre quota dans le Cloud Services Portal ou avec :

openstack quota show

Nettoyage

Lorsque vous supprimez un Service Kubernetes de type LoadBalancer, le cloud-controller-manager supprime automatiquement le load balancer Octavia correspondant et libère la floating IP :

Si vous souhaitez conserver la floating IP (par ex. pour un futur service ou des enregistrements DNS stables), définissez l'annotation loadbalancer.openstack.org/keep-floatingip: "true" avant la suppression. Voir Cycle de vie des floating IP.

kubectl delete svc nginx

Warning

Supprimez toujours d'abord le Service K8s. Si vous supprimez manuellement le load balancer Octavia dans OpenStack, le CCM risque de ne pas pouvoir nettoyer correctement, laissant des ressources orphelines.

Load balancers Octavia manuels

Vous pouvez également créer des load balancers Octavia manuellement pour des charges de travail non Kubernetes (par ex. des VM OpenStack). Consultez le guide des load balancers OpenStack pour des exemples CLI, y compris HTTP, la terminaison HTTPS et les health monitors.

Étape suivante

Apprenez à créer des comptes de service persistants ou revenez à la gestion des clusters.