Skip to content

02. Pods, Services, and Ingress — Objects that move traffic

⏱️ Estimated time: 22 min | Level: intermediate

ELI5 callback: Think of a busy shipping port. The dock manager must place every container on the right ship. Heavy ML work needs a cargo crane, and port security keeps lanes and permissions clean.

Pods are the real scheduling unit

Kubernetes schedules pods, not naked containers floating by themselves. A pod gives colocated containers one network identity and one lifecycle. Keep the analogy close. The dock manager reads the manifest, the container carries one workload unit, the ship offers capacity, the cargo crane handles ML-heavy lifts, and port security blocks unsafe access. Simple, no? For most apps, one main container per pod stays easiest to reason about. See. The pod is the deployment atom. Now watch.

pod shape
┌────────────┐    ┌────────────┐    ┌────────────┐
│ spec       │ -> │ pod        │ -> │ ip         │
└─────┬──────┘    └─────┬──────┘    └─────┬──────┘
      │                 │                 │
      v                 v                 v
  resources | containers | identity
One pod gets one IP and one fate.
Containers inside one pod share localhost, volumes, and some lifecycle hooks. A pod is mortal, so replacements usually receive a brand new IP. Never hardcode pod IPs in application configuration or client code. Init containers can prepare data before the main app starts. Pod specs declare env vars, volumes, resources, and health probes. Use sidecars only when tight coupling truly buys you something. So what to do? Keep pods small enough to reschedule quickly during failures. Avoid mixing unrelated processes just because localhost is convenient. Give each pod a clear owner like Deployment or Job. Read pod events first when behavior feels mysterious.

Services give stable networking over changing pods

A Service is a stable routing abstraction over a changing backend set. Labels and selectors decide which pods receive that traffic. ClusterIP is the default internal virtual address for east-west calls. The data plane then translates that virtual address into healthy backends. See. Service first, endpoints second. Now watch.

service flow
┌────────────┐    ┌────────────┐    ┌────────────┐
│ client     │ -> │ service    │ -> │ pods       │
└─────┬──────┘    └─────┬──────┘    └─────┬──────┘
      │                 │                 │
      v                 v                 v
  virtual IP | endpoint set | ready targets
Stable name, changing backends.
A Service is not a process; it is a routing rule. Endpoint lists change as pods pass or fail readiness checks. ClusterIP is perfect for internal APIs and worker communication. Headless services skip VIP load balancing and expose pod identities. DNS names are safer than copying addresses into config files. Readiness controls whether traffic should enter a pod at all. So what to do? Match selectors carefully or traffic disappears with no drama. Name service ports clearly for humans and tooling. Keep protocol expectations explicit between callers and backends. Inspect endpoints when a service looks mysteriously empty.

Ingress adds HTTP entry into the cluster

Ingress handles host and path based HTTP routing from outside. The resource alone does nothing until a controller watches it. That controller configures a reverse proxy or cloud load balancer. Host rules, paths, and TLS settings decide how requests enter. See. YAML alone does not route traffic. Now watch.

north-south path
┌────────────┐    ┌────────────┐    ┌────────────┐
│ internet   │ -> │ ingress    │ -> │ service    │
└─────┬──────┘    └─────┬──────┘    └─────┬──────┘
      │                 │                 │
      v                 v                 v
  DNS + TLS | controller | backend pods
The controller makes the resource real.
Ingress is mainly a Layer 7 HTTP concept, not generic TCP magic. TLS termination may happen at the cloud balancer or controller. One controller can serve many apps with shared policy. Header rewrites, auth filters, and rate limits often live here. Gateway API is the richer modern direction for complex traffic. Still, Ingress remains common and very interview-friendly. So what to do? Do not confuse the Ingress resource with the controller binary. Keep certificate renewal automated instead of manual heroics. Separate public and private entry paths deliberately. Watch 404, 502, and timeout errors hop by hop.

ClusterIP, NodePort, and LoadBalancer solve different problems

