Support Online
Skip to main content

Configuring Advanced Load Balancer Settings in Kubernetes Clusters

Kubernetes includes a fully managed control plane, high availability, and auto-scaling.
Integrates with standard Kubernetes toolchains (kubectl, API and CLI). It also supports CPU and GPU node pools, load balancers and volumes.

Kubernetes Cloud Controller Manager allows advanced settings for load balancers.
These settings are added via annotations in the metadata section in the service configuration file.
If an incorrect annotation value is entered, an error will be received when trying to apply the config file.

⚠️ Uyarı
Kümenin **Resources** sekmesine ek olarak; worker node’lar, load balancer’lar ve volume’lar,
Kubernetes sayfası dışında da listelenir.

Bu kaynakları kontrol panelinde yeniden adlandırır veya değiştirirseniz:
- Küme tarafından kullanılamaz hale gelebilirler,
- Veya reconciler yeni kaynaklar oluşturabilir.

Bunu önlemek için küme kaynaklarını yalnızca **kubectl** komutları
veya kontrol panelinin **Kubernetes sayfası** üzerinden yönetin.

Name

Available version: 1.27.x and later

This setting allows you to specify a custom name or rename an existing load balancer. The name must follow these rules:

  • Must not be longer than 255 characters.
  • Must start with Alphanumeric character.
  • Alphanumeric characters can contain . (dot) or - (quote mark), but the final character cannot be -.

If no specific name is given, the load balancer defaults to a name starting with the UID Service.

Example usage:

metadata:
name: my-example-service

Protocol

Available version: 1.27.x and later

This setting specifies the protocol to be used for the LoadBalancer service.

Available options: TCP or UDP.

For features like SSL/HTTPS, Ingress + cert-manager is often used.

You also need to set up a health check port that uses TCP, HTTP, or HTTPS for it to work properly.

The following example shows using https as the load balancer protocol:

. . .
metadata:
name: https-protocol-snippet
. . .

To use the UDP protocol with a Load Balancer, use the ports section in the load balancer service configuration file as follows:

spec:
type: LoadBalancer
selector:
app: nginx-example
ports:
- name: udp
protocol: UDP
port: 53
targetPort: 53

Due to a bug in Kubernetes, a load balancer port cannot be shared between TCP and UDP**.

Network Load Balancer

Available version: 1.29.x and later

This setting creates a regional load balancer** that routes TCP and UDP traffic at the network layer.
The feature is currently in public preview and does not have IPv6 support.

The following example shows how to create a network load balancer:

metadata:
name: example-nlb

UDP or TCP must be specified as the protocol in the ports section of your configuration, and the port and targetPort values must be the same.

Internal Load Balancer

Available version: 1.28.x and later

This setting creates a load balancer without any public IP address.
To access the internal load balancer, the resources must be in the same VPC.

Once a load balancer has been created, it is not possible to switch it between normal (with public IP) and internal.

The following example shows how to create an internal load balancer:

metadata:
name: example-ilb

Health Checks

Available version: 1.27.x and later (basic functionality)

Health checks verify that your nodes are online and meet specific health criteria you define.
The load balancer only forwards requests to nodes that pass the health check.

If UDP is used in the load balancer's routing rules, you must set a health check port that uses TCP, HTTP, or HTTPS for it to work properly.

Cloud Controller Manager automatically sets an appropriate health check configuration to determine pod and node availability and ensure smooth transitions during workload and node changes.
The specific values ​​determined depend on the external traffic policy setting.

Note:
In general, it is recommended that you do not manually change the health check annotations for port, path and protocol.

Port

The load balancer performs health checks over a port belonging to your service. The default value is the first NodePort in worker nodes defined in the service.
To replace it with your own value:

  • You must specify an open port (not NodePort),
  • You must also add the annotation service.beta.kubernetes.io/loadbalancer-override-health-check.

Path

The load balancer uses the specified path value to verify whether the backend node is healthy. The default value is /.
You must set the annotation service.beta.kubernetes.io/loadbalancer-override-health-check to replace it with your own value.

####Protocol

The load balancer uses a protocol to verify whether the backend node is healthy. The default value is tcp. Other options are http and https.
You must set the annotation service.beta.kubernetes.io/loadbalancer-override-health-check to replace it with your own value.

