LoadBalancer Services

In PSKE, Kubernetes Services of type LoadBalancer are provisioned through the OpenStack Cloud Controller Manager (CCM). The CCM automatically creates an Octavia LoadBalancer in OpenStack and assigns a floating IP to it.

Configuration is done exclusively via annotations on the Service object.

Annotation Reference

IP and Network Configuration

AnnotationDefaultDescription
service.beta.kubernetes.io/openstack-internal-load-balancerfalseCreates an internal LoadBalancer without a floating IP. Access is restricted to the internal network.
loadbalancer.openstack.org/keep-floatingipfalseRetains the floating IP in OpenStack even after the Service is deleted.
loadbalancer.openstack.org/hostnameSets an explicit hostname in the Service status instead of the floating IP.
loadbalancer.openstack.org/load-balancer-addressAutomatically set after creation. Contains the floating IP. When hostname is set, this is the only place to find the actual IP.

Proxy Protocol and Headers

AnnotationDefaultDescription
loadbalancer.openstack.org/proxy-protocol ¹falseEnables PROXY protocol. Values: v1 / true (version 1), v2 (version 2). Passes the original client IP to the backend.
loadbalancer.openstack.org/x-forwarded-for ¹Adds the X-Forwarded-For header. Forces listener type HTTP.

Load Balancing Behavior

AnnotationDefaultDescription
loadbalancer.openstack.org/lb-methodCCM configLB algorithm. Values: ROUND_ROBIN, LEAST_CONNECTIONS, SOURCE_IP, SOURCE_IP_PORT.
loadbalancer.openstack.org/connection-limit-1 (unlimited)Maximum connections per second per listener. Supports live updates.
loadbalancer.openstack.org/load-balancer-idBinds the Service to an existing Octavia LoadBalancer. Must not be changed after creation.

Timeouts

AnnotationDefaultDescription
loadbalancer.openstack.org/timeout-client-data ¹30000 msFrontend client inactivity timeout in milliseconds.
loadbalancer.openstack.org/timeout-member-connect ¹Backend member connection timeout in milliseconds.
loadbalancer.openstack.org/timeout-member-data ¹30000 msBackend member inactivity timeout in milliseconds.
loadbalancer.openstack.org/timeout-tcp-inspect ¹Time to wait for additional TCP packets for content inspection, in milliseconds.

Use Cases

Internal LoadBalancer

An internal LoadBalancer does not receive a floating IP and is only reachable within the cluster network. The internal IP address can be specified via spec.loadBalancerIP (any free address from the node network, default: 10.250.0.0/16).

apiVersion: v1
kind: Service
metadata:
  name: my-internal-service
  annotations:
    service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
spec:
  type: LoadBalancer
  loadBalancerIP: 10.250.0.10
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 8080

Reserving and Reusing a Floating IP

By default, the floating IP is released when the Service is deleted. Setting keep-floatingip: "true" retains it in OpenStack.

Reserve a floating IP:

metadata:
  annotations:
    loadbalancer.openstack.org/keep-floatingip: "true"

Assign an already reserved floating IP:

metadata:
  annotations:
    loadbalancer.openstack.org/keep-floatingip: "true"
    loadbalancer.openstack.org/load-balancer-address: <FloatingIP>
spec:
  loadBalancerIP: <FloatingIP>

Release a floating IP (before deleting the Service):

metadata:
  annotations:
    loadbalancer.openstack.org/keep-floatingip: "false"
    loadbalancer.openstack.org/load-balancer-address: <FloatingIP>
spec:
  loadBalancerIP: <FloatingIP>

If it is no longer known which floating IPs are reserved, please open a support ticket in the customer portal.

Adjusting Timeouts

The default timeout for OpenStack LoadBalancers is 30 seconds. For applications with long-lived connections (e.g. WebSockets, large file uploads), the timeouts should be adjusted:

metadata:
  annotations:
    loadbalancer.openstack.org/timeout-client-data: "70000"
    loadbalancer.openstack.org/timeout-member-data: "70000"

Proxy Protocol — Forwarding the Client IP

Without the Proxy Protocol, all incoming connections appear in the backend with the LoadBalancer’s internal IP as the source. The Proxy Protocol passes the original client IP through.

Annotation on the LoadBalancer Service:

metadata:
  annotations:
    loadbalancer.openstack.org/proxy-protocol: "true"

Ingress Controller — NGINX (ConfigMap):

use-proxy-protocol: "true"
use-forwarded-headers: "true"

Ingress Controller — Traefik (Helm values):

ports:
  web:
    proxyProtocol:
      trustedIPs:
        - "0.0.0.0/0"
  websecure:
    proxyProtocol:
      trustedIPs:
        - "0.0.0.0/0"

Gateway API — Traefik v3 (Helm values):

Traefik natively supports the Gateway API from v3 onwards. Proxy Protocol is configured at the EntryPoint level — regardless of whether Ingress or Gateway API resources are used:

ports:
  web:
    proxyProtocol:
      trustedIPs:
        - "0.0.0.0/0"
  websecure:
    proxyProtocol:
      trustedIPs:
        - "0.0.0.0/0"

Gateway API — Envoy Gateway:

Proxy Protocol is enabled via a ClientTrafficPolicy targeting the respective Gateway:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
  name: proxy-protocol
  namespace: <gateway-namespace>
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: <gateway-name>
  enableProxyProtocol: true

Proxy Protocol and Internal Services

When the Proxy Protocol is enabled, kube-proxy routes cluster-internal access to the external LoadBalancer IP directly to the Ingress controller — without speaking the Proxy Protocol. This causes connection errors, for example when Cert-Manager attempts an ACME challenge.

Solution: The annotation loadbalancer.openstack.org/hostname sets a DNS name in the Service status. kube-proxy uses this name instead of the IP, preserving the path through the LoadBalancer.

metadata:
  annotations:
    loadbalancer.openstack.org/proxy-protocol: "true"
    loadbalancer.openstack.org/hostname: <loadbalancer-ip>.nip.io

For <loadbalancer-ip>.nip.io — or a custom DNS A record — the IP must resolve to the floating IP of the LoadBalancer.


Full upstream documentation is available in the GitHub project kubernetes/cloud-provider-openstack — use the release branch matching the deployed Kubernetes version.

Last modified 29.04.2026: Resolving last comments (b48501e)