• Pod IPs are ephemeral: stable virtual IP + DNS from Service
  • Traffic: Client -> Service (port) -> Pod (targetPort -> containerPort)
  • Selector must match Pod labels exactly

Service Type Hierarchy

ClusterIP -> NodePort -> LoadBalancer
                \
         ExternalName (DNS-only)

1. ClusterIP (default)

  • Internal virtual IP; only accessible inside cluster
  • DNS same NS: backend; cross NS: backend.default
apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  type: ClusterIP
  selector:
    app: backend
  ports:
  - port: 80
    targetPort: 8080

Session affinity (sticky sessions)

spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800    # default 3 hours
  • None (default): round-robin; ClientIP: same source IP → same Pod

2. NodePort

  • Port range: 30000-32767; auto-assigned if not specified
  • Client -> NodeIP:NodePort -> Service -> Pod
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30007

3. LoadBalancer

  • Provisions external cloud load balancer
  • EXTERNAL-IP may be <pending> without cloud provider
  • Internally still uses NodePort

4. ExternalName

  • Pure DNS alias; no proxying, no IP, no endpoints, no selector
spec:
  type: ExternalName
  externalName: db.example.com
  • my-db.default.svc.cluster.local -> db.example.com

5. Headless Service

  • clusterIP: None; DNS returns Pod IPs directly
spec:
  clusterIP: None
  selector:
    app: db
  ports:
  - port: 5432

6. Selector-less Service (manual endpoints)

# Service without selector
spec:
  ports:
  - port: 80
    targetPort: 9999
  selector: null
---
# EndpointSlice
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: ext-service
  labels:
    kubernetes.io/service-name: ext-service
addressType: IPv4
ports:
- port: 9999
endpoints:
- addresses:
  - 192.168.1.10

Traffic Mapping

FieldMeaning
portService port (client uses)
targetPortPod/container port
nodePortNode external port (NodePort only)

DNS (CoreDNS)

ResourceDNS Format
Service (same NS)<svc-name>
Service (different NS)<svc-name>.<namespace>
Service (FQDN)<svc-name>.<namespace>.svc.cluster.local
StatefulSet pod<pod-name>.<svc-name>.<namespace>.svc.cluster.local
kubectl exec <pod> -- nslookup webapp-svc
kubectl exec <pod> -- wget -qO- http://webapp-svc:80

Commands

TaskCommand
Expose as ClusterIPkubectl expose deployment webapp --port=80 --target-port=8080
Expose as NodePortkubectl expose deployment webapp --type=NodePort --port=80
Get service + endpointskubectl get svc,endpoints
Describekubectl describe svc webapp
Test from inside clusterkubectl run tmp --image=busybox --rm -it -- wget -qO- http://webapp-svc

Debug Checklist

  1. Selector matches Pod labels
  2. kubectl get endpoints not empty
  3. targetPort == containerPort
  4. Pod is Ready
  5. Same namespace

Exam gotchas

  • Empty endpoints = no traffic; always verify kubectl get endpoints <svc-name>
  • ClusterIP is default
  • LoadBalancer still uses NodePort internally
  • ExternalName: no selector, no ClusterIP, no proxying
  • sessionAffinity: ClientIP for sticky sessions