UDP is not supported as a health check protocol. However, if your load balancer has UDP service ports, you need to configure a TCP service for health check for the load balancer to work properly.

Override Health Check

To replace the default health check port, path and protocol values ​​with your own values, you must additionally set the service.beta.kubernetes.io/loadbalancer-override-health-check annotation to true.

Interval

Time in seconds between two consecutive health checks.

  • The value must be between 3 and 300.
  • Default value: 3 seconds.

Timeout

The time the load balancer instance waits to receive a response. If this time expires, the health check is considered unsuccessful.

  • The value must be between 3 and 300.
  • Default value: 5 seconds.

Threshold

Specifies the number of times the health check must fail for a backend Droplet to be marked as unhealthy and removed from the relevant service's pool.

  • The value must be between 2 and 10.
  • Default value: 3.

The following example shows the health check configuration for a load balancer:

metadata:
name: health-check-snippet
annotations:
service.beta.kubernetes.io/loadbalancer-healthcheck-port: "80"
service.beta.kubernetes.io/loadbalancer-healthcheck-protocol: "http"
service.beta.kubernetes.io/loadbalancer-healthcheck-path: "/health"

External Traffic Policies and Health Checks

Load balancers managed by the cloud provider evaluate the health of the endpoints for the LoadBalancer service that provides them.

The behavior of a health check depends on the externalTrafficPolicy setting of the service.

  • Can be set to Local or Cluster.

  • Local policy: Health check is accepted only if the target pod is running on the local node.

  • Cluster policy: Allows nodes to distribute requests to pods on other nodes connected to the cluster.

Local Policy

  • Services that use local policy mark nodes that do not have any local endpoints belonging to that service as unhealthy.
  • The kube-proxy /healthz endpoint on the separate health check node port, specially created by Kubernetes, indicates whether there is an active pod on the node.

Cluster Policy

  • Services that use cluster policy can consider nodes as healthy even if they do not have pods hosting that service.
  • The kube-proxy /healthz endpoint on each worker node shows whether the node is healthy or not.

Note

  • Local external traffic policy ensures that worker nodes are drained safely before removal.
  • You must select the health check parameters (e.g. frequency and threshold values) so that the node is marked as unhealthy before the last target pod on the node stops accepting requests.

Changing the Setting

To change this setting for a service, you can run the following command, adding the desired policy value:

kubectl patch svc <service-adı> -p '{"spec":{"externalTrafficPolicy":"Local"}}'

Note:
Using externalTrafficPolicy=Local ensures secure routing of traffic before nodes are evacuated.
For more information on preserving the original client IP, you can refer to the Kubernetes official documentation.

Ports

You can specify which ports of the load balancer will be used for the HTTP, HTTP/2 or TLS protocol.

Note:
Ports cannot be shared between HTTP, TLS and HTTP/2 port annotations.

HTTP Ports

Available version: 1.27.x and later

This annotation is used to indicate which ports of the load balancer will use the HTTP protocol.

  • Values ​​must be comma separated list of ports (for example: 80, 8080).

The following example shows how to specify an HTTP port:

. . .
metadata:
name: http-ports-snippet
annotations:
service.beta.kubernetes.io/loadbalancer-http-ports: "80"
. . .

HTTP/2 Ports

Available version: 1.27.x and later

This annotation is used to indicate which ports of the load balancer will use the HTTP/2 protocol.

  • Values ​​must be comma separated list of ports (for example: 443, 6443, 7443).
  • If specified, you must also define one of the following annotations:
    • service.beta.kubernetes.io/loadbalancer-tls-passthrough
    • service.beta.kubernetes.io/loadbalancer-certificate-id
    • service.beta.kubernetes.io/loadbalancer-certificate-name

If service.beta.kubernetes.io/loadbalancer-protocol is not set to http2, this annotation is required to use HTTP/2 implicitly.

For HTTP/2, unlike service.beta.kubernetes.io/loadbalancer-tls-ports, a default port is not assigned.

The following example shows how to specify an HTTP/2 port:

. . .
metadata:
name: http2-ports-snippet
annotations:
service.beta.kubernetes.io/loadbalancer-http2-ports: "443,80"
. . .

HTTP/3 Ports

Available version: 1.25.4, 1.24.8, 1.23.14

