Kubernetes Services and Ingress: Types and Routing
Master Kubernetes service types and Ingress controllers to expose your applications inside and outside the cluster with proper load balancing and routing.
Kubernetes Services give changing Pods stable network endpoints, and controllers expose those endpoints to external clients. This guide compares ClusterIP, NodePort, LoadBalancer, headless Services, and HTTP routing, including endpoint discovery, traffic paths, and common production failures. Use its decision tables and checks to choose an exposure model and trace issues from the client to the Pod.
Kubernetes Services and Ingress: Types and Routing
Pods in Kubernetes are ephemeral. They get IP addresses assigned when they start and those addresses change when pods reschedule. If you want your application to be reachable, you need something stable. Kubernetes Services provide that stability by creating a persistent endpoint for a set of pods.
This post covers the four service types, when to use each one, and how Ingress controllers extend routing beyond simple port forwarding.
If you need to understand the basics of Kubernetes first, check the Kubernetes fundamentals post. For advanced networking patterns, see the Advanced Kubernetes post.
Introduction
Pod IPs change when pods reschedule. If your app depends on a fixed address, it breaks constantly. Kubernetes Services give you a stable virtual IP that load-balances across matching pods, which is what makes microservices actually work in practice.
External traffic is a separate problem. Kubernetes gives you four service types and Ingress resources for different exposure patterns. Picking the wrong one costs money (over-provisioned load balancers) or creates weird URLs that users cannot reach. Getting it right means understanding how traffic actually flows from the outside world to your container.
This post covers the four service types, when to use each, and how Ingress controllers add HTTP routing on top. You will see how a request travels from a user to your pod, the trade-offs between each approach, and how to fix the most common networking problems you will hit in production.
Service Types Comparison
Kubernetes offers four service types:
Decision Matrix: Choosing the Right Service Type
| Access Scenario | Service Type | Example |
|---|---|---|
| Internal microservice-to-microservice | ClusterIP | API to database |
| Expose single node for debugging | NodePort | Dev environment access |
| Production HTTP/HTTPS traffic | Ingress | Web app frontend |
| TCP/UDP without Ingress complexity | LoadBalancer | Custom protocol, legacy apps |
| Cross-cluster service discovery | ExternalName | Integrate external service |
Skip NodePort for production HTTP services. The port range (30000-32767) is awkward, and node IPs change in dynamic clusters.
Skip LoadBalancer per microservice. One load balancer per team or product boundary is usually enough. Provisioning a cloud LB for every pod gets expensive fast.
ClusterIP is internal only. If you need external access, ClusterIP is not your answer.
Traffic Flow Architecture
Here is how a request moves from an external user down to a pod:
flowchart TD
User([External user]) --> DNS[DNS]
DNS --> EdgeLB[External endpoint or load balancer]
EdgeLB --> Ingress[Gateway or Ingress controller]
Ingress --> ClusterIP[ClusterIP Service]
ClusterIP --> Pods[Ready backend Pods]
User --> NodePortURL[Node IP and NodePort]
NodePortURL --> NodePortService[NodePort Service]
NodePortService --> Pods
User --> ProviderLB[Provider load balancer]
ProviderLB --> LBService[LoadBalancer Service]
LBService --> Pods
These are alternative exposure paths. An HTTP route commonly reaches a Gateway or Ingress controller, then a ClusterIP Service; a provider load balancer may be one way to expose that controller.
NodePort and a LoadBalancer Service expose a Service through different mechanisms. Their exact data paths depend on the cluster’s service proxy and cloud integration.
Service Types Overview
| Type | Access Scope | Use Case |
|---|---|---|
| ClusterIP | Internal only | Microservices within the cluster |
| NodePort | Exposes on each node IP | Development, simple external access |
| LoadBalancer | External via cloud LB | Production external access |
| ExternalName | Maps to external DNS | Integrating external services |
ClusterIP is the default. You get an internal cluster IP that pods can use to communicate with each other. The other types expose services outside the cluster.
ClusterIP for Internal Access
ClusterIP is the most common service type. It creates an internal IP that load-balances traffic across all matching pods. Other pods in the cluster use the service name to reach your application.
apiVersion: v1
kind: Service
metadata:
name: api-backend
namespace: production
spec:
type: ClusterIP
selector:
app: api-backend
version: v2
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
- name: grpc
protocol: TCP
port: 50051
targetPort: 50051
The targetPort can be a number or a name that matches the container port. Using names makes it easier to update ports without changing the service.
Within the cluster, pods access the service using its fully qualified name:
http://api-backend.production.svc.cluster.local
Or just the service name if they are in the same namespace:
http://api-backend
DNS is automatic. Kubernetes maintains a DNS entry for every service.
Headless Services for StatefulSets
Set clusterIP: None to create a headless service. Instead of load balancing, DNS returns the pod IPs directly. This is useful for StatefulSets where clients need to discover individual pod addresses.
apiVersion: v1
kind: Service
metadata:
name: postgres-cluster
namespace: database
spec:
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
With a headless service, DNS queries return A records for each pod: postgres-cluster-0.postgres-cluster.database.svc.cluster.local, and so on.
NodePort for Development
NodePort opens a port on every node in the cluster. Traffic arriving at http://<node-ip>:<node-port> gets routed to the service. The port range defaults to 30000-32767.
apiVersion: v1
kind: Service
metadata:
name: web-frontend-nodeport
spec:
type: NodePort
selector:
app: web-frontend
ports:
- port: 80
targetPort: 80
nodePort: 30080
Setting nodePort is optional. Kubernetes assigns one from the default range if you omit it.
NodePort is useful for development and for implementations that need node-level targets. It opens a high port on nodes and does not provide host- or path-based HTTP routing by itself; external load balancing and firewall behavior depend on the surrounding infrastructure.
LoadBalancer with Cloud Controllers
On a cluster with a compatible load balancer implementation, type: LoadBalancer requests an external load balancer for the Service. Target type, health checks, supported protocols, and TLS termination depend on the controller and provider.
apiVersion: v1
kind: Service
metadata:
name: web-frontend-lb
namespace: production
spec:
type: LoadBalancer
selector:
app: web-frontend
ports:
- port: 80
targetPort: 80
- port: 443
targetPort: 443
For example, the AWS Load Balancer Controller can select an NLB with spec.loadBalancerClass: service.k8s.aws/nlb or controller-specific annotations, and target mode determines whether it registers nodes or Pod IPs. Health checks and source-IP behavior depend on that mode and its target-group settings. Do not copy provider annotations between controllers; check the AWS Load Balancer Controller annotation reference.
With the AWS Load Balancer Controller, an NLB TLS listener can use a certificate ARN and an explicit TLS port, for example:
annotations:
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-east-1:123456789:certificate/abc123"
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
Ingress Controllers and Rules
Ingress is not a Service type. It is a Kubernetes API for HTTP/HTTPS routing rules, and an Ingress controller implements them. The Ingress API remains stable but is frozen; Kubernetes recommends Gateway API for new designs. The community ingress-nginx controller retired in March 2026, so the NGINX annotations below are legacy examples for understanding existing configurations, not a recommendation for new deployments. Controller annotations are implementation-specific.
See the Kubernetes Ingress documentation and Gateway API documentation when choosing a current controller and API. The Kubernetes ingress-nginx retirement notice explains the March 2026 end of community maintenance.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
namespace: production
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: users-api
port:
number: 80
- path: /products
pathType: Prefix
backend:
service:
name: products-api
port:
number: 80
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-console
port:
number: 80
tls:
- hosts:
- api.example.com
- admin.example.com
secretName: example-com-tls
The ingressClassName field specifies which controller handles the Ingress. Check that the selected controller is supported and that its behavior matches the API features your routes use.
Path rewriting
Backend services rarely expose the same path structure as your Ingress routes. A frontend at example.com/users might proxy to an API that expects /users at its root. Without path rewriting, requests to /api/v1/users arrive at the backend as /api/v1/users, and the backend returns 404 because it only knows about /users.
For an existing community ingress-nginx deployment, path rewriting uses controller-specific annotations. New deployments should use a supported controller or Gateway API implementation.
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
The $2 holds the second captured group from a regex path. Pair it with use-regex: "true" and pathType: ImplementationSpecific:
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /api/v1(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: users-api
port:
number: 80
Requests to /api/v1/users hit the backend as /users. Requests to /api/v1/products/42 hit the backend as /products/42. The regex (.*) passes everything after /api/v1/ as-is, preserving query strings and nested paths.
This pattern shows up constantly when migrating from a monolith. You can route /api/v2/* to the new service and /legacy/* to the old one, rewriting paths to match whatever contract each backend expects.
Rate limiting with legacy ingress-nginx annotations
Rate limiting is controller-specific. In existing community ingress-nginx deployments, limit-rps limits requests per second and limit-connections limits concurrent connections per client IP, per controller replica. The project retired in March 2026, so do not start a new deployment on these annotations.
annotations:
nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-connections: "5"
These limits are calculated per controller replica, so adding replicas increases the effective per-client allowance. Exceeding a request or connection limit returns 503 by default; the controller’s limit-req-status-code setting can change the response code. Do not assume the response includes Retry-After. A 503 can also indicate an upstream failure, so correlate it with controller metrics and logs.
The limit-burst-multiplier annotation changes the burst size as a multiplier of the configured request rate; the default multiplier is 5. It is not a fixed number of extra requests, so calculate the effective burst from the RPS setting and test the chosen policy under expected traffic.
The client address comes from the controller’s trusted proxy configuration. Clients behind the same NAT may share one limit. Scope these annotations to the appropriate Ingress resource; for identity-based limits, use a supported gateway or rate-limiting service that authenticates the identity.
Security Considerations
Services enable connectivity, but you should restrict which pods can communicate with which. Kubernetes Network Policies (covered in a separate post) let you enforce microsegmentation between pods.
For HTTP/HTTPS exposure, use a supported Gateway API implementation or an existing Ingress controller with TLS where it fits your platform. Both depend on a controller for routing and certificate handling; NodePort alone does not provide those features.
Avoid creating a separate LoadBalancer for every HTTP Service without checking cost, isolation, and provider capabilities. A shared Gateway or Ingress controller may consolidate entry points, while separate load balancers can be appropriate for protocol support, isolation, or ownership boundaries.
Observability Checklist
Check the service path from the cluster edge to the selected pods, not just whether the Service object exists:
- Confirm the Service selector matches the intended pods and its EndpointSlices contain ready endpoints.
- Watch request rate, latency, and error rate at the Ingress or load balancer and at the backend.
- Alert on sustained 5xx responses, connection failures, and backends with no ready endpoints.
- Track load balancer provisioning events and cloud quota or health-check failures.
- Check DNS resolution and service discovery after pod rescheduling or rollout.
Security and Compliance Notes
Expose only the services that need external access. Use standard ports and TLS at the ingress boundary, then apply NetworkPolicy or another supported control to limit pod-to-pod paths. Keep administrative endpoints private and avoid relying on an obscure NodePort as an access control.
For regulated workloads, record which services handle sensitive data, where TLS terminates, and which identities can reach each backend. Review load balancer and ingress rules alongside Kubernetes policies; a cluster-level policy does not automatically cover traffic filtered before it reaches a pod. Map these settings to the applicable audit requirements and retain evidence of periodic review. The configuration supports compliance work but does not certify the environment by itself.
Trade-off Analysis
ClusterIP vs Headless Services
The difference between ClusterIP and headless comes down to who manages pod discovery. With ClusterIP, Kubernetes gives you a stable virtual IP and load-balances traffic across all matching pods. Your client hits one address and Kubernetes handles the rest. With headless (clusterIP: None), there is no virtual IP. DNS returns individual pod A records instead, and your client is responsible for tracking which pods exist and picking one.
| Aspect | ClusterIP | Headless (ClusterIP: None) |
|---|---|---|
| Endpoint selection | Service proxy chooses ready endpoints (implementation-specific) | Clients resolve and select pod addresses |
| DNS resolution | Single service IP | Multiple A records (one per pod) |
| Use case | Stateless microservices | StatefulSets, leader election |
| Client complexity | Low | High |
For stateless services, ClusterIP is almost always the right choice. Your client does not need to know which pod is which. For StatefulSets, headless is necessary because pods have stable identities — a PostgreSQL replica needs to know it is connecting to postgres-cluster-1, not just any available pod. The client also needs to track which pod is primary for writes versus read-only replicas.
With ClusterIP, clients reconnect to the Service IP and the cluster’s service proxy selects an eligible endpoint. With headless, clients must handle DNS changes and choose among pod addresses; application-level leader election remains the workload’s responsibility. Use headless discovery when clients need per-pod identity.
Service Type Selection Trade-offs
Each service type maps to a specific access pattern. Pick the wrong one and you either limit your traffic or pay for something you do not need.
| Exposure model | Pros | Cons or considerations |
|---|---|---|
| ClusterIP | Internal Service address | Not externally routable by default |
| NodePort | Works without a cloud load balancer | High port on nodes; external routing is separate |
| LoadBalancer | Requests provider-managed external access | Cost and behavior vary by implementation |
| Ingress | HTTP host/path routing | Requires a supported controller; API is frozen |
| Gateway API | Extensible, role-oriented routing API | Requires Gateway API CRDs and an implementation |
ClusterIP is the usual choice for internal traffic: API to database, frontend to backend, worker to queue. Its virtual IP is routable within the cluster by default; use network controls for isolation.
NodePort exposes a high port on each node and is often used as a target behind another load balancer. It does not provide HTTP host/path routing by itself; whether it fits production depends on the external routing and firewall design.
Use a LoadBalancer Service when the provider integration or protocol needs a dedicated external listener. For HTTP/HTTPS, an Ingress or Gateway implementation can share routing infrastructure, but account for its availability and capacity as a shared dependency.
Ingress controllers route HTTP/HTTPS by host and path. Gateway API is the recommended direction for new Kubernetes routing designs; the choice of implementation determines TLS handling, sharing, and operations.
Ingress vs LoadBalancer per Service
Sharing an HTTP entry point can reduce load balancer count, but compare cost and quota with the operational impact of a shared controller.
| Criteria | Ingress Controller | One LoadBalancer per Service |
|---|---|---|
| Cost | Shared infrastructure costs | Separate infrastructure costs |
| SSL management | Centralized | Per-service or per-LB |
| HTTP/HTTPS routing | Path-based, host-based | Port-based only |
| Operational overhead | Controller deployment | Cloud quota management |
Provider quotas and prices vary by account, region, load balancer type, and traffic. Check current limits and pricing for your environment rather than planning around fixed examples. A shared controller can reduce frontend resources, but it also becomes a shared failure and capacity boundary.
SSL management is simpler with Ingress too. You store one certificate per hostname and the controller terminates TLS for every backend service behind it. With per-service LBs, you either terminate SSL at the LB (each one needs its own certificate) or at the backend (each service handles its own certs, more operational work).
Dedicated load balancers can make sense for non-HTTP protocols, static addressing, or isolation requirements. Kubernetes Service type alone does not guarantee a particular layer or feature set; check the controller’s supported protocols and routing model.
For new HTTP/HTTPS designs, evaluate a supported Gateway API implementation as well as existing Ingress options. Compare resource cost, controller support, failure isolation, and migration needs.
Production Failure Scenarios
ClusterIP Service Not Reachable After Pod Restart
When a pod restarts, its IP changes. If your application hardcodes pod IPs instead of using the ClusterIP service name, communication breaks.
Symptoms: Pod-to-pod communication fails after restarts, Connection refused errors.
Diagnosis:
kubectl get pod -o wide # Check pod IPs
kubectl get endpointslices -n <namespace> -l kubernetes.io/service-name=<service-name>
kubectl describe pod <pod-name> # Check status
Mitigation: Always use the ClusterIP service DNS name for pod-to-pod communication, never pod IPs.
NodePort Service Port Conflicts
When two services request the same nodePort value, Kubernetes rejects the second one with nodePort port is already allocated. This sneaks into clusters through hardcoded ports in Helm charts or kustomization overlays that nobody validated against existing allocations. In GitOps workflows, the conflict only shows up at apply time, not at render time, so code review misses it.
To diagnose an active conflict, filter services by nodePort in the 30000-32767 range:
kubectl get svc -A -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.type}{"\t"}{.spec.ports[*].nodePort}{"\n"}{end}' | grep -v '<none>'
The output lists every service with an assigned nodePort. When provisioning a new service, pick a free port or omit nodePort entirely and let Kubernetes assign one. Conflicts only happen when two manifests hardcode the same value.
Prevention across teams requires a shared allocation record. Some teams keep a ConfigMap with reserved ports and owners. Others skip NodePort entirely and use LoadBalancer or Ingress, which removes manual port management from the picture. If you run NodePort in a multi-tenant cluster, treat nodePort allocations like ephemeral port ranges: assign them centrally and never hardcode them in definitions that migrate between environments.
LoadBalancer Service Stays Pending
On cloud providers, LoadBalancer provisioning can fail due to quota limits, missing IAM permissions, or unsupported service configurations.
Symptoms: the Service’s EXTERNAL-IP remains <pending> or events show provisioning errors.
Diagnosis:
kubectl describe service <name> -n <namespace>
# Check events for error messages
kubectl get events --sort-by='.lastTimestamp' -n <namespace>
Mitigation: Check events, controller logs, permissions, quotas, and the provider-specific Service configuration. Confirm which controller owns the Service before changing annotations.
Common Pitfalls / Anti-Patterns
Exposing Services Directly Without Ingress
Do not create a separate external load balancer for every HTTP Service without checking current cost and quota. A shared Gateway or Ingress can reduce frontend resources, but it also concentrates capacity and failure risk. Keep separate entry points where protocol support, isolation, addressability, or ownership requires them, and verify current provider pricing and limits.
Using NodePort in Production
NodePort allocates a port from a fixed range (30000-32767) on every node in the cluster. When a pod receives traffic, kube-proxy routes it from that high port to the target pod. This sounds convenient for dev environments, but the model breaks down in production for several reasons.
The port range itself is the first problem. Standard HTTP is 80 or 443. Users hitting https://example.com:31234 see a port that looks like a VPN or proxy. Corporate firewalls routinely block non-standard ports, dropping traffic silently before it reaches your cluster. In regulated industries with strict outbound policies, high ports may be blocked entirely.
Node IP stability is the second problem. In managed Kubernetes (EKS, GKE, AKS), nodes live in an auto-scaling group. When scale-in events occur, terminated nodes return their IPs to the VPC pool and new nodes pick up different ones. Your NodePort service still exposes port 30080 on the new IPs, but any DNS records or firewall rules pointing to old node IPs go stale. You either maintain a dynamic discovery layer or accept intermittent outages during node churn.
Security is the third concern. Opening a port on every node means your service is reachable from anywhere in the cluster network. If nodes share a subnet with other workloads, a compromised pod can hit the NodePort directly, bypassing your Ingress controller’s authentication layer entirely. ClusterIP and Ingress shrink this attack surface by only exposing services through explicitly routed paths.
For local development, NodePort is fine. For anything beyond a quick demo, use Ingress with a proper HTTP/HTTPS stack or a LoadBalancer for TCP services. The routing clarity, SSL termination, and firewall-friendliness of standard ports justifies the extra setup time.
Skipping Health Checks on Headless Services
StatefulSets give pods stable identities: postgres-0 is always the primary, postgres-1 and postgres-2 are replicas. Clients querying the headless service DNS get all pod IPs and must pick one. Without health checks, clients can try to write to a pod that is still replaying WAL segments, causing failed queries, split-brain, or worse depending on the database.
Use a readinessProbe that reflects whether the pod can serve its intended role. Without one, Kubernetes can consider a container ready once it is running, even if database recovery is unfinished. A simple SELECT 1 only confirms that PostgreSQL accepts a query; it does not establish that a replica is caught up or that a pod is the write leader. Headless Service DNS normally follows endpoint readiness unless publishNotReadyAddresses changes that behavior.
spec:
containers:
- name: postgres
readinessProbe:
exec:
command:
- sh
- -c
- "psql -h localhost -U postgres -c 'SELECT 1' -q"
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
failureThreshold: 3 requires three consecutive probe failures before the probe reports failure; the probe period and timeout determine the delay. Tune readiness to the database recovery process and avoid overly aggressive checks that make endpoints flap.
Liveness probes serve a different purpose: they restart a container when it is stuck, not when it is merely unready. Do not use max_connections or statement_timeout as restart or failover controls; database high availability and recovery need their own mechanisms.
Quick Recap Checklist
- Confirm the Service type fits the access pattern, and trace traffic from the client through the load balancer or Ingress to the backend pods.
- Check the Service selector and EndpointSlices to confirm they list the intended, ready pod endpoints.
- Verify that an Ingress controller is running for HTTP/HTTPS routing; use a Service to expose the backend it routes to.
- Check pod readiness probes and health-check results so unready pods do not receive traffic.
- Review NetworkPolicy rules in both directions to confirm the client, Ingress controller, and backend are allowed to communicate.
Interview Questions
Expected answer points:
- ClusterIP provides internal-only access within the cluster — only other pods can reach it
- NodePort exposes the service on a high port (30000-32767) on every node's IP — useful for dev but not production HTTP
- LoadBalancer provisions an external cloud load balancer (AWS ELB, GCP LB, Azure LB) for production external access
- Ingress is not a service type but a routing layer for HTTP/HTTPS with host and path-based rules
Expected answer points:
- The cluster's service proxy watches Services and their EndpointSlices; some network implementations provide a replacement for kube-proxy.
- The proxy implements the virtual Service IP using its supported dataplane, such as iptables, nftables, IPVS, or an integrated eBPF implementation.
- Endpoint selection and connection behavior depend on that implementation; do not assume round-robin or random selection.
- When ready endpoints change, the control plane updates EndpointSlices and the dataplane converges.
Expected answer points:
- A headless service is created by setting `clusterIP: None`
- No ClusterIP is assigned — DNS returns individual pod A records instead
- Clients can discover pod IPs directly for StatefulSet workloads where each pod needs a stable identity
- Useful for leader election, master-slave database setups, and scenarios requiring direct pod-to-pod communication
Expected answer points:
- targetPort specifies the port on the pod that receives traffic
- It can be a number or a named port matching the container's port definition
- Using named ports makes updates easier — changing the container port does not require changing the service
- If omitted, targetPort defaults to the `port` value
Expected answer points:
- NodePort uses a non-standard port range (30000-32767) that is not typical for end users
- Node IPs are dynamic in managed clusters — using them requires additional discovery or stable host entries
- No HTTP host/path routing or centralized TLS termination by NodePort itself
- External load balancing and traffic policy must be configured separately
Expected answer points:
- Ingress is a Kubernetes resource; an Ingress controller is the implementation that acts on it
- Ingress provides HTTP/HTTPS host and path rules; the Ingress API is frozen, and Kubernetes recommends Gateway API for new designs
- A Service of type LoadBalancer requests an external load balancer; supported protocols and features depend on its provider/controller
- A shared Gateway or Ingress controller can route to multiple Services, trading fewer frontends for a shared capacity and failure boundary
Expected answer points:
- Annotations are controller-specific. With AWS Load Balancer Controller, `service.beta.kubernetes.io/aws-load-balancer-type: "external"` is used in annotation-based controller selection; supported setups may instead select it with `spec.loadBalancerClass`.
- `service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"` registers Pod IPs as NLB targets when the cluster networking supports it; `instance` targets nodes.
- `service.beta.kubernetes.io/aws-load-balancer-ssl-cert` and `...aws-load-balancer-ssl-ports` configure certificate-backed TLS listeners when supported by that controller.
- Confirm current annotation names and defaults in the documentation for the installed controller and version.
Expected answer points:
- The EndpointSlice controller removes or marks the endpoint unready, and the service proxy updates its dataplane.
- In-flight requests may fail or reset; graceful termination and connection draining affect the result.
- New connections are sent to remaining ready endpoints after the dataplane converges.
- Clients should handle transient failures safely, with bounded retries for operations that are safe to repeat.
Expected answer points:
- `None` is the default; backend selection is handled by the cluster's service proxy.
- `ClientIP` asks the proxy to keep connections from the same client IP on the same endpoint for the configured timeout.
- This can help protocols that need connection affinity, but clients behind a shared NAT may map to the same affinity key.
- Affinity is not application session state and cannot guarantee an endpoint remains available.
Expected answer points:
- Services do not provide fine-grained traffic control (canary releases, traffic splitting)
- No built-in circuit breaking, retry policies, or rate limiting at the service mesh level
- NetworkPolicies provide L3/L4 isolation but not L7 traffic management
- Service mesh solutions (Istio, Linkerd) extend Services with L7 control, mTLS, and observability
Expected answer points:
- List current EndpointSlices: `kubectl get endpointslices -n
-l kubernetes.io/service-name= ` and check ready addresses. - Check pod selector labels match: `kubectl describe service
` shows selector - Verify pods are running and ready: `kubectl get pods -l app=
` - Check the service proxy or CNI dataplane logs and rules for programming issues
- Test connectivity from another pod using the service DNS name
Expected answer points:
- ClusterIP is routable within the cluster network by default.
- LoadBalancer asks a compatible provider/controller to provision external access to the Service.
- External address, target mode, protocols, and cost depend on the implementation.
- Use ingress or Gateway routing for HTTP paths when its supported features and operational model fit.
Expected answer points:
- Yes — an Ingress spec can contain multiple `rules` entries, each with a different `host`
- Each host can have its own set of paths routing to different backend services
- A single TLS block can cover multiple hosts via multiple entries in the `hosts` list
- Wildcard hosts (e.g., `*.example.com`) match one DNS label below `example.com`; they do not match the apex or multiple nested labels
Expected answer points:
- Exact match: URL path must match the path string exactly (e.g., `/users` matches only `/users`)
- Prefix match: URL path must have the prefix at the start (e.g., `/users` matches `/users`, `/users/123`, `/users/foo/bar`)
- `pathType` is required in the stable Ingress API. `Prefix` is explicit and matches path elements, not arbitrary string prefixes.
- Exact is useful when you need strict path boundaries and no unintended prefix matching
Expected answer points:
- List EndpointSlices in the Service namespace using the `kubernetes.io/service-name` label.
- Inspect endpoint addresses and their readiness conditions rather than relying only on pod phase.
- Check that the Service selector matches the intended pod labels and that readiness probes pass.
- The legacy Endpoints API is deprecated; use EndpointSlices for current tooling.
Expected answer points:
- `Local` limits Service forwarding to node-local endpoints and avoids source NAT by the Kubernetes Service proxy on that path.
- The external load balancer must health-check or target nodes that have ready local endpoints; integration behavior varies.
- Uneven pod placement can create uneven traffic or leave nodes without usable local endpoints.
- Verify client-IP behavior end to end with the chosen load balancer and target mode before relying on it for logs or policy.
Expected answer points:
- Pod `readinessProbe` controls whether the Pod is considered ready for Service endpoints; a failed readiness probe does not restart the container.
- `livenessProbe` can trigger a container restart after repeated failures; it should detect a stuck process, not ordinary load.
- Provider load balancer health checks are configured separately through the relevant controller or provider integration.
- Probe types include `exec`, `httpGet`, and `tcpSocket`; choose checks that test the condition needed for traffic.
Expected answer points:
- EndpointSlices represent Service endpoints in separate resources so updates can scale without one large Endpoints object.
- The control plane creates up to 100 endpoints per slice by default; this limit is configurable up to 1000.
- Endpoint data can include fields such as hostname, node name, zone, and routing hints where populated.
- The legacy Endpoints API was deprecated in Kubernetes v1.33; service proxies consume EndpointSlices as their endpoint source.
Expected answer points:
- The annotation specifies that the NLB should route directly to pod IPs (IP target) rather than node IPs (instance target)
- IP target mode routes directly to Pod IPs and avoids an extra node hop.
- Client source-IP preservation is not guaranteed by IP target mode; AWS NLB IP targets disable it by default unless configured through target-group attributes.
- Confirm address-family, CNI, health-check, and target-group requirements in the installed AWS Load Balancer Controller documentation.
- This mode requires the AWS VPC CNI plugin and works with pods that have ENIs attached in the VPC subnet
Expected answer points:
- CoreDNS creates A records for ClusterIP services: `
. .svc.cluster.local` resolves to the ClusterIP - For headless services (`clusterIP: None`), DNS returns addresses for eligible Pod endpoints; readiness and `publishNotReadyAddresses` affect which endpoints are published
- SRV records are created for named ports: `
. . .svc.cluster.local` - ExternalName services create CNAME records pointing to the external FQDN specified
Further Reading
- Kubernetes Official Documentation - Services
- Ingress Controllers
- Network Policies
- Cloud Load Balancer Integration
Conclusion
Kubernetes Services provide stable endpoints for applications as Pods change. ClusterIP supports in-cluster access, while NodePort and LoadBalancer expose traffic through different network paths whose details depend on the cluster and provider. Ingress remains a stable but frozen API; Kubernetes recommends Gateway API for new HTTP/HTTPS routing designs.
Start with ClusterIP for internal traffic. For external HTTP/HTTPS access, select a supported Gateway API implementation or maintain an existing Ingress controller based on its lifecycle and capabilities. Choose LoadBalancer when its provider-specific behavior, protocol support, or isolation fits the service.
Understanding these networking primitives helps you design services that are reachable, scalable, and secure. For deeper Kubernetes networking concepts like Network Policies, see the Advanced Kubernetes post.
Category
Related Posts
Kubernetes Network Policies: Practical Pod Security
Implement microsegmentation in Kubernetes using Network Policies to control traffic flow between pods and enforce zero-trust networking.
Cloud Security: IAM, Network Isolation, and Encryption
Implement defense-in-depth security for cloud infrastructure—identity and access management, network isolation, encryption, and security monitoring.
Container Security: Image Scanning and Vulnerability Management
Implement comprehensive container security: from scanning images for vulnerabilities to runtime security monitoring and secrets protection.