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:
- Lack of Stability: If a node goes down, that specific URL becomes unavailable. Clients must manually retry another node IP.
- 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. - 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:
- Request: The Kubernetes Controller Manager detects the
LoadBalancertype request. - 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).
- 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.
- 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.ingressfield.
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
NodePorttype service). - The
EXTERNAL-IPfield inkubectl get servicesremains 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.