This annotation is used to indicate which port of the load balancer will use the HTTP/3 protocol.

  • Unlike other annotations, more than one port cannot be specified; HTTP/3 can only be defined for a single port.
  • HTTP/3 is not assigned a default port, so you must provide a port number.

To use the HTTP/3 protocol:

  • service.beta.kubernetes.io/loadbalancer-certificate-id or
  • service.beta.kubernetes.io/loadbalancer-certificate-name
    You must add one of the annotations.

Since the load balancer can only receive HTTP/3 traffic, you must also define a protocol for push traffic. To do this, you must add one of the following annotations:

  • service.beta.kubernetes.io/loadbalancer-tls-ports or
  • service.beta.kubernetes.io/loadbalancer-http2-ports

TLS Ports

Available version: 1.27.x and later

This annotation is used to indicate which ports of the load balancer will use the HTTPS protocol:

Values must be comma separated list of ports (for example: 443, 6443, 7443).
If specified, you must also define one of the following:

  • service.beta.kubernetes.io/loadbalancer-tls-passthrough: Specifies whether the load balancer will transmit encrypted data to backend Droplets. Options are true or false. The default value is false.

  • service.beta.kubernetes.io/loadbalancer-certificate-id: Specifies the certificate ID to be used for the HTTPS protocol. You can use the kubectl describe certificate <cert-adı></cert-adı> (e.g. with cert-manager) command to see available certificates.

  • service.beta.kubernetes.io/loadbalancer-certificate-name (1.26 and later): Specifies the certificate name to be used for the HTTPS protocol. It is recommended that you use this annotation because the name of the Let's Encrypt certificate does not change, but its ID changes with each renewal. The certificate name must be unique within the account. You can use the kubectl describe certificate <cert-adı></cert-adı> (e.g. with cert-manager) command to see available certificates.

If you do not specify an HTTPS port but define one of the annotations service.beta.kubernetes.io/loadbalancer-tls-passthrough, service.beta.kubernetes.io/loadbalancer-certificate-id, or service.beta.kubernetes.io/loadbalancer-certificate-name, the load balancer defaults to port 443 for HTTPS. However, if the service.beta.kubernetes.io/loadbalancer-http2-ports annotation already includes port 443, this rule does not apply.

The following example shows how to specify a TLS port with passthrough:

. . .
metadata:
name: tls-ports-snippet
annotations:
service.beta.kubernetes.io/loadbalancer-tls-ports: "443"
. . .

HTTP Idle Timeout

Available version: 1.27.x and later

Specifies the HTTP idle timeout duration in seconds. The default value is 60 seconds.

The following example specifies the timeout value as 65 seconds:

. . .
metadata:
name: http-idle-timeout
annotations:
service.beta.kubernetes.io/loadbalancer-http-idle-timeout-seconds: "65"
. . .

Accessing by Hostname

Available version: 1.27.x and later

Due to an existing restriction in upstream Kubernetes, pods cannot communicate with other pods via the IP address of an external load balancer set via a service of type LoadBalancer.

To get around this:

  • You can create a private DNS record with a provider of your choice and direct it to the load balancer's external IP address.
  • Then configure the service to return the custom hostname by adding hostname to the service.beta.kubernetes.io/loadbalancer-hostname annotation.
  • You can then get the hostname information using the status.Hostname field of the service.

The workflow for setting the service.beta.kubernetes.io/loadbalancer-hostname annotation is typically as follows:

  1. Deploy the manifest containing your service (as in the example below).
  2. Wait for the external IP address of the service to be assigned.
  3. Add an A or AAAA DNS record for your hostname that points to the external IP.
  4. Add the hostname annotation to your manifest file (as in the example below) and redeploy.
kind: Service
apiVersion: v1
metadata:
name: hello
annotations:
service.beta.kubernetes.io/loadbalancer-certificate-id: "1234-5678-9012-3456"
service.beta.kubernetes.io/loadbalancer-protocol: "https"
service.beta.kubernetes.io/loadbalancer-hostname: "hello.example.com"
spec:
type: LoadBalancer
selector:
app: my-app-example
ports:
- name: https
protocol: TCP
port: 443
targetPort: 80
. . .

SSL Certificates

Available version: 1.27.x and later

