Lab 14 - Services

Lab 14 - Services

Goal: reach Pods by a stable name, from inside and from outside. Chapter: Services

# 1 - something to expose
cd ~
kubectl create deploy web --image nginx:1.27 --replicas 3
kubectl get pods -l app=web -o wide      # note the Pod IPs
# 2 - ClusterIP, the default
kubectl expose deploy web --port 80 --name web-svc
kubectl get svc web-svc
kubectl get endpointslices -l kubernetes.io/service-name=web-svc

The EndpointSlice is the interesting object: it holds the three Pod IPs. The Service is just a stable front; the EndpointSlice is the live membership list, maintained by a controller as Pods become ready.

# 3 - reach it by name from inside the cluster
kubectl run tmp --image busybox --restart=Never -it --rm -- \
  wget -qO- --timeout=3 web-svc | head -3

# 4 - what DNS actually returns
kubectl run tmp --image busybox --restart=Never -it --rm -- \
  nslookup web-svc.default.svc.cluster.local

The name resolves to the ClusterIP, not to a Pod. Traffic to that virtual IP is rewritten by kube-proxy on the node to one of the real Pod IPs.

# 5 - stability: destroy every Pod, keep the address
kubectl get svc web-svc -o jsonpath='{.spec.clusterIP}{"\n"}'
kubectl delete pod -l app=web
kubectl get pods -l app=web -o wide      # all new IPs
kubectl get svc web-svc -o jsonpath='{.spec.clusterIP}{"\n"}'   # unchanged
kubectl get endpointslices -l kubernetes.io/service-name=web-svc  # new IPs inside

That is the whole value proposition: the Pods are cattle, the Service name is not.

From outside the cluster

# 6 - NodePort opens the same port on EVERY node
kubectl delete svc web-svc
kubectl expose deploy web --port 80 --type NodePort --name web-svc
PORT=$(kubectl get svc web-svc -o jsonpath='{.spec.ports[0].nodePort}')
echo $PORT
for n in control01 worker01 worker02 worker03; do
  echo -n "$n: "; curl -s --max-time 3 http://$n:$PORT | grep -o '<title>.*</title>'
done

Every node answers, including nodes running none of the Pods - kube-proxy forwards for the whole cluster. Note how quickly this gets unmanageable with more than a couple of applications, which is the argument for the Gateway API in the next lab.

# 7 - port-forward, for debugging only
kubectl port-forward svc/web-svc 8080:80 &
curl -s localhost:8080 | head -3
kill %1

port-forward runs on your workstation and dies with the terminal. Useful for poking at something that has no external access; never part of a solution.

Clean up

# 8 -
kubectl delete svc web-svc
kubectl delete deploy web