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
- Crea un
Servicecontype: LoadBalancernel Suo shoot cluster. - Il cloud-controller-manager (CCM) rileva il nuovo servizio.
- 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.
- Un floating IP viene creato sulla rete pubblica e associato alla VIP del load balancer.
- Il CCM riscrive il floating IP nello stato del Service come
EXTERNAL-IP. kubectl get svcora 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.