interview-prep

Crisp answer: A Service is a stable virtual IP and DNS name that load-balances traffic to a set of pods selected by labels, regardless of where those pods are running or how many there are.

Why Services exist:

Pods are ephemeral. Their IPs change every time they are replaced. A Service provides a stable endpoint that other pods and external clients can use regardless of pod churn.

The four Service types:

ClusterIP (default):

Creates a virtual IP (VIP) that only works within the cluster. kube-proxy programs iptables/IPVS rules on every node to NAT packets destined for the ClusterIP to a real pod IP.

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  type: ClusterIP     # default if omitted
  selector:
    app: api
  ports:
  - port: 80
    targetPort: 8080
# DNS: api.default.svc.cluster.local → ClusterIP
# From any pod: curl http://api  or  curl http://api.default.svc.cluster.local
kubectl get svc api
# NAME  TYPE       CLUSTER-IP    EXTERNAL-IP  PORT(S)  AGE
# api   ClusterIP  10.96.45.12   <none>       80/TCP   5m

NodePort:

Opens a static port (30000-32767) on every node. Traffic to <any-node-IP>:<nodePort> is forwarded to the Service. Useful for testing. Not for production — you'd need to manage your own load balancer in front of the nodes.

LoadBalancer:

On EKS/AWS, this provisions an AWS Network Load Balancer (NLB) or Classic ELB automatically. The external IP of the LB is exposed as the Service's EXTERNAL-IP.

kubectl get svc my-service
# NAME        TYPE          CLUSTER-IP   EXTERNAL-IP                        PORT(S)
# my-service  LoadBalancer  10.96.1.1    a1b2c3d4.eu-west-2.elb.amazonaws.com  80:32456/TCP

This is what most production workloads on EKS use for external exposure. Each LoadBalancer Service creates a new AWS load balancer — expensive if you have many services. Use an Ingress controller (one LB for many services) instead.

ExternalName:

Maps a Service to a DNS name outside the cluster. No proxying — just a CNAME.

spec:
  type: ExternalName
  externalName: rds.eu-west-2.amazonaws.com

Headless Service:

clusterIP: None — no VIP, DNS returns individual pod IPs. Used by StatefulSets and service meshes for peer discovery.

How kube-proxy implements Services:

# See iptables rules for a Service:
iptables -t nat -L KUBE-SERVICES -n | grep <service-IP>

# The chain KUBE-SVC-XXXX contains rules to probabilistically forward
# to each endpoint (KUBE-SEP-XXXX chains)

# On EKS with IPVS mode:
ipvsadm -ln

Endpoints:

A Service has an Endpoints (or EndpointSlice) object that lists the pod IPs. When pods are added/removed, kube-proxy updates the iptables rules.

kubectl get endpoints api
# NAME  ENDPOINTS                           AGE
# api   10.244.1.5:8080,10.244.2.3:8080    5m

# If Endpoints shows <none>, the selector doesn't match any pods:
kubectl get pods --show-labels | grep app=api

What to say in the interview:

"A Service gives a stable ClusterIP and DNS name that survives pod churn. kube-proxy programs iptables rules on every node to DNAT packets to the ClusterIP into real pod IPs. The four types: ClusterIP for internal traffic, NodePort for opening a port on every node, LoadBalancer for provisioning an AWS NLB on EKS, and ExternalName for a DNS alias to something outside the cluster. If a Service isn't routing, the first thing I check is the Endpoints object — if it's empty, the selector doesn't match any pods. If Endpoints look right, I check iptables rules or whether kube-proxy is running."


My notes