Vai al contenuto

Kubernetes LoadBalancer e Octavia

Quando espone un'applicazione Kubernetes su Internet, in genere utilizza un Service di type: LoadBalancer. Sulla nostra piattaforma, questo crea automaticamente un vero Octavia Load Balancer nel Suo progetto OpenStack. Comprendere questa integrazione è fondamentale per risolvere i problemi di rete e gestire la quota.

Come funziona

Quando crea un Service con type: LoadBalancer nel Suo shoot cluster, il cloud-controller-manager, in esecuzione nel control plane dello shoot sul Seed, provisiona un load balancer Octavia in OpenStack e lo collega ai Suoi worker node.

%%{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;

Il flusso di provisioning

  1. Crea un Service con type: LoadBalancer nel Suo shoot cluster.
  2. Il cloud-controller-manager (CCM) rileva il nuovo servizio.
  3. Il CCM chiama l'API OpenStack Octavia per provisionare:
    • Un load balancer con una VIP sulla rete dei worker node.
    • Un listener per la porta specificata nel Service K8s.
    • Un pool con i worker node come membri.
    • Un health monitor che controlla ciascun worker node.
  4. Un floating IP viene creato sulla rete pubblica e associato alla VIP del load balancer.
  5. Il CCM riscrive il floating IP nello stato del Service come EXTERNAL-IP.
  6. kubectl get svc ora mostra l'IP esterno: la Sua applicazione è raggiungibile da Internet.

Cosa appare in OpenStack

Il load balancer Octavia è una vera risorsa OpenStack nel Suo progetto. Può vederlo in:

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

Ogni servizio K8s LoadBalancer crea:

Risorsa Octavia Scopo
Load Balancer L'oggetto LB di primo livello con una VIP sulla rete dei worker
Listener Ascolta sulla porta specificata nel Service K8s
Pool Contiene i worker node come membri
Members Uno per worker node, inoltra al NodePort
Health Monitor Controlla lo stato di salute dei worker node tramite il NodePort

Esempio pratico

Distribuisca nginx con un servizio 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

Applichi e verifichi il servizio:

kubectl apply -f nginx.yaml
kubectl get svc nginx

Durante il provisioning di Octavia, l'IP esterno viene mostrato come <pending>:

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

Una volta che Octavia è pronto (in genere da 30 a 60 secondi):

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

L'EXTERNAL-IP è il floating IP assegnato da Octavia. La Sua applicazione è ora raggiungibile all'indirizzo http://192.0.2.50.

Verificare in OpenStack

Il load balancer e il floating IP sono visibili in OpenStack:

openstack loadbalancer list
openstack floating ip list

Ciclo di vita del floating IP

Il floating IP appartiene sempre al servizio LoadBalancer, non all'oggetto Ingress. Ne consegue il seguente comportamento:

Azione Cosa succede al floating IP
Eliminare il servizio LoadBalancer Il floating IP viene eliminato e lascia il Suo progetto
Eliminare solo l'oggetto Ingress Il floating IP viene mantenuto: appartiene al servizio del controller Ingress
Disinstallare il controller Ingress (ad es. helm uninstall) Il floating IP viene eliminato perché il servizio del controller viene rimosso con esso
Eliminare e ricreare un servizio LoadBalancer Un nuovo floating IP con un indirizzo diverso: gli indirizzi IP non sono "sticky"

Mantenere un floating IP in modo permanente

Con l'annotazione loadbalancer.openstack.org/keep-floatingip: "true", il floating IP rimane nel Suo progetto quando il servizio viene eliminato. Viene quindi dissociato (openstack floating ip list lo mostra senza porta) e può essere riutilizzato in seguito:

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

Il riutilizzo avviene tramite spec.loadBalancerIP: il nuovo servizio adotta l'indirizzo esistente non appena è libero (dissociato).

Impostare l'annotazione su ogni servizio

L'annotazione si applica per servizio e non è legata all'indirizzo IP stesso. Un nuovo servizio che adotta un floating IP esistente tramite spec.loadBalancerIP deve impostare anch'esso l'annotazione, altrimenti l'IP viene eliminato insieme a quel servizio.

Gli indirizzi riservati non possono essere recuperati

Se deve conservare un indirizzo IP specifico (ad es. per record DNS o allowlist di firewall su sistemi remoti), riservarlo con l'annotazione è l'unico modo affidabile. Un floating IP eliminato non può essere riottenuto con lo stesso indirizzo.

NodePort vs LoadBalancer vs Ingress

NodePort LoadBalancer Ingress
Espone Un singolo servizio su una porta alta (da 30000 a 32767) Un singolo servizio su una porta standard Più servizi tramite routing HTTP(S)
IP esterno IP del worker node + porta del node Floating IP dedicato Dipende dal tipo di servizio del controller Ingress
LB Octavia No Sì, uno per servizio Solo se il controller Ingress utilizza LoadBalancer
Terminazione TLS No Possibile con annotazioni Sì (il controller Ingress gestisce il TLS)
Quota Nessuna 1 LB Octavia + 1 floating IP per servizio 1 LB Octavia (per il controller Ingress)
Ideale per Accesso interno / debug Singolo servizio esposto su Internet Più servizi HTTP(S) su un solo IP

Raccomandazione

Per più servizi HTTP(S), utilizzi un controller Ingress (ad es. nginx-ingress) con un unico servizio LoadBalancer. Questo consuma solo un LB Octavia e Le offre la terminazione TLS e il routing basato sul percorso.

Considerazioni sulla quota

Ogni Service di tipo LoadBalancer crea un load balancer Octavia nel Suo progetto OpenStack. Questo consuma:

  • Load balancer Octavia: verifichi la quota del Suo progetto.
  • Floating IP: uno per servizio LoadBalancer.
  • Porte: sulla rete dei worker node.

Se raggiunge il limite di quota, i nuovi servizi LoadBalancer rimangono nello stato <pending>. Verifichi la quota nel Cloud Services Portal o con:

openstack quota show

Pulizia

Quando elimina un Service Kubernetes di tipo LoadBalancer, il cloud-controller-manager elimina automaticamente il load balancer Octavia corrispondente e rilascia il floating IP:

Se desidera mantenere il floating IP (ad es. per un servizio futuro o record DNS stabili), imposti l'annotazione loadbalancer.openstack.org/keep-floatingip: "true" prima dell'eliminazione. Vedere Ciclo di vita del floating IP.

kubectl delete svc nginx

Warning

Elimini sempre prima il Service K8s. Se elimina manualmente il load balancer Octavia in OpenStack, il CCM potrebbe non essere in grado di ripulire correttamente, lasciando risorse orfane.

Load balancer Octavia manuali

Può anche creare load balancer Octavia manualmente per carichi di lavoro non Kubernetes (ad es. VM OpenStack). Consulti la guida ai load balancer OpenStack per esempi CLI, inclusi HTTP, terminazione HTTPS e health monitor.

Passo successivo

Scopra come creare service account persistenti oppure torni alla gestione dei cluster.