See Requirements for the full port and resource sizing reference.
Create a kubelb namespace for KubeLB CCM.
KubeLB CCM expects a Secret named kubelb-cluster by default. Its kubelb data key must contain the kubeconfig for the management cluster.
# Replace with the tenant cluster kubeconfig path
TENANT_KUBECONFIG=~/.kube/<tenant-cluster>
# Replace with the tenant name
TENANT_NAME=tenant-shroud
KUBELB_KUBECONFIG_B64=$(kubectl get secret kubelb-ccm-kubeconfig --namespace "$TENANT_NAME" --template='{{ .data.kubelb }}')
# Switch to the tenant cluster.
export KUBECONFIG="$TENANT_KUBECONFIG"
kubectl --namespace kubelb create secret generic kubelb-cluster \
--from-literal=kubelb="$(printf '%s' "$KUBELB_KUBECONFIG_B64" | base64 -d)"
Override the Secret name with .Values.kubelb.clusterSecretName if required. Otherwise, the Secret is named kubelb-cluster and looks like this:
kubectl get secret kubelb-cluster --namespace kubelb -o yaml
apiVersion: v1
data:
kubelb: xxx-base64-encoded-xxx
kind: Secret
metadata:
name: kubelb-cluster
namespace: kubelb
type: Opaque
Set tenantName in values.yaml to the tenant’s unique identifier. The management cluster stores tenant namespaces with a tenant- prefix; for example, my-tenant becomes tenant-my-tenant. KubeLB accepts the name with or without this prefix.
At this point a minimal values.yaml should look like this:
kubelb:
clusterSecretName: kubelb-cluster
tenantName: <unique-identifier-for-tenant>
Private clusters: If the tenant nodes do not have external IP addresses, set kubelb.nodeAddressType to InternalIP.
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node-x Ready control-plane 208d v1.29.9 10.66.99.222 <none> Ubuntu 5.15.0-121-generic containerd://1.6.33
Adjust values.yaml:
kubelb:
# -- Address type to use for routing traffic to node ports. Values are ExternalIP, InternalIP, or Hostname.
nodeAddressType: InternalIP
To enable Gateway API support, set both fields below in values.yaml. KubeLB CCM cannot start with Gateway API enabled unless the CRDs are installed.
kubelb:
enableGatewayAPI: true
installGatewayAPICRDs: true
At this point a minimal values.yaml should look like this:
imagePullSecrets:
- name: <imagePullSecretName>
kubelb:
clusterSecretName: kubelb-cluster
tenantName: <unique-identifier-for-tenant>
helm pull oci://quay.io/kubermatic/helm-charts/kubelb-ccm-ee --version=v1.5.0 --untardir "." --untar
## Apply CRDs
kubectl apply -f kubelb-ccm-ee/crds/
## Create and update values.yaml with the required values.
helm upgrade --install kubelb-ccm kubelb-ccm-ee --namespace kubelb -f kubelb-ccm-ee/values.yaml --create-namespace
Helm applies a chart’s crds/ directory only on helm install and silently skips it on helm upgrade. 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 | |
| extraVolumeMounts | list | [] | |
| extraVolumes | list | [] | |
| fullnameOverride | string | "" | |
| global.imagePullSecrets | list | [] | Global image pull secrets propagated to all pod specs. Used for private mirror registries. |
| global.imageRegistry | string | "" | Override the registry for all images (prefix replacement). Example: “registry.customer.internal” rewrites quay.io/foo/bar to registry.customer.internal/foo/bar |
| 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-ccm-ee" | |
| image.tag | string | "v1.5.0" | |
| imagePullSecrets[0].name | string | "kubermatic-quay.io" | |
| kubeRbacProxy.image.pullPolicy | string | "IfNotPresent" | |
| kubeRbacProxy.image.repository | string | "quay.io/brancz/kube-rbac-proxy" | |
| kubeRbacProxy.image.tag | string | "v0.20.1" | |
| kubelb.clusterSecretName | string | "kubelb-cluster" | Name of the secret that contains kubeconfig for the loadbalancer cluster |
| kubelb.disableBackendTrafficPolicyController | bool | false | disableBackendTrafficPolicyController specifies whether to disable the BackendTrafficPolicy Controller. |
| kubelb.disableClientTrafficPolicyController | bool | false | disableClientTrafficPolicyController specifies whether to disable the ClientTrafficPolicy Controller. |
| kubelb.disableGRPCRouteController | bool | false | disableGRPCRouteController specifies whether to disable the GRPCRoute Controller. |
| kubelb.disableGatewayController | bool | false | disableGatewayController specifies whether to disable the Gateway Controller. |
| kubelb.disableHTTPRouteController | bool | false | disableHTTPRouteController specifies whether to disable the HTTPRoute Controller. |
| kubelb.disableIngressController | bool | false | disableIngressController specifies whether to disable the Ingress Controller. |
| kubelb.disableTCPRouteController | bool | false | disableTCPRouteController specifies whether to disable the TCPRoute Controller. |
| kubelb.disableTLSRouteController | bool | false | disableTLSRouteController specifies whether to disable the TLSRoute Controller. |
| kubelb.disableUDPRouteController | bool | false | disableUDPRouteController specifies whether to disable the UDPRoute Controller. |
| 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 | Enable the leader election. |
| kubelb.enableSecretSynchronizer | bool | false | Enable to automatically convert Secrets labelled with kubelb.k8c.io/managed-by: kubelb to Sync Secrets. This is used to sync secrets from tenants to the LB cluster in a controlled and secure way. |
| kubelb.gatewayAPICRDsChannel | string | "experimental" | gatewayAPICRDsChannel specifies the channel for the Gateway API CRDs. Options are standard and experimental. |
| kubelb.gatewayClasses | list | ["kubelb"] | gatewayClasses specifies tenant GatewayClass names watched when useGatewayClass is true. |
| kubelb.ingressConversion.copyTLSSecrets | bool | true | copyTLSSecrets copies TLS secrets from Ingress namespace to Gateway namespace for cross-namespace certificate references |
| kubelb.ingressConversion.disableEnvoyGatewayFeatures | bool | false | disableEnvoyGatewayFeatures disables creation of Envoy Gateway policies (SecurityPolicy, BackendTrafficPolicy) |
| kubelb.ingressConversion.domainReplace | string | "" | domainReplace is the domain suffix to replace in hostnames |
| kubelb.ingressConversion.domainSuffix | string | "" | domainSuffix is the replacement domain suffix for hostnames |
| kubelb.ingressConversion.enabled | bool | false | enabled enables automatic Ingress to HTTPRoute conversion |
| kubelb.ingressConversion.gatewayAnnotations | string | "" | gatewayAnnotations are annotations to add to created Gateway (comma-separated key=value pairs) Example: “cert-manager.io/cluster-issuer=letsencrypt,external-dns.alpha.kubernetes.io/target=lb.example.com” |
| kubelb.ingressConversion.gatewayClass | string | "kubelb" | gatewayClass is the GatewayClass name for created Gateway |
| kubelb.ingressConversion.gatewayName | string | "kubelb" | gatewayName is the name of the Gateway for converted HTTPRoutes |
| kubelb.ingressConversion.gatewayNamespace | string | "kubelb" | gatewayNamespace is the namespace for the shared Gateway (required) |
| kubelb.ingressConversion.ingressClass | string | "" | ingressClass filters Ingresses to convert (empty = convert all) |
| kubelb.ingressConversion.propagateExternalDnsAnnotations | bool | true | propagateExternalDnsAnnotations propagates external-dns annotations to Gateway/HTTPRoute |
| kubelb.ingressConversion.standaloneMode | bool | false | standaloneMode runs as standalone converter, disabling all other controllers |
| kubelb.installGatewayAPICRDs | bool | false | installGatewayAPICRDs Installs and manages the Gateway API CRDs using gateway crd controller. |
| 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.maxNodeAddressCount | int | 0 | Maximum number of node addresses to forward to the LB cluster. When set, addresses are selected with topology-aware round-robin spread across zones (topology.kubernetes.io/zone). 0 means no limit. |
| kubelb.nodeAddressLabelSelector | string | "" | Only use nodes matching this label selector as endpoint addresses (e.g. kubelb.k8c.io/endpoint=true). |
| kubelb.nodeAddressType | string | "ExternalIP" | Address type to use for routing traffic to node ports. Values are ExternalIP, InternalIP. |
| kubelb.tenantName | string | nil | Name of the tenant, must be unique against a load balancer cluster. |
| kubelb.tenantProxy.envoy.image.repository | string | "docker.io/envoyproxy/envoy" | Envoy image repository for the mTLS tenant proxy DaemonSet. |
| kubelb.tenantProxy.envoy.image.tag | string | "distroless-v1.36.4" | Envoy image tag for the mTLS tenant proxy DaemonSet. |
| kubelb.tenantProxy.serviceAccount.annotations | object | {} | Annotations to add to the mTLS tenant proxy ServiceAccount. |
| kubelb.tenantProxy.serviceAccount.create | bool | true | Create a dedicated ServiceAccount for the mTLS tenant proxy xDS writer sidecar. |
| kubelb.tenantProxy.serviceAccount.name | string | "" | Name of the mTLS tenant proxy ServiceAccount. If not set and create is true, a name is generated. |
| kubelb.tenantProxy.serviceType | string | "" | Override the mTLS tenant proxy Service type (NodePort or LoadBalancer). Empty follows the management cluster configuration. |
| kubelb.tenantProxy.shutdownManager.image.repository | string | "docker.io/envoyproxy/gateway" | Shutdown-manager image repository for the mTLS tenant proxy DaemonSet. |
| kubelb.tenantProxy.shutdownManager.image.tag | string | "v1.8.3" | Shutdown-manager image tag for the mTLS tenant proxy DaemonSet. Must match images.DefaultShutdownManagerImage — this value is what actually reaches the DaemonSet, and only tags present in docs/images/images.txt exist in an air-gap mirror. |
| kubelb.tenantProxy.staticAddresses | list | [] | Static IPs or hostnames published as the mTLS tenant proxy dial target instead of node or load balancer addresses. For proxies fronted by an appliance, NAT, or a user-managed DNS record. |
| kubelb.tenantProxy.staticPort | int | 15443 | Port dialed together with staticAddresses. |
| kubelb.useGatewayClass | bool | true | useGatewayClass specifies whether to target resources with kubelb gateway class or all resources. |
| kubelb.useIngressClass | bool | true | useIngressClass specifies whether to target resources with kubelb ingress class or all resources. |
| kubelb.useLoadBalancerClass | bool | false | useLoadBalancerClass specifies whether to target services of type LoadBalancer with kubelb load balancer class or all services of type LoadBalancer. |
| metrics.port | int | 9445 | Port where the CCM exposes 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 | 8443 | |
| service.protocol | string | "TCP" | |
| service.type | string | "ClusterIP" | |
| serviceAccount.annotations | object | {} | |
| serviceAccount.create | bool | true | |
| serviceAccount.name | string | "" | |
| serviceMonitor.enabled | bool | false | |
| testImage.repository | string | "busybox" | |
| testImage.tag | string | "1.35.0" | |
| tolerations | list | [] |
helm pull oci://quay.io/kubermatic/helm-charts/kubelb-ccm --version=v1.5.0 --untardir "." --untar
## Apply CRDs
kubectl apply -f kubelb-ccm/crds/
## Create and update values.yaml with the required values.
helm upgrade --install kubelb-ccm kubelb-ccm --namespace kubelb -f kubelb-ccm/values.yaml --create-namespace
Helm applies a chart’s crds/ directory only on helm install and silently skips it on helm upgrade. 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 | |
| extraVolumeMounts | list | [] | |
| extraVolumes | list | [] | |
| 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-ccm" | |
| image.tag | string | "v1.5.0" | |
| imagePullSecrets | list | [] | |
| kubeRbacProxy.image.pullPolicy | string | "IfNotPresent" | |
| kubeRbacProxy.image.repository | string | "quay.io/brancz/kube-rbac-proxy" | |
| kubeRbacProxy.image.tag | string | "v0.20.1" | |
| kubelb.clusterSecretName | string | "kubelb-cluster" | Name of the secret that contains kubeconfig for the loadbalancer cluster |
| kubelb.disableGRPCRouteController | bool | false | disableGRPCRouteController specifies whether to disable the GRPCRoute Controller. |
| kubelb.disableGatewayController | bool | false | disableGatewayController specifies whether to disable the Gateway Controller. |
| kubelb.disableHTTPRouteController | bool | false | disableHTTPRouteController specifies whether to disable the HTTPRoute Controller. |
| kubelb.disableIngressController | bool | false | disableIngressController specifies whether to disable the Ingress Controller. |
| 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 | Enable the leader election. |
| kubelb.enableSecretSynchronizer | bool | false | Enable to automatically convert Secrets labelled with kubelb.k8c.io/managed-by: kubelb to Sync Secrets. This is used to sync secrets from tenants to the LB cluster in a controlled and secure way. |
| kubelb.gatewayAPICRDsChannel | string | "standard" | gatewayAPICRDsChannel specifies the channel for the Gateway API CRDs. Options are standard and experimental. |
| kubelb.ingressConversion.copyTLSSecrets | bool | true | copyTLSSecrets copies TLS secrets from Ingress namespace to Gateway namespace for cross-namespace certificate references |
| kubelb.ingressConversion.disableEnvoyGatewayFeatures | bool | false | disableEnvoyGatewayFeatures disables creation of Envoy Gateway policies (SecurityPolicy, BackendTrafficPolicy) |
| kubelb.ingressConversion.domainReplace | string | "" | domainReplace is the domain suffix to replace in hostnames |
| kubelb.ingressConversion.domainSuffix | string | "" | domainSuffix is the replacement domain suffix for hostnames |
| kubelb.ingressConversion.enabled | bool | false | enabled enables automatic Ingress to HTTPRoute conversion |
| kubelb.ingressConversion.gatewayAnnotations | string | "" | gatewayAnnotations are annotations to add to created Gateway (comma-separated key=value pairs) Example: “cert-manager.io/cluster-issuer=letsencrypt,external-dns.alpha.kubernetes.io/target=lb.example.com” |
| kubelb.ingressConversion.gatewayClass | string | "kubelb" | gatewayClass is the GatewayClass name for created Gateway |
| kubelb.ingressConversion.gatewayName | string | "kubelb" | gatewayName is the name of the Gateway for converted HTTPRoutes |
| kubelb.ingressConversion.gatewayNamespace | string | "kubelb" | gatewayNamespace is the namespace for the shared Gateway (required) |
| kubelb.ingressConversion.ingressClass | string | "" | ingressClass filters Ingresses to convert (empty = convert all) |
| kubelb.ingressConversion.propagateExternalDnsAnnotations | bool | true | propagateExternalDnsAnnotations propagates external-dns annotations to Gateway/HTTPRoute |
| kubelb.ingressConversion.standaloneMode | bool | false | standaloneMode runs as standalone converter, disabling all other controllers |
| kubelb.installGatewayAPICRDs | bool | false | installGatewayAPICRDs Installs and manages the Gateway API CRDs using gateway crd controller. |
| 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.nodeAddressType | string | "ExternalIP" | Address type to use for routing traffic to node ports. Values are ExternalIP, InternalIP. |
| kubelb.tenantName | string | nil | Name of the tenant, must be unique against a load balancer cluster. |
| kubelb.useGatewayClass | bool | true | useGatewayClass specifies whether to target resources with kubelb gateway class or all resources. |
| kubelb.useIngressClass | bool | true | useIngressClass specifies whether to target resources with kubelb ingress class or all resources. |
| kubelb.useLoadBalancerClass | bool | false | useLoadBalancerClass specifies whether to target services of type LoadBalancer with kubelb load balancer class or all services of type LoadBalancer. |
| metrics.port | int | 9445 | Port where the CCM exposes 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 | 8443 | |
| 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 CCM is running:
kubectl get pods -n kubelb
NAME READY STATUS RESTARTS AGE
kubelb-ccm-7c9f7d6b8d-4qk2n 2/2 Running 0 1m
The kubelb-ccm pod must be in Running state before load balancer services are reconciled.
Starting from KubeLB v1.2.0, the Gateway API CRDs can be installed using the installGatewayAPICRDs flag.
imagePullSecrets:
- name: <imagePullSecretName>
kubelb:
clusterSecretName: kubelb-cluster
tenantName: <unique-identifier-for-tenant>
# This will install the experimental channel of the Gateway API CRDs
installGatewayAPICRDs: true
enableGatewayAPI: true
For more details: Experimental Install
kubelb:
clusterSecretName: kubelb-cluster
tenantName: <unique-identifier-for-tenant>
# This will install the standard channel of the Gateway API CRDs
installGatewayAPICRDs: true
enableGatewayAPI: true
For more details: Standard Install