Document contract
- Role: concept
- Truth boundary: portable Kubernetes behavior observed through
devata- Last verified: Kubernetes documentation, 2026-07-26
Prerequisites: kubernetes
Pods are replaceable. A rescheduled Pod gets a new IP, so its address is not a durable contract for callers. A Service supplies a stable DNS name and virtual address in front of a changing set of eligible Pods.
The Service does not proxy bytes by itself. Three mechanisms cooperate:
flowchart LR caller --> dns[CoreDNS name] dns --> service[Service and ClusterIP] selector[Label selector] --> endpoints[EndpointSlice backends] endpoints -. eligible IPs .-> dataplane[Cilium or kube-proxy] service --> dataplane --> pod[Ready Pod]
- the Service selector describes which Pods belong behind it;
- EndpointSlice controllers publish their current addresses and readiness;
- a dataplane implements translation from the virtual Service address to one backend.
In devata, cilium implements the dataplane with eBPF because kube-proxy is disabled. On many clusters kube-proxy programs iptables or IPVS rules for the same contract.
Observe every link
These commands are read-only:
kubectl config current-context
kubectl -n monitoring get service kps-grafana -o wide
kubectl -n monitoring get service kps-grafana -o jsonpath='{.spec.selector}'
kubectl -n monitoring get endpointslice \
-l kubernetes.io/service-name=kps-grafana -o wide
kubectl -n monitoring get pods --show-labels -o wideExpected observations:
- the Service has a stable clusterip and a label selector;
- the EndpointSlice contains current backend IPs;
- those IPs match Pods whose labels satisfy the selector;
- backend readiness can remove a Pod from normal traffic without deleting it.
A Service with no endpoints is a valid object with no usable backends. A Service with endpoints can still fail because of DNS, network policy, dataplane, port mapping, or application behavior. Test the transaction, not only the objects.
Service types are exposure choices
ClusterIPis reachable through the cluster network and is the default.NodePortreserves a port on nodes and forwards it to the Service.LoadBalancerasks an implementation such as metallb for an external address.ExternalNamereturns a DNS alias and does not select Pods.
Gateway API and Ingress can route HTTP traffic to a Service, but they do not replace the Service’s stable backend contract.
Check yourself
- Why does deleting and recreating a backend Pod not require callers to learn a new address?
- Which object proves the current backend set, and which field links it to the Service?
- What evidence distinguishes a selector mistake from a broken dataplane?