Linode Load Balancers require 192.168 subnets in VPC clusters

Summary

The issue arises when provisioning a Linode Load Balancer from a Kubernetes cluster that uses the Linode Cloud Controller Manager (LCCM) on a VPC‑only network. The controller requires node IPs to fall within the 192.168.x.x subnet range, which conflicts with user‑defined VPC subnets such as 10.0.0.0/16. The result is a 400 error telling that node IPs must start with 192.168, and subsequent attempts to force the controller into a VPC‑only context produce a “Nodebalancer is not allowed within a VPC” message. The core missing piece is that Linode Load Balancers cannot be created on custom VPC subnet ranges; they must use the private 192.168 subnet that the LCCM expects.

Root Cause

  • Linode Load Balancer IP validation: LCCM enforces that backend node IPs begin with 192.168.
  • VPC subnet mismatch: User VPC (10.0.0.0/16) does not satisfy this requirement.
  • Helm chart misconfiguration: Overriding VPC and subnet values in the chart does not alter the controller’s hardcoded IP validation.
  • Documentation ambiguity: Official docs imply VPC support but exclude the fact that load balancers still require the 192.168 namespace.

Why This Happens in Real Systems

  • Legacy IP handling: Linode historically used 192.168 internal addresses for nodebalancers; changing that requires a code change in the controller.
  • Mixed networking stacks: Many true‑cloud clusters (AWS, GCP) use custom ranges; this litmus test exposes the mismatch.
  • Operational simplification: By restricting to 192.168, Linode simplifies backend configuration and security rules.

Real-World Impact

  • Services cannot expose external traffic via a LoadBalancer in a VPC‑only setup.
  • DevOps teams waste time troubleshooting API errors that are actually network‑policy violations.
  • Production workloads become unavailable or rely on costly Workload‑load balancer alternatives.

Example or Code (if necessary and relevant)

apiVersion: v1
kind: Service
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/linode-loadbalancer-backend-ipv4-range: "10.0.1.8/30"
    service.beta.kubernetes.io/linode-loadbalancer-backend-vpc-name: "k8s-vpc"
    service.beta.kubernetes.io/linode-loadbalancer-backend-subnet-name: "k8s-nodes"
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: my-app

The above manifest triggers the 400 error because the IP range is not 192.168.

How Senior Engineers Fix It

  • Revert to the default 192.168 subnet: Create a new VPC/Subnet with 192.168.0.0/16 and deploy Linodes into it.
  • Use External Load Balancers: Offload to a cloud‑native load balancer (e.g., a NodePort exposed via a reverse proxy).
  • Patch the Controller: Fork the LCCM source, adjust the IP validation logic, and deploy a custom build.
  • Leverage Cilium’s load‑balancer feature: Replace Linode LB with Cilium‑in‑cluster LB, which is VPC‑agnostic.
  • Document the limitation: Update internal runbooks to highlight the 192.168 requirement.

Why Juniors Miss It

  • Assuming full VPC support from Linode documentation leads to overlooking the 192.168 constraint.
  • Misreading error messages: “Must begin with 192.168” is often mistaken as a generic validation error.
  • Lack of troubleshooting depth: Junior engineers might triage only by changing annotations or Helm values without examining the controller’s validation logic.
  • Ignoring version differences: Newer LCCM releases may still contain legacy checks that older docs hide.

Leave a Comment