LearnKubernetes
Kubernetes2. Core Concepts·EXPERT·6 min read

Kubernetes Services

TL;DR

  • A Service is a stable virtual IP and DNS name in front of a set of Pods selected by label; it exists because Pod IPs are ephemeral and change on every restart/reschedule.
  • Four types cover distinct exposure levels: ClusterIP (internal only, default), NodePort (host port 30000-32767 on every node), LoadBalancer (provisions a cloud LB, builds on NodePort/ClusterIP), ExternalName (DNS CNAME alias, no selector, no proxying).
  • Services are not processes — kube-proxy on every node programs iptables/IPVS rules in the kernel to DNAT traffic from the Service VIP to a Pod IP.
  • The single biggest gotcha: an empty Endpoints/EndpointSlice list almost always means the Service selector does not match the Pod’s labels (frequently a case mismatch) — the Service object itself will look healthy.
  • Headless Services (clusterIP: None) skip the VIP entirely and return individual Pod A records via DNS — required for peer-aware stateful workloads.

Core Concepts

Why Services Exist

Pod IP addresses are dynamic: Pods are recreated on rescheduling, scaling, or rollout, and each new Pod gets a new IP. Clients cannot reliably target individual Pod IPs. A Service provides a stable virtual IP (VIP) and DNS name that persists independent of which Pods are currently backing it.

Service Types

ClusterIP (default). Allocates a stable, internal-only IP from the cluster’s Service CIDR. Only reachable from inside the cluster. Used for internal microservices — databases, backend APIs, caches.

NodePort. Exposes the Service on every Node’s IP at a static port in the 30000-32767 range. A client connects to :; kube-proxy intercepts the traffic on that node and routes it to a backing Pod, which may live on a different node. Used for local/dev access or bridging to external load balancers that can’t provision native cloud LBs.

LoadBalancer. Provisions a cloud provider’s native load balancer (AWS NLB/ALB, GCP Cloud Load Balancer). Under the hood it automatically creates a NodePort and ClusterIP, then configures the cloud LB to forward to the NodePort on cluster nodes. Used for public-facing applications.

ExternalName. Maps the Service name to an external DNS name via a CNAME record. Has no selector and does no proxying/load balancing — it is purely a DNS-level redirect. Used to give pods a stable internal name for an external dependency (e.g., an RDS endpoint).

Labels, Selectors, and EndpointSlices

Services decouple clients from specific Pods using label selectors. When a Service is created, the control plane continuously computes an EndpointSlice object that maps the Service to the actual IPs of currently-matching, ready Pods. This mapping is what kube-proxy consumes to program routing rules — it is not a static snapshot.

Under the Hood: kube-proxy and Kernel-Level Routing

A Service is not a running proxy process (unlike an Nginx instance). It is a logical spec realized by cluster components:

  1. VIP assignment. The API Server assigns a virtual IP to the Service from the cluster’s Service CIDR range.
  2. kube-proxy sync. kube-proxy, running as a daemon on every Node, watches the API server for Service and EndpointSlice changes.
  3. Kernel programming. kube-proxy writes iptables rules (or IPVS rules, in IPVS mode) directly into the host Node’s kernel netfilter tables.
  4. Packet routing. When a container sends a packet to the Service VIP, the host kernel intercepts it via these rules, selects a backing Pod (e.g., iptables’ random-probability matching to approximate load balancing), rewrites the destination IP to that Pod’s IP (DNAT), and forwards the packet. No user-space proxy is on the data path in iptables mode.

Headless Services

Setting clusterIP: None explicitly disables VIP allocation and proxying. CoreDNS then returns a list of A records — one per matching, ready Pod IP — instead of a single virtual IP. Clients performing a DNS lookup get direct Pod IPs and can connect peer-to-peer. This is required for stateful clustered systems (Cassandra, Elasticsearch, Kafka) where replicas must establish direct connections to specific peers rather than being load-balanced round-robin.

DNS Resolution