You can encrypt incoming traffic to your Kubernetes cluster using an SSL certificate in conjunction with the load balancer.
First you need to create or install an SSL certificate, then you can use one of the following annotations to reference the certificate in the load balancer's configuration file:

  • service.beta.kubernetes.io/loadbalancer-certificate-id → To specify the certificate ID.
  • service.beta.kubernetes.io/loadbalancer-certificate-name (1.26.x and later) → To specify the certificate name.

It is recommended that you use this annotation because the name of the Let's Encrypt certificate does not change, but the ID changes with each renewal. The certificate name must be unique within the account.

If you specify both certificate ID and certificate name, certificate ID takes precedence.

You can use the following command to get the IDs of installed SSL certificates:

kubectl describe certificate <certificate-adı>

To use the certificate, you must specify the load balancer protocol as HTTPS.
To do this, you can use one of the following annotations:

service.beta.kubernetes.io/loadbalancer-protocol
service.beta.kubernetes.io/loadbalancer-tls-ports

Additionally, you can specify whether to automatically create a DNS record for the certificate when creating the load balancer.
Use this annotation for this:

loadbalancer-disable-lets-encrypt-dns-records

If set to true, DNS A records will not be automatically created at the root (apex) of your domain to support the SSL certificate.

This setting is available starting from versions 1.21.5, 1.20.11 and 1.19.15.

The following example shows how to create a load balancer using an SSL certificate:

---
kind: Service
apiVersion: v1
metadata:
name: https-with-cert
annotations:
service.beta.kubernetes.io/loadbalancer-protocol: "https"
service.beta.kubernetes.io/loadbalancer-certificate-id: "your-certificate-id"
spec:
type: LoadBalancer
selector:
app: nginx-example
ports:
- name: https
protocol: TCP
port: 443
targetPort: 80
. . .

Note:
When you renew a Let's Encrypt certificate, cert-manager or the Ingress Controller you are using will automatically update this renewal.
However, you will need to manually update external configuration files and tools that reference the UUID.

For further troubleshooting, you can refer to the documentation for cert-manager or the ingress controller you are using.

Mandatory SSL Connections

Available version: 1.27.x and later

The SSL option redirects HTTP requests on port 80** to HTTPS on port 443.
When this option is enabled, HTTP URLs are redirected to HTTPS with 307 redirect.

The following example shows the configuration settings that must be set to true for redirection to work:

. . .
name: https-with-redirect-snippet
annotations:
service.beta.kubernetes.io/loadbalancer-protocol: "http"
service.beta.kubernetes.io/loadbalancer-tls-ports: "443"
service.beta.kubernetes.io/loadbalancer-certificate-id: "your-certificate-id"
service.beta.kubernetes.io/loadbalancer-redirect-http-to-https: "true"
spec:
type: LoadBalancer
selector:
app: nginx-example
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 80
. . .

Size Unit

Available version: 1.27.x and later

This setting allows you to specify how many nodes the load balancer will be created with.

  • More nodes means the load balancer can handle more connections simultaneously.

The value can be an integer between 1 and 200, and the default value is 1.
Your actual load balancer node limit is determined by the limits defined in your account. You can contact the support team to request a limit increase.

Once the load balancer is created, resizing can be done once per minute.

The following example shows how to specify the number of nodes a load balancer will have:

. . .
metadata:
name: nginx
annotations:
service.beta.kubernetes.io/loadbalancer-size-unit: "3"
. . .

Sticky Sessions

Available version: 1.27.x and later

Sticky sessions redirect consecutive requests from the same client to the same node.
To do this, a configurable cookie name and TTL (Time-To-Live) duration are specified.

  • TTL parameter defines how long the cookie will remain valid in the client browser.
  • This feature is useful for application sessions that need to connect to the same node on every request.

Highlights:

  • Sticky sessions have consistent routing to nodes, not pods. Therefore, you should avoid running more than one pod on the same node to meet requests.
  • To use Sticky sessions, you must configure your service with externalTrafficPolicy: Local. This ensures that client source IP addresses are protected while incoming traffic is forwarded to other nodes.

The loadbalancer-sticky-sessions-type annotation is used to enable or disable sticky sessions:

  • cookiesEnables Sticky sessions.
  • nonedisables Sticky sessions (default behavior).
