Load balancing
This tutorial describes how a load balancer (LB) can be created through a Kubernetes service object.
Mechanisms
Abschnitt betitelt „Mechanisms“When creating a Kubernetes service object, you can choose between several different types of services (see: Service Types in the Kubernetes documentation ).
On creation of a Kubernetes service object with the type Load Balancer, one or more servers inside your portal project will be created, which will receive the traffic through a public IP and then redirect it to the Kubernetes cluster, where it will then be routed to the corresponding pods.
These servers and public IPs are visible inside your Portal project via API and will be charged as normal VMs.
Server view inside the portal project, including load balancer VMs:

Creating a load balancer service
Abschnitt betitelt „Creating a load balancer service“A new load balancer can be created using the Kubernetes service object. Inside a service, you can define which application/pods (spec.selector) should receive the traffic on a specified port (spec.ports). For more information, see Services in the Kubernetes documentation.
Example service:
apiVersion: v1kind: Servicemetadata: name: my-servicespec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 8080 type: LoadBalancerAs soon as the service is ready to use, a public IP will appear in your service object. With this IP, you can reach your service:
kubectl get serviceThe output will look similar to this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEmy-service LoadBalancer 100.67.140.208 193.148.xxx.xxx 80:30642/TCP 14hFunctionalities
Abschnitt betitelt „Functionalities“Configuration
Abschnitt betitelt „Configuration“STACKIT Load Balancer can be configured via annotations on the service object. Clusters using STACKIT Load Balancers support annotations from the following table that are prefixed with either lb.stackit.cloud/.
| Annotation | Default | Description |
|---|---|---|
lb.stackit.cloud/internal-lb | ”false” | The load balancer is not exposed via a public IP, but instead resides in the Kubernetes nodes network. (This allocated local IP is not persistent. It changes in case the service gets recreated.) |
lb.stackit.cloud/tcp-proxy-protocol | ”false” | Enables the TCP proxy protocol for TCP ports. Also see lb.stackit.cloud/ip-mode-proxy. |
lb.stackit.cloud/tcp-proxy-protocol-ports-filter | none | Defines which ports use the TCP proxy protocol. Only takes effect if TCP proxy protocol is enabled. If the annotation is not present then all TCP ports use the TCP proxy protocol. Has no effect on UDP ports. The ports must be specified as a comma separated list, for example “8080,80” for ports 8080 and 80. |
lb.stackit.cloud/tcp-idle-timeout | If unset, the default is “1h” (1 hour). | Defines the idle timeout for all TCP ports (including ports that use the PROXY protocol). The value must include a valid unit (like “s”, “m”, “h”). For a timeout of 5 minutes 30 seconds, set “5m30s”. |
lb.stackit.cloud/udp-idle-timeout | If unset, the default is “2m” (2 minutes). | Defines the idle timeout for all UDP ports. The value must include a valid unit (like “s”, “m”, “h”). For a timeout of 5 minutes 30 seconds, set “5m30s”. |
lb.stackit.cloud/external-address | none | Refer to an existing public IP for the load balancer by specifying the IP address, for example “198.51.100.17”. When specified, it is used instead of an ephemeral IP. The user must create this IP, and it persists even after service deletion. However, this annotation is ignored for internal load balancers. If this annotation is set post-creation of the service, it must match the assigned used ephemeral IP. The ephemeral IP will be promoted to a static IP that persists even after service deletion. |
lb.stackit.cloud/service-plan-id | p10 | Defines the service plan for the load balancer. |
lb.stackit.cloud/ip-mode-proxy | ”false” | If true, the load balancer will be reported to Kubernetes as a proxy (in the service status). This causes connections to the load balancer IP that come from within the cluster to be routed through the load balancer, rather than directly to a target pod. Requires Kubernetes v1.30. The annotation has no effect on earlier versions. Recommended in combination with the TCP proxy protocol, to ensure that connection from within the cluster also use the proxy protocol. See Load Balancer IP Mode for more details. |
lb.stackit.cloud/session-persistence-with-source-ip | ”false” | When set to true, all connections from the same source IP are consistently routed to the same target. This setting changes the load balancing algorithm to Maglev. Note, this only works reliably when externalTrafficPolicy: Local is set on the Service, and each node has exactly one backing pod. Otherwise, session persistence may break. |
Limit source IP ranges
Abschnitt betitelt „Limit source IP ranges“To limit the access to an IP range, configure service.spec.loadBalancerSourceRanges.To also allow accesses to the load balancer from within the cluster, the podCIDR needs to be added to the allowed IP ranges.
Service plans and flavors
Abschnitt betitelt „Service plans and flavors“Service plans were introduced as a way to vertically scale load balancers. They can be configured using an annotation on your service. The annotation is optional and the service plan p10 is used by default.
| Plan | Type | vCPU | Memory(GB) | Region |
|---|---|---|---|---|
| p10 | High Availability (HA)(Active / Passive) (2 VMs) | 1 | 1 | EU01 |
| p50 | High Availability (HA)(Active / Passive) (2 VMs) | 4 | 4 | EU01 |
| p250 | High Availability (HA)(Active / Passive) (2 VMs) | 8 | 8 | EU01 |
| p750 | High Availability (HA)(Active / Passive) (2 VMs) | 16 | 16 | EU01 |
Examples
Abschnitt betitelt „Examples“Internal load balancers
Abschnitt betitelt „Internal load balancers“By default, Load Balancers are created with a public IP. If you want to use an internal Load Balancer, which resides in the network of your Kubernetes nodes, you can define it by adding an annotation to your service, as shown in the example below.
Example service:
apiVersion: v1kind: Servicemetadata: annotations: lb.stackit.cloud/internal-lb: "true" name: my-internal-servicespec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 8080 type: LoadBalancerLimit source IP ranges
Abschnitt betitelt „Limit source IP ranges“A Kubernetes Service definition contains a field called loadBalancerSourceRanges to limit the IP ranges which can access the Load Balancer.
To limit the access to an IP Range (for example 123.123.123.0/24) this IP range can be set in the Service definition as follows:
Example service:
apiVersion: v1kind: Servicemetadata: annotations: name: my-sourcerange-servicespec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 8080 loadBalancerSourceRanges: - 123.123.123.0/24 type: LoadBalancerEnsure that you add the pod CIDR (e.g. 10.96.0.0/11) to the loadBalancerSourceRanges if you need to access the Load Balancer from within the same cluster. You can find the pod CIDR in the shoot-info ConfigMap by running:
kubectl describe configmap -n kube-system shoot-infoTCP proxy protocol
Abschnitt betitelt „TCP proxy protocol“To use client IPs inside of Kubernetes, the Proxy Protocol (Version 2) can be enabled.
To enable the proxy protocol support, set the following annotation on your Kubernetes Service object.
Example service:
apiVersion: v1kind: Servicemetadata: annotations: lb.stackit.cloud/tcp-proxy-protocol: "true" name: my-proxy-servicespec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 8080 type: LoadBalancerChange service plan
Abschnitt betitelt „Change service plan“To obtain a STACKIT load balancer with increased resources (e.g., 4 vCPUs and 4GB RAM), you can select a higher-tier service plan.
Example service:
apiVersion: v1kind: Servicemetadata: annotations: lb.stackit.cloud/service-plan-id: p50 name: my-servicespec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 8080 type: LoadBalancerSession persistence
Abschnitt betitelt „Session persistence“To enable session persistence add the lb.stackit.cloud/session-persistence-with-source-ip annotation as shown in the example.
Example service:
apiVersion: v1kind: Servicemetadata: annotations: lb.stackit.cloud/session-persistence-with-source-ip: "true" name: my-servicespec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 8080 type: LoadBalancer externalTrafficPolicy: LocalNote, this only works reliably when externalTrafficPolicy: Local is set on the Service, and each node has exactly one backing pod. Otherwise, session persistence may break.