Contents

Kubernetes Services - Load Balancer

Website Visitors:

The NodePort Limitation

Consider a four-node cluster hosting front-end applications, such as a voting app and a result app. To expose these via NodePort, Kubernetes allocates a port from the default range (30000-32767) on every node. Even if the application pods reside on only two nodes (e.g., nodes with IPs 70 and 71), the NodePort service creates iptables rules across all nodes. Consequently, a user can access the application via any node IP in the cluster. Traffic entering a node that does not host the pod is proxied by the kube-proxy component to a node that does.

This architecture forces end users to interact with a fragile URL structure: http://<NodeIP>:<NodePort>. In a four-node cluster, users effectively have four potential entry points for each application. This approach has several failures:

  1. Lack of Stability: If a node goes down, that specific URL becomes unavailable. Clients must manually retry another node IP.
  2. Poor Usability: End users require a single, stable DNS name (e.g., votingapp.com), not a list of IP addresses and non-standard port numbers.
  3. IP Management: Node IPs are ephemeral in cloud environments; hardcoding them into user configurations is not viable.

The Manual Load Balancer Approach

One solution involves provisioning a separate virtual machine outside the Kubernetes cluster. An administrator would install a load balancer such as HAProxy or Nginx on this VM. This external load balancer would be configured with a backend pool consisting of all four worker node IPs and the assigned NodePort.

While functional, this approach imposes operational overhead:

  • Provisioning: Requires manual VM creation and lifecycle management.
  • Configuration: The load balancer configuration must be manually updated if nodes are added or removed from the cluster.
  • Health Checks: External monitoring must be configured to detect node failures and remove them from the rotation.

Native Cloud Integration (Service Type: LoadBalancer)

Kubernetes automates this process through the LoadBalancer service type on supported cloud platforms (AWS, Google Cloud, Azure). When a service is defined with type: LoadBalancer, the Kubernetes control plane interacts with the cloud provider’s API.

The workflow executes as follows:

  1. Request: The Kubernetes Controller Manager detects the LoadBalancer type request.
  2. Provisioning: It calls the cloud provider’s API to provision a network load balancer (e.g., an AWS Classic Load Balancer or an Azure Load Balancer).
  3. Configuration: The cloud provider configures the load balancer to distribute traffic across all worker nodes in the cluster, specifically targeting the NodePort automatically assigned to the service.
  4. IP Allocation: The cloud provider returns a static, publicly accessible IP address (or DNS name) to Kubernetes, which updates the service object’s status.loadBalancer.ingress field.

This creates a traffic path: User -> Cloud Load Balancer IP -> NodePort (on any Node) -> Pod.

Behavior in Unsupported Environments

A critical distinction exists regarding supported vs. unsupported environments. The LoadBalancer type requires a Cloud Controller Manager (CCM) to execute the infrastructure provisioning logic.

If this service type is deployed in an unsupported environment (e.g., a local VirtualBox cluster, a bare-metal installation without a CCM), the provisioning call fails. In this scenario:

  • Kubernetes creates the service object successfully.
  • It allocates a NodePort (behaving exactly like a NodePort type service).
  • The EXTERNAL-IP field in kubectl get services remains in a <pending> state indefinitely because no external infrastructure exists to fulfill the request.

To achieve a LoadBalancer IP in on-premise environments, operators must install implementations like MetalLB. Without such a controller, the service is accessible only via NodePorts.

Your inbox needs more DevOps articles.

Subscribe to get our latest content by email.