🐳 Section 14 · Question #11

What is Service in Kubernetes

A Service in Kubernetes is an abstract Layer 4 (TCP/UDP) networking object that provides a stable, permanent network entry point (Virtual IP and DNS name) and load balancing acr...

🟢 Junior Level

30-Second Interview Answer

A Service in Kubernetes is an abstract Layer 4 (TCP/UDP) networking object that provides a stable, permanent network entry point (Virtual IP and DNS name) and load balancing across an ephemeral, dynamically changing group of Pods.

Pods in Kubernetes are mortal and disposable: when a Pod crashes, scales up, or is rescheduled onto another node, it receives a completely new dynamic IP address:

  • If microservices communicated directly using Pod IPs, every deployment or restart would break upstream services.
  • A Service solves this: It is assigned a permanent virtual IP (ClusterIP) that remains constant throughout the lifecycle of the Service.
  • Upstream clients send traffic to a consistent hostname (e.g., http://payment-service:8080), and Kubernetes automatically load balances incoming requests across all healthy Pod replicas.

Real-World Analogy: The Bank Call Center

Imagine calling a commercial bank’s customer support:

  • The support operators are the Pods: they take breaks, finish shifts, and their numbers fluctuate dynamically.
  • The Service is the single 1-800 toll-free hotline number.
  • As a customer, you never call an operator’s personal cell phone. You dial the single permanent hotline, and the automated switchboard connects your call to an available, on-duty operator.

Basic Service Manifest Example

apiVersion: v1
kind: Service
metadata:
  name: payment-service
spec:
  type: ClusterIP      # Internal cluster-only access (default)
  selector:
    app: payment-api   # Discovers all Pods labeled app=payment-api
  ports:
  - name: http
    port: 80           # Port exposed by the Service on its ClusterIP
    targetPort: 8080   # Port on the container where the Java app listens

Within the cluster, any client container accesses the application via internal DNS:

curl http://payment-service:80/api/v1/payments

🟡 Middle Level

How Services Discover Pods: Selectors and EndpointSlices

The relationship between a Service and its target Pods is loosely coupled through Labels and Selectors:

  1. The Service defines query criteria in spec.selector (e.g., app: payment-api).
  2. The Kubernetes Control Plane continuously discovers Pods possessing matching labels.
  3. The IP addresses of Pods that have successfully passed their readinessProbe are automatically published to a linked resource: the Endpoints or modern EndpointSlice object: ```yaml apiVersion: discovery.k8s.io/v1 kind: EndpointSlice metadata: name: payment-service-abc12 labels: kubernetes.io/service-name: payment-service addressType: IPv4 ports:
    • name: http port: 8080 endpoints:
    • addresses: [“10.244.1.15”] conditions: ready: true
    • addresses: [“10.244.2.34”] conditions: ready: true ```
  4. If a Pod crashes or its readiness probe fails, its IP is immediately stripped from the EndpointSlice, instantaneously terminating traffic flow to that Pod.

Internal DNS Resolution (CoreDNS)

When a Service is created, the cluster’s internal DNS engine (CoreDNS) creates an A record mapping the service name to its ClusterIP. The Fully Qualified Domain Name (FQDN) follows the standard structure: \(\mathbf{<service\text{-}name>.<namespace>.svc.cluster.local}\)

  • Same Namespace: A short name is sufficient: http://payment-service.
  • Cross-Namespace: Requires the namespace prefix: http://payment-service.billing-ns.
  • Full FQDN: http://payment-service.billing-ns.svc.cluster.local.

The 4 Core Service Types

| Service Type | Reachability Scope | Primary Production Purpose | |—|—|—| | ClusterIP (Default)| Accessible only within the Kubernetes cluster | Standard internal microservice-to-microservice communication. | | NodePort | Accessible on a static high port (30000–32767) on every node | Dev environments or on-prem setups without cloud load balancers. | | LoadBalancer | Publicly accessible via the internet | Provisions a managed cloud load balancer (AWS NLB/ALB, GCP LB). | | ExternalName | Internal DNS CNAME redirect | Maps an internal Service name to an external DNS record (e.g., AWS RDS). |


🔴 Senior Level

Under the Hood: kube-proxy Data Planes (iptables vs IPVS vs eBPF)

A Senior Engineer must recognize that ClusterIP is a Virtual IP (VIP).

  • There is no physical or virtual network interface card assigned this IP.
  • The kube-proxy daemon runs on every node, intercepting traffic destined for the ClusterIP and rewriting network packets using the host Linux kernel:
[ Inbound Packet to ClusterIP:80 ]
               │
               ▼
[ Linux Kernel Netfilter / iptables / IPVS ]
               │ (DNAT rewrites destination IP/Port)
               ▼
[ Physical Pod IP: 10.244.2.34:8080 ]

1. iptables Mode (Default)

  • kube-proxy configures Linux kernel iptables rules in the nat table.
  • Load balancing is implemented using the statistic kernel module with random probability. For 3 Pods:
    • Rule 1 matches with probability $p = 1/3$.
    • Rule 2 matches with probability $p = 1/2$.
    • Rule 3 matches the remainder ($p = 1.0$).
  • The $O(N)$ Scalability Bottleneck: Rules must be evaluated sequentially. In massive clusters with 5,000+ Services (tens of thousands of iptables rules), kernel packet processing latency increases linearly, consuming substantial CPU.

2. IPVS Mode (IP Virtual Server)

  • Built on top of the Linux kernel Netfilter transport layer, using hash tables with constant-time lookup $O(1)$.
  • Supports sophisticated load-balancing algorithms: round-robin, least connections, locality-based, source hashing.
  • Can easily handle 50,000+ Services without packet processing degradation.

3. eBPF Mode (e.g., Cilium CNI)

  • Completely replaces kube-proxy and iptables conntrack.
  • Uses eBPF (Extended Berkeley Packet Filter) bytecode attached directly to socket layers and network drivers (XDP).
  • Achieves near-native wire speed with virtually zero Netfilter overhead.

EndpointSlice API: Mitigating the etcd Watch Storm

In early Kubernetes releases (prior to 1.21), all Pod IPs for a service were bundled into a single monolithic Endpoints object:

  • For a service with 5,000 Pods, the Endpoints resource exceeded 1.5–2 MB.
  • When a single Pod restarted, the entire 2 MB JSON object was broadcast to every kube-proxy daemon across thousands of nodes.
  • This triggered catastrophic API server CPU saturation and network bandwidth spikes (Watch Storms).
  • The Modern Solution: Kubernetes now splits endpoints across multiple EndpointSlice objects (capped at 100 endpoints per slice). Updating one Pod mutates a single 2 KB slice, reducing network serialization traffic by over 95%.

Headless Services (clusterIP: None)

Declaring clusterIP: None in a Service manifest creates a Headless Service:

apiVersion: v1
kind: Service
metadata:
  name: kafka-cluster
spec:
  clusterIP: None  # Disables virtual IP allocation!
  selector:
    app: kafka
  ports:
  - port: 9092
  • Behavior: Kubernetes does not assign a VIP, and kube-proxy creates no packet routing rules.
  • DNS Lookup: Querying CoreDNS for kafka-cluster returns a list of A records containing the direct IP addresses of all healthy Pods.
  • Production Use Case: Distributed stateful systems (Kafka, Cassandra, PostgreSQL/MySQL clusters) where the client driver (e.g., Kafka Producer/Consumer) must negotiate direct point-to-point connections with specific partition leaders and replicas.

4 Tricky Questions with In-Depth Answers

1. Why does running ping <ClusterIP> from inside a Pod always result in 100% packet loss, even though curl works instantly?

Answer: A Service ClusterIP is purely a software construct implemented via Linux kernel address translation rules (DNAT in Netfilter iptables or IPVS). These rules are bound strictly to Layer 4 transport protocols (TCP and UDP) on the specific ports declared in the Service manifest. The ping utility operates on ICMP Echo Requests (Layer 3/Network layer), which have no port concept. Because no physical interface or virtual adapter holds the ClusterIP, the Linux kernel has no rule to translate or route ICMP packets addressed to the VIP, and the ping packets are discarded silently.

2. How do you configure a Service to connect to an external Oracle/PostgreSQL database located outside the cluster using internal Kubernetes Service Discovery?

Answer: You create a Service without a selector, and manually declare an independent Endpoints object with the exact same name:

apiVersion: v1
kind: Service
metadata:
  name: external-oracle-db
spec:
  ports:
  - port: 1521
---
apiVersion: v1
kind: Endpoints
metadata:
  name: external-oracle-db
subsets:
  - addresses:
      - ip: 192.168.1.150   # Physical IP of external DB server
    ports:
      - port: 1521

Java applications within the cluster configure their JDBC connection as jdbc:oracle:thin:@external-oracle-db:1521/XEPDB1. If the physical database moves or changes IP, only the Endpoints manifest needs updating—zero application restarts or configuration changes required.

3. What is the exact difference between port and targetPort in a Service spec, and what happens if targetPort is omitted?

Answer:

  • port: The TCP/UDP port that the Service exposes on its virtual ClusterIP inside the cluster. This is the port that client microservices call.
  • targetPort: The actual port on which the container process is listening inside the target Pod (e.g., port 8080 for Spring Boot). The kernel translates incoming packets from port to targetPort.
  • Omission Behavior: If targetPort is omitted from the manifest, Kubernetes automatically defaults targetPort to be identical to port.

4. Why can using sessionAffinity: ClientIP in a Service break load balancing in a microservices architecture with an Ingress / API Gateway?

Answer: When sessionAffinity: ClientIP is enabled, kube-proxy pins all traffic originating from a given client IP address to the same backend Pod for a specified duration. In modern architectures, client requests pass through an edge reverse proxy (such as an Ingress Controller, Envoy, or Spring Cloud Gateway). From the perspective of the internal Service, every single inbound connection originates from the same source IP: the Ingress Controller’s internal IP. Consequently, sessionAffinity routes 100% of all incoming cluster traffic to a single Pod, starving it into CPU/OOM failure while neighboring Pod replicas sit completely idle. Session affinity should be handled at Layer 7 (e.g., via Ingress cookie-based sticky sessions), not Layer 4.


🎯 Interview Cheat Sheet

Summary of Service

  • Definition: Stable Layer 4 network abstraction and load balancer providing a permanent VIP and DNS name for dynamic Pods.
  • Wiring: Connects to Pods via Label Selectors; healthy IPs are listed in EndpointSlices.
  • DNS Resolution: Handled by CoreDNS (<name>.<namespace>.svc.cluster.local).
  • Data Plane Mechanics: Implemented by kube-proxy using iptables ($O(N)$ random routing), IPVS ($O(1)$ hashing), or eBPF.
  • Headless Mode: clusterIP: None bypasses load balancing and returns direct Pod IPs for stateful clustering.

Service Types Matrix

| Type | Accessible Location | Default Port Scope | Typical Use Case | |—|—|—|—| | ClusterIP | Internal cluster only | Any port | Internal microservice communication | | NodePort | Cluster-wide on all Node IPs | Port 30000–32767 | Non-cloud testing, developer clusters | | LoadBalancer| Internet / External network | Standard ports (80, 443) | Production public entry points via Cloud LBs | | ExternalName| Internal cluster via CNAME | N/A (DNS redirect) | Integrating external RDS / legacy databases |

Red Flags (DO NOT Say)

  • ❌ “A Service is a separate Nginx container running on each node.” (It is an abstract control plane resource implemented via kernel Netfilter rules).
  • ❌ “You can test if a Service is alive using ping <ClusterIP>.” (ClusterIPs do not respond to ICMP; always test with curl or nc).
  • ❌ “Services inspect HTTP paths and route traffic like an API Gateway.” (Services operate strictly at Layer 4; path/domain routing requires an Ingress or Gateway API).