Every Service gets a DNS entry via CoreDNS. Within the same namespace, the short name (db-service) resolves. Across namespaces, the FQDN is required: ..svc.cluster.local (e.g., db-service.data.svc.cluster.local).

ClusterIP vs NodePort vs LoadBalancer vs ExternalName

Aspect ClusterIP NodePort LoadBalancer ExternalName
Reachable from Inside cluster only Any node IP, port 30000-32767 Public internet (via cloud LB) Inside cluster (DNS alias)
Builds on ClusterIP NodePort + ClusterIP
Uses selector Yes Yes Yes No
Requires cloud provider integration No No Yes No
Typical use Internal services, DBs Dev/test, legacy LB integration Public-facing apps Pointing to external endpoints

Command / Configuration Reference

apiVersion: v1
kind: Service
metadata:
  name: auth-service
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: auth-api # Finds all pods with label "app: auth-api"
  ports:
  - name: http
    port: 80 # Port exposed by the Service VIP
    targetPort: 3000 # Port the container actually listens on
# List all Services in the current namespace
kubectl get svc

# Describe a Service to see its mapped endpoints (target Pod IPs)
kubectl describe svc auth-service
# Check the "Endpoints:" field — if empty, the selector doesn't match Pod labels

# Expose an existing Deployment imperatively as a NodePort Service
kubectl expose deployment auth-api --name=auth-service --type=NodePort --port=80 --target-port=3000

# Verify Service DNS resolution from inside a throwaway pod
kubectl run dns-diagnostic --rm -i --tty --image=busybox -- nslookup auth-service

Common Pitfalls

  • Pitfall: kubectl describe svc shows an empty Endpoints list and traffic to the Service times out. Why: The Service’s selector does not match any Pod’s labels — often a case-sensitivity mismatch (app: frontend vs app: FrontEnd); the Service object itself validates fine. Fix: Compare kubectl get svc -o yaml selector against kubectl get pods --show-labels and align them exactly.
  • Pitfall: Assuming a Service is a running proxy that can be restarted or debugged like a pod. Why: A Service is a logical object; the actual routing is kernel-level iptables/IPVS rules maintained by kube-proxy on each node. Fix: Debug by checking kube-proxy logs/rules on the node and the EndpointSlice object, not the Service resource itself.
  • Pitfall: Expecting a NodePort Service to load-balance evenly and immediately after a Pod is deleted. Why: Routing depends on kube-proxy reconciling updated EndpointSlices, which is eventually consistent, not instantaneous. Fix: Account for brief propagation delay; use readiness probes so terminating/starting Pods aren’t sent traffic prematurely.
  • Pitfall: Using a regular Service for a StatefulSet where replicas need to address each other individually. Why: A normal Service load-balances across a single VIP, hiding individual Pod identity. Fix: Use a Headless Service (clusterIP: None) so DNS returns per-Pod A records.

Interview Questions

  • What is a Headless Service and when would you use one? — Tests understanding of clusterIP: None and stateful workload requirements.
  • Walk through what happens at the kernel level when a Service receives a packet. — Tests depth of understanding of kube-proxy, iptables/IPVS, and DNAT.
  • A Service has Pods running and healthy, but kubectl describe svc shows no endpoints — how do you debug it? — Tests practical troubleshooting of selector/label mismatches.
  • Why does LoadBalancer type depend on the cloud provider, and what happens if you use it on bare-metal? — Tests knowledge of cloud controller integration and tools like MetalLB.
  • How does DNS resolution differ for a Service in the same namespace versus a different namespace? — Tests FQDN and svc.cluster.local knowledge.
🔒 Locked
Sign in and unlock the full syllabus to keep reading.
Sign in to continue
Knowledge check
5 scenario questions on this topic
Take the quiz →
Related in 2. Core Concepts
Why Kubernetes
INTERMEDIATE
Kubernetes Architecture
EXPERT
Kubernetes Cluster Setup
INTERMEDIATE
Pods & YAML
INTERMEDIATE