LoadBalancer implementation. This can be a cloud solution or a self-managed implementation like MetalLB.See Requirements for the full port and resource sizing reference.
kubelb.enableGatewayAPI to true in values.yaml. Without the CRDs, KubeLB Manager cannot start.kubelb namespace for KubeLB Manager.imagePullSecrets in that namespace so the chart can pull Enterprise Edition images.A minimal values.yaml looks like this:
imagePullSecrets:
- name: <imagePullSecretName>
helm pull oci://quay.io/kubermatic/helm-charts/kubelb-manager-ee --version=v1.4.3 --untardir "." --untar
## Apply CRDs
kubectl apply -f kubelb-manager-ee/crds/
## Create and update values.yaml with the required values.
helm upgrade --install kubelb-manager kubelb-manager-ee --namespace kubelb -f kubelb-manager-ee/values.yaml --create-namespace
Helm applies a chart’s crds/ directory only on helm install and silently skips it on helm upgrade. This applies to the addon subcharts too, so the Gateway API, Envoy Gateway and External DNS CRDs are never updated by Helm. Re-apply the CRDs on every upgrade — see Upgrading KubeLB.
| Key | Type | Default | Description |
|---|---|---|---|
| affinity | object | {} | |
| autoscaling.enabled | bool | false | |
| autoscaling.maxReplicas | int | 10 | |
| autoscaling.minReplicas | int | 1 | |
| autoscaling.targetCPUUtilizationPercentage | int | 80 | |
| autoscaling.targetMemoryUtilizationPercentage | int | 80 | |
| cert-manager.enabled | bool | false | Enable cert-manager. |
| external-dns.enabled | bool | false | Enable External-DNS. |
| fullnameOverride | string | "" | |
| grafana.dashboards.annotations | object | {} | Additional annotations for dashboard ConfigMaps |
| grafana.dashboards.enabled | bool | false | Requires grafana to be deployed with sidecar.dashboards.enabled=true. For more info: https://github.com/grafana/helm-charts/tree/grafana-10.5.13/charts/grafana#:~:text=%5B%5D-,sidecar.dashboards.enabled,-Enables%20the%20cluster |
| image.pullPolicy | string | "IfNotPresent" | |
| image.repository | string | "quay.io/kubermatic/kubelb-manager-ee" | |
| image.tag | string | "v1.3.9" | |
| imagePullSecrets[0].name | string | "kubermatic-quay.io" | |
| kkpintegration.rbac | bool | false | Create RBAC for KKP integration. |
| kubeRbacProxy.image.pullPolicy | string | "IfNotPresent" | |
| kubeRbacProxy.image.repository | string | "quay.io/brancz/kube-rbac-proxy" | |
| kubeRbacProxy.image.tag | string | "v0.20.1" | |
| kubelb.debug | bool | true | |
| kubelb.disableEnvoyGatewayFeatures | bool | false | disableEnvoyGatewayFeatures disables Envoy Gateway support for BackendTrafficPolicy and ClientTrafficPolicy. Use this if you’re using a Gateway API implementation other than Envoy Gateway. |
| kubelb.enableGatewayAPI | bool | false | enableGatewayAPI specifies whether to enable the Gateway API and Gateway Controllers. By default Gateway API is disabled since without Gateway APIs installed the controller cannot start. |
| kubelb.enableLeaderElection | bool | true | |
| kubelb.enableWAF | bool | false | [Beta feature] Enables Web Application Firewall policy validation and reconciliation. WAF is disabled by default. |
| kubelb.envoyProxy.affinity | object | {} | |
| kubelb.envoyProxy.gracefulShutdown.disabled | bool | false | Disable graceful shutdown (default: false) |
| kubelb.envoyProxy.nodeSelector | object | {} | |
| kubelb.envoyProxy.replicas | int | 2 | The number of replicas for the Envoy Proxy deployment. |
| kubelb.envoyProxy.resources | object | {} | |
| kubelb.envoyProxy.singlePodPerNode | bool | true | Deploy single pod per node. |
| kubelb.envoyProxy.tolerations | list | [] | |
| kubelb.envoyProxy.topology | string | "shared" | Topology defines the deployment topology for Envoy Proxy. Valid values are: shared and global. |
| kubelb.envoyProxy.useDaemonset | bool | false | Use DaemonSet for Envoy Proxy deployment instead of Deployment. |
| kubelb.logLevel | string | "info" | To configure the verbosity of logging. Can be one of ‘debug’, ‘info’, ’error’, ‘panic’ or any integer value > 0 which corresponds to custom debug levels of increasing verbosity. |
| kubelb.propagateAllAnnotations | bool | false | Propagate all annotations from the LB resource to the LB service. |
| kubelb.propagatedAnnotations | object | {} | Allowed annotations that will be propagated from the LB resource to the LB service. |
| kubelb.skipConfigGeneration | bool | false | Set to true to skip the generation of the Config CR. Useful when the config CR needs to be managed manually. |
| kubelb.tunnel.connectionManager.affinity | object | {} | |
| kubelb.tunnel.connectionManager.healthCheck.enabled | bool | true | |
| kubelb.tunnel.connectionManager.healthCheck.livenessInitialDelay | int | 30 | |
| kubelb.tunnel.connectionManager.healthCheck.readinessInitialDelay | int | 10 | |
| kubelb.tunnel.connectionManager.httpAddr | string | ":8080" | Server addresses |
| kubelb.tunnel.connectionManager.httpRoute.annotations | object | {"cert-manager.io/cluster-issuer":"letsencrypt-prod","external-dns.alpha.kubernetes.io/hostname":"connection-manager.${DOMAIN}"} | Annotations for HTTPRoute |
| kubelb.tunnel.connectionManager.httpRoute.domain | string | "connection-manager.${DOMAIN}" | Domain for the HTTPRoute NOTE: Replace ${DOMAIN} with your domain name. |
| kubelb.tunnel.connectionManager.httpRoute.enabled | bool | false | |
| kubelb.tunnel.connectionManager.httpRoute.gatewayName | string | "gateway" | Gateway name to attach to |
| kubelb.tunnel.connectionManager.httpRoute.gatewayNamespace | string | "" | Gateway namespace |
| kubelb.tunnel.connectionManager.image | object | {"pullPolicy":"IfNotPresent","repository":"quay.io/kubermatic/kubelb-connection-manager-ee","tag":""} | Connection manager image configuration |
| kubelb.tunnel.connectionManager.ingress | object | {"annotations":{"cert-manager.io/cluster-issuer":"letsencrypt-prod","external-dns.alpha.kubernetes.io/hostname":"connection-manager.${DOMAIN}","nginx.ingress.kubernetes.io/backend-protocol":"HTTP","nginx.ingress.kubernetes.io/proxy-read-timeout":"3600","nginx.ingress.kubernetes.io/proxy-send-timeout":"3600"},"className":"nginx","enabled":false,"hosts":[{"host":"connection-manager.${DOMAIN}","paths":[{"path":"/tunnel","pathType":"Prefix"},{"path":"/health","pathType":"Prefix"}]}],"tls":[{"hosts":["connection-manager.${DOMAIN}"],"secretName":"connection-manager-tls"}]} | Ingress configuration for external HTTP/2 access |
| kubelb.tunnel.connectionManager.nodeSelector | object | {} | |
| kubelb.tunnel.connectionManager.podAnnotations | object | {} | Pod configuration |
| kubelb.tunnel.connectionManager.podLabels | object | {} | |
| kubelb.tunnel.connectionManager.podSecurityContext.fsGroup | int | 65534 | |
| kubelb.tunnel.connectionManager.podSecurityContext.runAsNonRoot | bool | true | |
| kubelb.tunnel.connectionManager.podSecurityContext.runAsUser | int | 65534 | |
| kubelb.tunnel.connectionManager.replicaCount | int | 1 | Number of connection manager replicas |
| kubelb.tunnel.connectionManager.requestTimeout | string | "30s" | |
| kubelb.tunnel.connectionManager.resources | object | {"limits":{"cpu":"500m","memory":"256Mi"},"requests":{"cpu":"250m","memory":"128Mi"}} | Resource limits |
| kubelb.tunnel.connectionManager.securityContext | object | {"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"runAsUser":65534} | Security context |
| kubelb.tunnel.connectionManager.service | object | {"httpPort":8080,"type":"ClusterIP"} | Service configuration |
| kubelb.tunnel.connectionManager.tolerations | list | [] | |
| kubelb.tunnel.enabled | bool | false | Enable tunnel functionality |
| metrics.port | int | 9443 | Port where the manager exposes metrics (includes both manager and envoycp metrics) |
| nameOverride | string | "" | |
| nodeSelector | object | {} | |
| podAnnotations | object | {} | |
| podLabels | object | {} | |
| podSecurityContext.runAsNonRoot | bool | true | |
| podSecurityContext.seccompProfile.type | string | "RuntimeDefault" | |
| priorityClassName | string | "" | PriorityClassName for the manager pod (e.g., “system-cluster-critical”) |
| rbac.allowLeaderElectionRole | bool | true | |
| rbac.allowMetricsReaderRole | bool | true | |
| rbac.allowProxyRole | bool | true | |
| rbac.enabled | bool | true | |
| replicaCount | int | 1 | |
| resources.limits.cpu | string | "500m" | |
| resources.limits.memory | string | "512Mi" | |
| resources.requests.cpu | string | "100m" | |
| resources.requests.memory | string | "128Mi" | |
| securityContext.allowPrivilegeEscalation | bool | false | |
| securityContext.capabilities.drop[0] | string | "ALL" | |
| securityContext.runAsUser | int | 65532 | |
| service.port | int | 8001 | |
| service.protocol | string | "TCP" | |
| service.type | string | "ClusterIP" | |
| serviceAccount.annotations | object | {} | |
| serviceAccount.create | bool | true | |
| serviceAccount.name | string | "" | |
| serviceMonitor.enabled | bool | false | |
| tolerations | list | [] |
helm pull oci://quay.io/kubermatic/helm-charts/kubelb-manager --version=v1.4.3 --untardir "." --untar
## Apply CRDs
kubectl apply -f kubelb-manager/crds/
## Create and update values.yaml with the required values.
helm upgrade --install kubelb-manager kubelb-manager --namespace kubelb -f kubelb-manager/values.yaml --create-namespace
Helm applies a chart’s crds/ directory only on helm install and silently skips it on helm upgrade. This applies to the addon subcharts too, so the Gateway API, Envoy Gateway and External DNS CRDs are never updated by Helm. Re-apply the CRDs on every upgrade — see Upgrading KubeLB.
| Key | Type | Default | Description |
|---|---|---|---|
| affinity | object | {} | |
| autoscaling.enabled | bool | false | |
| autoscaling.maxReplicas | int | 10 | |
| autoscaling.minReplicas | int | 1 | |
| autoscaling.targetCPUUtilizationPercentage | int | 80 | |
| autoscaling.targetMemoryUtilizationPercentage | int | 80 | |
| fullnameOverride | string | "" | |
| grafana.dashboards.annotations | object | {} | Additional annotations for dashboard ConfigMaps |
| grafana.dashboards.enabled | bool | false | Requires grafana to be deployed with sidecar.dashboards.enabled=true. For more info: https://github.com/grafana/helm-charts/tree/grafana-10.5.13/charts/grafana#:~:text=%5B%5D-,sidecar.dashboards.enabled,-Enables%20the%20cluster |
| image.pullPolicy | string | "IfNotPresent" | |
| image.repository | string | "quay.io/kubermatic/kubelb-manager" | |
| image.tag | string | "v1.3.9" | |
| imagePullSecrets | list | [] | |
| kkpintegration.rbac | bool | false | Create RBAC for KKP integration. |
| kubeRbacProxy.image.pullPolicy | string | "IfNotPresent" | |
| kubeRbacProxy.image.repository | string | "quay.io/brancz/kube-rbac-proxy" | |
| kubeRbacProxy.image.tag | string | "v0.20.1" | |
| kubelb.debug | bool | true | |
| kubelb.enableGatewayAPI | bool | false | enableGatewayAPI specifies whether to enable the Gateway API and Gateway Controllers. By default Gateway API is disabled since without Gateway APIs installed the controller cannot start. |
| kubelb.enableLeaderElection | bool | true | |
| kubelb.envoyProxy.affinity | object | {} | |
| kubelb.envoyProxy.gracefulShutdown.disabled | bool | false | Disable graceful shutdown (default: false) |
| kubelb.envoyProxy.nodeSelector | object | {} | |
| kubelb.envoyProxy.replicas | int | 2 | The number of replicas for the Envoy Proxy deployment. |
| kubelb.envoyProxy.resources | object | {} | |
| kubelb.envoyProxy.singlePodPerNode | bool | true | Deploy single pod per node. |
| kubelb.envoyProxy.tolerations | list | [] | |
| kubelb.envoyProxy.topology | string | "shared" | Topology defines the deployment topology for Envoy Proxy. Valid values are: shared and global. |
| kubelb.envoyProxy.useDaemonset | bool | false | Use DaemonSet for Envoy Proxy deployment instead of Deployment. |
| kubelb.logLevel | string | "info" | To configure the verbosity of logging. Can be one of ‘debug’, ‘info’, ’error’, ‘panic’ or any integer value > 0 which corresponds to custom debug levels of increasing verbosity. |
| kubelb.propagateAllAnnotations | bool | false | Propagate all annotations from the LB resource to the LB service. |
| kubelb.propagatedAnnotations | object | {} | Allowed annotations that will be propagated from the LB resource to the LB service. |
| kubelb.skipConfigGeneration | bool | false | Set to true to skip the generation of the Config CR. Useful when the config CR needs to be managed manually. |
| metrics.port | int | 9443 | Port where the manager exposes metrics (includes both manager and envoycp metrics) |
| nameOverride | string | "" | |
| nodeSelector | object | {} | |
| podAnnotations | object | {} | |
| podLabels | object | {} | |
| podSecurityContext.runAsNonRoot | bool | true | |
| podSecurityContext.seccompProfile.type | string | "RuntimeDefault" | |
| rbac.allowLeaderElectionRole | bool | true | |
| rbac.allowMetricsReaderRole | bool | true | |
| rbac.allowProxyRole | bool | true | |
| rbac.enabled | bool | true | |
| replicaCount | int | 1 | |
| resources.limits.cpu | string | "500m" | |
| resources.limits.memory | string | "512Mi" | |
| resources.requests.cpu | string | "100m" | |
| resources.requests.memory | string | "128Mi" | |
| securityContext.allowPrivilegeEscalation | bool | false | |
| securityContext.capabilities.drop[0] | string | "ALL" | |
| securityContext.runAsUser | int | 65532 | |
| service.port | int | 8001 | |
| service.protocol | string | "TCP" | |
| service.type | string | "ClusterIP" | |
| serviceAccount.annotations | object | {} | |
| serviceAccount.create | bool | true | |
| serviceAccount.name | string | "" | |
| serviceMonitor.enabled | bool | false | |
| tolerations | list | [] |
Check that the manager is running:
kubectl get pods -n kubelb
NAME READY STATUS RESTARTS AGE
kubelb-manager-6d95d7f45d-xz2lp 2/2 Running 0 1m
The kubelb-manager pod must be in Running state. Envoy proxy pods appear in the tenant namespaces later, once tenants are registered and load balancers are created.
The examples and tools shared below are for demonstration purposes, you can use any other tools or configurations as per your requirements.
The management cluster acts as the data plane and central control plane for all your load balancing configurations. All the components required for Layer 4 and Layer 7 load balancing, AI Gateways, MCP Gateways, Agent2Agent Gateways, API Gateways etc. are deployed here. The management cluster is multi-tenant and can serve a whole fleet of clusters.
KubeLB has introduced an addons chart to simplify the installation of the required components for the management cluster. The chart is already part of the KubeLB manager chart and can be installed by setting the kubelb-addons.enabled to true in the values.yaml.
kubelb:
enableGatewayAPI: true
debug: true
## Addon configuration
kubelb-addons:
enabled: true
gatewayClass:
create: true
# Ingress Nginx
ingress-nginx:
enabled: false
controller:
service:
externalTrafficPolicy: Local
# Envoy Gateway
envoy-gateway:
enabled: true
# Cert Manager
cert-manager:
enabled: true
crds:
enabled: true
config:
apiVersion: controller.config.cert-manager.io/v1alpha1
kind: ControllerConfiguration
enableGatewayAPI: true
# External DNS
external-dns:
domainFilters:
- example.com
extraVolumes:
- name: credentials
secret:
secretName: route53-credentials
extraVolumeMounts:
- name: credentials
mountPath: /.aws
readOnly: true
env:
- name: AWS_SHARED_CREDENTIALS_FILE
value: /.aws/credentials
txtOwnerId: kubelb-example-aws
registry: txt
provider: aws
policy: sync
sources:
- service
- ingress
- gateway-httproute
- gateway-grpcroute
- gateway-tlsroute
- gateway-tcproute
- gateway-udproute
## AI, MCP and Agent2Agent Gateways Integration
agentgateway-crds:
enabled: true
agentgateway:
enabled: true
The kubelb-addons chart honors global.imageRegistry and global.imagePullSecrets and propagates both to every addon subchart (ingress-nginx, envoy-gateway, cert-manager, external-dns, metallb, agentgateway). Set them on the top-level install to route all addon images through a private mirror and attach a pull secret, without editing each subchart’s own values. See the Air-Gap Installation guide for the full end-to-end mirroring workflow; the same flags apply to non-airgap setups pulling from a company registry.
Envoy rejects requests whose combined client headers exceed 60 KiB with a 431 Request Header Fields Too Large response. Workloads that carry large Authorization/JWT tokens, long cookies, or many tracing headers can hit this limit.
An L7 request passes through two Envoy hops: the Envoy Gateway edge proxy, and then KubeLB’s own managed Envoy. Both must allow the larger headers, otherwise the request is rejected at whichever hop still enforces the 60 KiB default.
KubeLB’s managed Envoy limits are set on the Config resource under spec.envoyProxy.headerLimits:
apiVersion: kubelb.k8c.io/v1alpha1
kind: Config
metadata:
name: default
namespace: kubelb
spec:
envoyProxy:
headerLimits:
# Max request header block size in KiB. Range (0, 8192]. Defaults to 8192.
maxRequestHeadersKb: 8192
# Max number of request headers. Defaults to 4096.
maxRequestHeadersCount: 4096
# Max upstream response header block size in KiB. Range (0, 8192]. Defaults to 8192.
maxResponseHeadersKb: 8192
All three fields default to Envoy’s maximum, so out of the box KubeLB’s managed Envoy never rejects headers the edge already accepted. Lower them if you want the managed Envoy to enforce a smaller cap.
On the Gateway API path the effective ceiling is therefore Envoy Gateway’s stock limits of 100 request headers / 60 KiB, not KubeLB’s: oversized requests are rejected with 431 at the Envoy Gateway hop before KubeLB’s configured limits apply, unless a ClientTrafficPolicy raising them is attached to the Gateway.
The Envoy Gateway edge is not managed by KubeLB. Raise its limit yourself on the EnvoyProxy resource that your GatewayClass references, for example with a bootstrap runtime layer:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: kubelb-proxy-config
namespace: kubelb
spec:
bootstrap:
type: Merge
value: |
layered_runtime:
layers:
- name: header-limits
static_layer:
envoy.reloadable_features.max_request_headers_size_kb: 96
Refer to Layer 4 Load Balancing Setup for more details.
For Application layer load balancing, kubeLB supports both Ingress and Gateway API resources.
Our default recommendation is to use Gateway API and use Envoy Gateway as the Gateway API implementation. Most of the upcoming and current features that KubeLB will focus on will prioritize Gateway API instead of Ingress. With Envoy Gateway being the product that we’ll actively support, test, and base our features on.
While KubeLB supports integration with any Ingress or Gateway API implementation, the only limitation is that we only support native Kubernetes APIs i.e. Ingress and Gateway APIs. Provider specific APIs are not supported by KubeLB and will be completely ignored. Also, we are only testing KubeLB with Envoy Gateway and Nginx Ingress, we can’t guarantee the compatibility with other Gateway API or Ingress implementations.
Refer to Ingress Setup for more details.
Refer to Gateway API Setup for more details.
Refer to Certificate Management Setup for more details.
Refer to DNS Management Setup for more details.