metadata:
name: sticky-session-snippet
annotations:
service.beta.kubernetes.io/loadbalancer-sticky-sessions-type: "cookies"
service.beta.kubernetes.io/loadbalancer-sticky-sessions-cookie-name: "example"
service.beta.kubernetes.io/loadbalancer-sticky-sessions-cookie-ttl: "60"

PROXY Protocol

Available version: 1.27.x and later

Enabling the PROXY protocol allows the load balancer to forward client connection information (for example, client IP addresses) to your nodes.
The software running on the nodes must be configured correctly to accept this connection information from the load balancer.

Options: true or false
Default value: false

---
. . .
metadata:
name: proxy-protocol
annotations:
service.beta.kubernetes.io/loadbalancer-enable-proxy-protocol: "true"
. . .

Protecting Client Source IP Address

Most cloud load balancers do not automatically maintain the client's source IP address when routing requests. You can use one of the following methods to protect the source IP address:

  • Enable PROXY protocol → This requires that the application or ingress provider receiving the request be able to parse the PROXY protocol header.

  • Use the X-Forwarded-For HTTP header → Most cloud load balancers add this header automatically.
    This method only works when the entry and target protocols are HTTP or HTTP/2 (excluding TLS passthrough).

For more information, see the Cross-platform support section in the Kubernetes documentation.

Backend Keepalive

Available version: 1.27.x and later

By default, some cloud provider Load Balancers block HTTP responses from backend nodes.
It ignores the Connection: keep-alive header and closes the connection when the operation is completed.

When Backend keepalive is enabled, the load balancer takes this header into account and keeps the connection open for reuse.
This way, the load balancer can use fewer active TCP connections to send and receive HTTP requests with target nodes.

Enabling this option generally increases performance (requests per second and latency) and makes resource usage more efficient.
In many use cases, such as websites and APIs, it can improve the performance experienced by the client.
However, it is not guaranteed to improve performance in all cases and may increase latency in some scenarios.

This option applies to all redirect rules where the target protocol is HTTP or HTTPS.
Does not apply to redirect rules using TCP, HTTPS, or HTTP/2 passthrough.

There is no hard limit on the number of connections between the load balancer and each server.
However, if the target servers have low hardware resources, they may not be able to process incoming traffic and packet losses may occur.
For more information, see Kubernetes Ingress Controller performance settings.

Options: true or false
Default value: false

---
. . .
metadata:
name: backend-keepalive
annotations:
service.beta.kubernetes.io/loadbalancer-enable-backend-keepalive: "true"
. . .

Disown

Available version: 1.27.x and later

This setting allows you to specify whether to relinquish ownership of a managed load balancer.
Changes can no longer be made to decommissioned load balancers; This includes create, update and delete operations.

Using this setting, you can transfer ownership of a load balancer to another Service, or even to a Service in another cluster.
For more information, see Changing Ownership of the Load Balancer.

Options: true or false
Default value: false

You must provide the value as string, otherwise all annotations in your Service resource may be lost due to a bug in Kubernetes.

⚠️ Warning

Decommissioned load balancers may not work correctly in this case.
This is because necessary updates such as target nodes or configuration annotations are no longer pushed to the load balancer.
Similarly, the Service status field may not reflect the current status of the load balancer.
Therefore, you should assign disowned load balancers to a new Service as soon as possible.

The following example shows how to remove ownership of a load balancer:

. . .
metadata:
name: disown-snippet
annotations:
service.kubernetes.io/loadbalancer-disown: "true"
. . .

Firewall Rules

Available version: 1.27.x and later

Deny Rules

Specifies firewall rules that block traffic from passing through.
Rules must be in the following format: &#123;type&#125;:&#123;source&#125;

The following example shows how to add firewall rules to block connections from IP block 198.51.100.0/16:

. . .
metadata:
name: firewall-rules
annotations:
service.beta.kubernetes.io/loadbalancer-deny-rules: "cidr:198.51.100.0/16"
. . .

Allow Rules

Note:
The service.beta.kubernetes.io/loadbalancer-allow-rules annotation is now deprecated. Instead, use the LoadBalancerSourceRanges field in the service configuration file.
The values ​​specified in this field take precedence over the relevant annotation.

Specifies the firewall rules that allow traffic to pass.
Rules must be in the following format: &#123;type&#125;:&#123;source&#125;