ClusterIP stays inside the cluster and is safest by default. NodePort opens the same port on every node in the cluster. LoadBalancer asks the cloud provider to create an external balancer. Exposure choice changes security, cost, and operator pain immediately. See. Pick the smallest exposure that meets the requirement. Now watch.

service types
┌────────────┐    ┌────────────┐    ┌────────────┐
│ clusterip  │ -> │ nodeport   │ -> │ lb         │
└─────┬──────┘    └─────┬──────┘    └─────┬──────┘
      │                 │                 │
      v                 v                 v
  internal only | every node | public front door
More exposure means more blast radius.
ClusterIP fits internal service-to-service traffic almost all the time. NodePort is handy for labs and awkward for polished production. LoadBalancer is standard for public north-south traffic in clouds. NodePort still sits underneath many cloud load balancer implementations. ExternalName simply returns DNS and does not proxy packets. Choose the smallest public surface area that still solves the need. So what to do? Do not make NodePort your default production architecture. Keep firewall rules aligned with service exposure decisions. Budget for public IP and load balancer charges. Validate external health checks from the actual front door.

Debug traffic with sequence, not panic

Most traffic bugs are label mistakes, readiness mistakes, or DNS mistakes. Keep routing layers understandable before adding mesh features on top. Logs, events, endpoints, and ingress status usually reveal the truth. Start from the client and walk one hop at a time. See. Networking needs sequence more than intuition. Now watch.

debug order
┌────────────┐    ┌────────────┐    ┌────────────┐
│ client     │ -> │ dns        │ -> │ backend    │
└─────┬──────┘    └─────┬──────┘    └─────┬──────┘
      │                 │                 │
      v                 v                 v
  name lookup | routing | app response
Check one hop before jumping ahead.
First confirm that the pod is ready and listening. Then confirm the service has the expected endpoints. Then confirm ingress rules match host and path exactly. Finally confirm ACLs, security groups, and balancer health. In interviews, draw only the layers you truly need. Simple routing wins until traffic policy demands more complexity. So what to do? Use curl from inside the cluster to isolate hops. Keep selectors and labels boring and consistent. Prefer one ingress strategy per platform when possible. Document the default request path for every service.

Where this lives in the wild

  • SaaS control planes expose public APIs through ingress and keep internal workers on ClusterIP.
  • E-commerce checkout services use stable service DNS while pods roll underneath.
  • Kubeflow dashboards often sit behind ingress controllers with shared TLS policy.
  • Platform teams standardize labels so service selectors remain predictable across namespaces.

Pause and recall

  1. Why is a pod more than just one container process?
  2. Why do Services exist if pods already have IP addresses?
  3. Why is an Ingress resource useless without a controller?
  4. When would you choose ClusterIP over NodePort or LoadBalancer?

Interview Q&A

Q: Why should clients call a Service name instead of a pod IP? A: Pods are replaced frequently, so their IPs change as health and scheduling change. A Service gives a stable name and backend selection over that churn. Common wrong answer to avoid: “Because Services are faster than pod IPs.”

Q: Why keep one main container per pod for most apps? A: One main process per pod keeps lifecycle, logging, and failure ownership clear. Multiple tightly coupled containers are fine, but they should share a real reason. Common wrong answer to avoid: “Because Kubernetes forbids multiple containers in one pod.”

Q: Why is NodePort rarely the best production entry pattern? A: It opens the same port on every node and pushes more network policy burden onto operators. A managed load balancer or ingress path is usually cleaner and safer. Common wrong answer to avoid: “Because NodePort is deprecated.”

Q: Why do readiness probes matter for Services and Ingress? A: Readiness decides whether a pod should receive live traffic right now. Without it, routing can hit processes that started but are not actually ready. Common wrong answer to avoid: “They are only for dashboards and status pages.”

Apply now (5 min)

Draw one web request from internet to pod using four boxes only. Label where DNS, TLS, service selection, and readiness each appear. Now replace pod IPs mentally and confirm the Service still works. Next, choose ClusterIP, NodePort, or LoadBalancer for the entry path. Finally, list the first three objects you would inspect during a 502.

Bridge. Objects defined. But how do we deploy and scale them? → 03 → 03-deployments-and-scaling.md