linode-cloud-controller-manager

LoadBalancer Services Configuration

Overview

The CCM supports two types of LoadBalancer implementations:

  1. Linode NodeBalancers (default)
  2. BGP-based IP sharing

For implementation examples, see Basic Service Examples.

NodeBalancer Implementation

When using NodeBalancers, the CCM automatically:

  1. Creates and configures a NodeBalancer
  2. Sets up backend nodes
  3. Manages health checks
  4. Handles SSL/TLS configuration

For more details, see Linode NodeBalancer Documentation.

IPv6 Support

NodeBalancers support both IPv4 and IPv6 ingress addresses. By default, the CCM uses only IPv4 address for LoadBalancer services.

You can enable IPv6 addresses globally for all services by setting the enable-ipv6-for-loadbalancers flag:

spec:
  template:
    spec:
      containers:
        - name: ccm-linode
          args:
            - --enable-ipv6-for-loadbalancers=true

Alternatively, you can enable IPv6 addresses for individual services using the annotation:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-ingress: "true"

When IPv6 is enabled (either globally or per-service), both IPv4 and IPv6 addresses will be included in the service's LoadBalancer status.

IPv6 Backend Support

IPv6 frontends and IPv6 backends are configured independently. Frontend IPv6 controls what the Service publishes in status.loadBalancer.ingress, while backend IPv6 controls which node addresses a NodeBalancer targets.

IPv6 backends require a dual-stack workload cluster. In practice, the cluster networking stack must support IPv6 NodePort traffic, and the Service itself should be created as dual-stack. A single-stack IPv4 LoadBalancer Service can still be annotated for IPv6 backends, but the NodeBalancer health checks and traffic path may fail because the backend NodePort is not exposed over IPv6.

You can enable IPv6 backends globally for NodeBalancer services:

spec:
  template:
    spec:
      containers:
        - name: ccm-linode
          args:
            - --enable-ipv6-for-nodebalancer-backends=true

Or per service:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-backends: "true"

When IPv6 backends are enabled:

Recommended Service configuration for IPv6 backends:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-backends: "true"
spec:
  type: LoadBalancer
  ipFamilyPolicy: RequireDualStack
  ipFamilies:
    - IPv4
    - IPv6
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: my-app

If your cluster does not provide IPv6-capable NodePort routing, the NodeBalancer may still be created with IPv6 backend addresses, but the backends will not become healthy. Likewise, if your cluster is using VPC backends but the nodes do not also have public IPv6 endpoints, IPv6 backend reconciliation will fail because CCM does not currently program VPC IPv6 backend addresses.

Basic Configuration

Create a LoadBalancer service:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: my-app

See Advanced Configuration Examples for more complex setups.

NodeBalancer Settings

Protocol Configuration

Available protocols:

Set the default protocol:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-default-protocol: "http"

See Service Annotations for all protocol options.

Health Checks

Configure health checks using annotations:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-check-type: "http"
    service.beta.kubernetes.io/linode-loadbalancer-check-path: "/healthz"
    service.beta.kubernetes.io/linode-loadbalancer-check-interval: "5"
    service.beta.kubernetes.io/linode-loadbalancer-check-timeout: "3"
    service.beta.kubernetes.io/linode-loadbalancer-check-attempts: "2"

Available check types:

For more details, see Health Check Configuration.

SSL/TLS Configuration

  1. Create a TLS secret:
apiVersion: v1
kind: Secret
metadata:
  name: my-tls-secret
type: kubernetes.io/tls
data:
  tls.crt: <base64-encoded-cert>
  tls.key: <base64-encoded-key>
  1. Reference in service annotation:
metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-port-443: |
      {
        "protocol": "https",
        "tls-secret-name": "my-tls-secret"
      }

Connection Throttling

Limit connections from the same client IP:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-throttle: "5"

Proxy Protocol

Enable proxy protocol for client IP preservation:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-default-proxy-protocol: "v2"

