🐳 Section 14 · Question #12

What types of Service exist (ClusterIP, NodePort, LoadBalancer)

In Kubernetes, there are four primary Service types that control the network accessibility and scope of application Pods (whether an application is isolated inside the cluster o...

🟢 Junior Level

30-Second Interview Answer

In Kubernetes, there are four primary Service types that control the network accessibility and scope of application Pods (whether an application is isolated inside the cluster or exposed to the public internet):

  1. ClusterIP (Default): Assigns an internal, stable virtual IP accessible only within the Kubernetes cluster. Traffic from the public internet cannot reach this address. Used for 95% of microservices (backend APIs, databases, caches, message brokers).
  2. NodePort: Exposes a static port from a dedicated range (30000–32767) on every worker node in the cluster. External clients can access the application via http://<Node-IP>:NodePort.
  3. LoadBalancer: Automatically provisions a dedicated cloud load balancer (AWS NLB, GCP Cloud Load Balancer, Azure LB) with a public external IP through the cloud provider API.
  4. ExternalName: A specialized service type with no selector and no proxying. It returns a DNS CNAME record, redirecting internal traffic to an external domain (e.g., an external database mydb.rds.amazonaws.com).

Real-World Analogy: The Russian Matryoshka Doll

Architecturally, Kubernetes Service types are nested inside one another like traditional nesting dolls:

  • ClusterIP: The core, innermost doll. It creates the fundamental virtual IP routing directly to Pods.
  • NodePort: The middle doll. It wraps ClusterIP, exposing the port on all physical/virtual worker node interfaces.
  • LoadBalancer: The largest, outermost doll. It provisions an external cloud load balancer that routes traffic to the NodePort, which in turn routes to the ClusterIP, which load-balances traffic across the Pods!
+---------------------------------------------------------------+
|                      The Service Hierarchy                    |
|                                                               |
|   [ LoadBalancer ]  (External Cloud Public IP)                |
|         │                                                     |
|         ▼ wraps                                               |
|   [ NodePort ]      (Host IP : Port 30000-32767 on all nodes) |
|         │                                                     |
|         ▼ wraps                                               |
|   [ ClusterIP ]     (Internal Cluster Virtual IP)             |
|         │                                                     |
|         ▼ routes via kube-proxy                               |
|   [ Application Pods ] (Dynamic Pod IPs: 10.244.x.x)          |
+---------------------------------------------------------------+

Quick Comparison Matrix

| Service Type | External Public IP | Internet Reachable | Primary Architectural Use Case | |—|:—:|:—:|—| | ClusterIP | ❌ No | ❌ No | Internal microservice communication (Backend $\leftrightarrow$ DB) | | NodePort | ❌ No (Node IP) | 🟡 Yes (via Node IPs) | Staging environments, direct debugging, on-premises | | LoadBalancer | 🟢 Yes | 🟢 Yes | Production public entry points via cloud load balancers | | ExternalName | ❌ No | ❌ No | DNS alias for external databases and third-party SaaS |


🟡 Middle Level

Detailed Declarations & Usage Examples

1. ClusterIP (Internal Microservices Standard)

apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  type: ClusterIP      # Optional; defaults to ClusterIP if omitted
  selector:
    app: order-service
  ports:
  - name: http
    port: 80           # Port exposed inside the cluster
    targetPort: 8080   # Port on which the Spring Boot container listens

2. NodePort (Direct Access via Host Ports)

apiVersion: v1
kind: Service
metadata:
  name: debug-service
spec:
  type: NodePort
  selector:
    app: order-service
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 31234    # Must fall within 30000–32767; auto-assigned if omitted

A request sent to http://192.168.1.10:31234 is routed to the service, even if that specific node does not host any replica of the target Pod.

3. LoadBalancer (Cloud Infrastructure Integration)

apiVersion: v1
kind: Service
metadata:
  name: public-gateway
spec:
  type: LoadBalancer
  selector:
    app: api-gateway
  ports:
  - port: 443
    targetPort: 8443

The Kubernetes Cloud Controller Manager listens for this object and commands the cloud provider’s API to provision a physical AWS Network Load Balancer or Google Cloud Load Balancer.

4. ExternalName (DNS CNAME Redirection)

apiVersion: v1
kind: Service
metadata:
  name: payment-database
spec:
  type: ExternalName
  externalName: mydb-cluster.rds.amazonaws.com # CNAME returned by CoreDNS

The Java application connects to jdbc:postgresql://payment-database:5432/orders_db, and CoreDNS resolves the query to AWS RDS without proxying any TCP bytes through kube-proxy.


Architectural Cost Optimization: Ingress vs Multiple LoadBalancers

In enterprise production environments, every cloud LoadBalancer incurs monthly costs ($15 to $35/month per load balancer on AWS/GCP):

  • Anti-Pattern: Exposing 20 distinct microservices using 20 separate LoadBalancer services ($20 \times $25 = $500$ monthly just for idle network infrastructure).
  • Production Standard (The Ingress Pattern):
    1. Provision exactly one LoadBalancer service pointing to an Ingress Controller (Nginx, Traefik, Envoy).
    2. Configure all internal microservices as inexpensive, private ClusterIP services.
    3. The Ingress Controller inspects incoming HTTP/HTTPS traffic at Layer 7 and routes requests by domain or path prefix (/api/orders, /api/users) to the internal ClusterIP services.

🔴 Senior Level

Network Routing Policy: externalTrafficPolicy: Cluster vs Local

For NodePort and LoadBalancer services, understanding spec.externalTrafficPolicy is critical for security and network performance:

[ externalTrafficPolicy: Cluster (Default) ]        [ externalTrafficPolicy: Local ]
                  Client                                            Client
                    │                                                 │
                    ▼                                                 ▼
          [ Node 1 (No Pod) ]                               [ Node 1 (No Pod) ]
                    │ (SNAT + Extra Hop)                              ❌ Dropped! (LB doesn't route here)
                    ▼                                                 ▼
          [ Node 2 (Has Pod) ]                              [ Node 2 (Has Pod) ]
                                                                      🟢 Direct execution (No SNAT!)

1. externalTrafficPolicy: Cluster (Default)

  • Traffic arriving at any worker node can be routed over the cluster overlay network (Flannel, Calico) to a Pod running on a different node.
  • Advantage: Perfectly balanced traffic distribution across all Pods in the cluster.
  • Disadvantages:
    1. Extra Network Hop: Adds cross-node network latency.
    2. Loss of Client Source IP (SNAT): The node performs Source NAT, rewriting the client IP to the node’s internal overlay IP. The application loses the real client IP, breaking geolocation, audit logging, and rate limiting.

2. externalTrafficPolicy: Local

  • Traffic arriving at a node is routed only to Pods running locally on that same node. If no Pod exists on that node, packets are discarded.
  • Advantages:
    1. Preserves Real Client IP: Eliminates SNAT; the Java application receives the original public IP.
    2. Zero Extra Hops: Guarantees lowest possible network latency.
  • Disadvantage: Requires the cloud load balancer to know which nodes host healthy Pods. Kubernetes automatically opens a dedicated healthCheckNodePort so the cloud load balancer checks node readiness and routes traffic only to nodes running active Pods.

Internal Cloud LoadBalancers (Private VPC)

By default, type: LoadBalancer allocates an internet-facing public IP. To create an internal load balancer accessible only within a private enterprise VPC, apply cloud provider annotations:

metadata:
  name: internal-api
  annotations:
    # AWS NLB/ELB:
    service.beta.kubernetes.io/aws-load-balancer-internal: "true"
    # Google Cloud GKE:
    networking.gke.io/load-balancer-type: "Internal"
    # Azure AKS:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"

On-Premises Bare-Metal Load Balancing: MetalLB

Bare-metal Kubernetes clusters do not have cloud provisioning APIs; services of type LoadBalancer remain perpetually in <pending> status. To resolve this, engineers deploy MetalLB:

  1. Layer 2 Mode (ARP/NDP): One node in the cluster responds to ARP requests for the virtual VIP using gratuitous ARP. If that node crashes, failover mechanisms elect another node to announce the VIP.
  2. BGP Mode (Border Gateway Protocol): Cluster worker nodes establish BGP peering sessions with data center top-of-rack physical routers (Cisco, Juniper), announcing service VIP routes using Equal-Cost Multi-Path (ECMP) load balancing.

4 Tricky Questions with In-Depth Answers

1. Why does Kubernetes allocate both a NodePort and a ClusterIP when creating a service of type: LoadBalancer? Can you disable the NodePort allocation?

Answer: Cloud load balancers (such as AWS Classic ELB or basic NLB) do not have direct routing routes into the internal Kubernetes pod overlay CIDR (10.244.0.0/16). Instead, the cloud load balancer forwards incoming public packets to the physical IP addresses of the cluster nodes on the assigned NodePort. The node’s kube-proxy rules then translate that packet through the ClusterIP to target the Pod. Disabling NodePort: Since Kubernetes 1.20, you can set spec.allocateLoadBalancerNodePorts: false. In modern cloud setups where the CNI plugin supports direct Pod IP routing (e.g., AWS VPC CNI with TargetGroupBinding in IP mode), the cloud load balancer bypasses node ports and routes directly to the Pod IPs, preserving valuable node ports in the cluster.

2. Why does connecting to an external HTTPS service via type: ExternalName often fail with an SSL/TLS handshake error (SSLHandshakeException) in Java?

Answer: The ExternalName service operates purely as a DNS redirect (returning a CNAME record) without proxying TCP packets:

  • When a Java application calls https://external-service:443, the JVM sends a TLS ClientHello packet containing a Server Name Indication (SNI) extension with the value external-service.
  • The remote server (e.g., AWS RDS or an external API gateway) presents an SSL certificate issued for its real domain: *.rds.amazonaws.com.
  • The JVM’s TLS verification layer compares the requested hostname (external-service) with the Subject Alternative Names (SAN) in the server’s certificate. Because they do not match, the JVM aborts the connection with javax.net.ssl.SSLPeerUnverifiedException: Certificate for <external-service> doesn't match common name.

3. How does externalTrafficPolicy: Local prevent Client IP leakage and why does it require healthCheckNodePort?

Answer: Under the default Cluster policy, a packet arriving at Node A may be forwarded across the overlay network to Node B where the Pod resides. To allow Node B to send response packets back through Node A, Node A replaces the client’s source IP with its own node IP using Source NAT (SNAT), obliterating the original client IP. In Local mode, cross-node packet forwarding is prohibited; packets are handled exclusively by Pods on the receiving node, eliminating the need for SNAT and preserving the authentic Client IP. However, if a node has no Pod replicas, incoming packets would be dropped. To prevent black-holing traffic, Kubernetes creates a healthCheckNodePort. The cloud load balancer polls this port: nodes hosting healthy Pods return HTTP 200, while nodes without Pods return HTTP 503, allowing the external load balancer to route traffic only to viable nodes.

4. Can you connect to a NodePort service from inside the cluster using its internal ClusterIP, ignoring the port 30000–32767?

Answer: Yes, absolutely. Every NodePort service is simultaneously a fully functional ClusterIP service. Inside the cluster, other microservices should always access the service via its internal DNS name and standard port (e.g., http://my-service:80), ignoring the external nodePort (31234). The nodePort allocation is solely intended to receive ingress traffic arriving on the node’s external physical network interfaces.


🎯 Interview Cheat Sheet

Summary of Service Types

  • ClusterIP: Internal default; stable virtual IP accessible only within the cluster.
  • NodePort: Exposes static port 30000–32767 on every node; wraps ClusterIP.
  • LoadBalancer: Provisions external cloud public IP (AWS/GCP); wraps NodePort and ClusterIP.
  • ExternalName: Pure DNS CNAME alias; returns external domain without TCP proxying.
  • Ingress Pattern: Expose 1 LoadBalancer for Ingress; keep all microservices as ClusterIP.
  • externalTrafficPolicy: Local: Preserves real Client IP and eliminates extra hop; requires healthCheckNodePort.

Network Access Property Matrix

| Service Type | Allocates ClusterIP? | Allocates NodePort? | Requires Cloud Provider / MetalLB? | |—|:—:|:—:|:—:| | ClusterIP | 🟢 Yes | ❌ No | ❌ No | | NodePort | 🟢 Yes | 🟢 Yes | ❌ No | | LoadBalancer | 🟢 Yes | 🟢 Yes (Default) | 🟢 Yes | | ExternalName | ❌ No | ❌ No | ❌ No (CoreDNS only) |

Red Flags (DO NOT Say)

  • ❌ “In production, we create a public LoadBalancer service for every backend microservice.” (Massive unnecessary cloud expense and dangerous security surface; use Ingress with ClusterIP).
  • ❌ “NodePort only opens the port on the node where the Pod is actively running.” (NodePort binds on every single worker node across the entire cluster).
  • ❌ “ExternalName proxies TCP traffic through kube-proxy to an external database.” (It is pure DNS CNAME aliasing; traffic travels directly between client and host).