BGP-based IP Sharing Implementation

BGP-based IP sharing provides a more cost-effective solution for multiple LoadBalancer services. For detailed setup instructions, see Cilium BGP Documentation.

Prerequisites

Configuration

  1. Enable BGP in CCM deployment:
args:
  - --load-balancer-type=cilium-bgp
  - --bgp-node-selector=cilium-bgp-peering=true
  - --ip-holder-suffix=mycluster
  1. Label nodes that should participate in BGP peering:
kubectl label node my-node cilium-bgp-peering=true
  1. Create LoadBalancer services as normal - the CCM will automatically use BGP-based IP sharing instead of creating NodeBalancers.

Environment Variables

For more details, see Environment Variables.

Configuring NodeBalancers directly with VPC

NodeBalancers can be configured to have VPC specific ips configured as backend nodes. It requires:

  1. VPC with a subnet and Linodes in VPC
  2. Each NodeBalancer created within that VPC needs a free /30 or bigger subnet from the subnet to which Linodes are connected

Specify NodeBalancer backend ipv4 range when creating service:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-backend-ipv4-range: "10.100.0.0/30"

By default, CCM uses first VPC and Subnet name configured with it to attach NodeBalancers to that VPC subnet. To overwrite those, use:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-backend-ipv4-range: "10.100.0.4/30"
    service.beta.kubernetes.io/linode-loadbalancer-backend-vpc-name: "vpc1"
    service.beta.kubernetes.io/linode-loadbalancer-backend-subnet-name: "subnet1"

Configuring NodeBalancer frontend with VPC

NodeBalancers can optionally be configured with a VPC-based frontend address.

Frontend VPC configuration supports the following annotations:

  1. Choose the frontend subnet:

    • service.beta.kubernetes.io/linode-loadbalancer-frontend-subnet-id (preferred)
    • OR service.beta.kubernetes.io/linode-loadbalancer-frontend-vpc-name and service.beta.kubernetes.io/linode-loadbalancer-frontend-subnet-name
  2. Optionally constrain the frontend address assignment within the subnet:

    • service.beta.kubernetes.io/linode-loadbalancer-frontend-ipv4-range (CIDR)
    • service.beta.kubernetes.io/linode-loadbalancer-frontend-ipv6-range (CIDR)

Order of precedence:

Example:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-frontend-subnet-id: "169341"
    # Optional:
    # service.beta.kubernetes.io/linode-loadbalancer-frontend-ipv4-range: "10.0.0.0/24"
    # service.beta.kubernetes.io/linode-loadbalancer-frontend-ipv6-range: "2001:db8::/64"

For a complete working example, see examples/vpc-frontend-example.yaml.

If CCM is started with --nodebalancer-backend-ipv4-subnet flag, then it will not allow provisioning of nodebalancer unless subnet specified in service annotation lie within the subnet specified using the flag. This is to prevent accidental overlap between nodebalancer backend ips and pod CIDRs.

Advanced Configuration

Using Existing NodeBalancers

Specify an existing NodeBalancer:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-nodebalancer-id: "12345"

Reserved IPv4 addresses

Create an new NodeBalancer with an existing Reserved IPv4 Address:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-reserved-ipv4: "100.100.100.100"

The annotation must be present when the Service is created in order to take effect.

NodeBalancer Preservation

Prevent NodeBalancer deletion when service is deleted:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-preserve: "true"

Port Configuration

Configure individual ports:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-port-443: |
      {
        "protocol": "https",
        "tls-secret-name": "my-tls-secret",
        "proxy-protocol": "v2"
      }

Tags

Add tags to NodeBalancer:

metadata:
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-tags: "production,web-tier"

Excluding nodes from nodebalancer

Add a label to the node object to exclude

apiVersion: v1
kind: Node
metadata:
  name: node-to-exclude
  labels:
    node.kubernetes.io/exclude-from-external-load-balancers: "true"