Skip to main content

Services & Networking

Pods are ephemeral β€” they come and go with new IPs each time. A Service gives you a stable endpoint to reach them.


Why Services Exist

Kubernetes Workload Controllers, Services & Storage CSI Architecture
SELECT SERVICE ROUTING TYPE:
ClusterIP (Internal Only)
NodePort (Host Port Binding)
LoadBalancer (Cloud Provider)
Ingress Controller (L7 HTTP Router)
Networking & Service Traffic Flow
Ingress Controller (L7 HTTP Router)

Manages external L7 HTTP/HTTPS routing rules, TLS termination, and path-based routing (/api βž” service-a, /app βž” service-b).


Service Types

1. ClusterIP (Default)

Internal-only. Accessible only within the cluster.

apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
type: ClusterIP # Default β€” can omit
selector:
app: my-api # Route to Pods with this label
ports:
- name: http
port: 80 # Service port (what clients connect to)
targetPort: 8080 # Container port (what the Pod listens on)
protocol: TCP
- name: management
port: 9090
targetPort: 9090
Inside cluster:
curl http://my-api # Resolves via DNS β†’ ClusterIP
curl http://my-api:80 # Explicit port
curl http://my-api.default.svc.cluster.local # Fully qualified

2. NodePort

Exposes service on each Node's IP at a static port (30000–32767).

apiVersion: v1
kind: Service
metadata:
name: my-api-nodeport
spec:
type: NodePort
selector:
app: my-api
ports:
- port: 80 # ClusterIP port
targetPort: 8080 # Container port
nodePort: 30080 # Port on every Node (omit for random)
Traffic flow:
External β†’ NodeIP:30080 β†’ ClusterIP:80 β†’ Pod:8080

Use case: Development, on-premise without cloud load balancer. Rarely used in production cloud deployments.


3. LoadBalancer

Provisions a cloud load balancer. Most common for production.

apiVersion: v1
kind: Service
metadata:
name: my-api-lb
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb" # AWS NLB
service.beta.kubernetes.io/aws-load-balancer-internal: "false"
spec:
type: LoadBalancer
selector:
app: my-api
ports:
- port: 80
targetPort: 8080
Traffic flow:
Internet β†’ AWS ALB/NLB (external IP) β†’ NodePort β†’ Pod:8080

Problem with LoadBalancer: One external IP / load balancer per service = expensive and complex. Use Ingress for HTTP traffic instead.


4. ExternalName

Maps a service to an external DNS name. No proxying β€” just DNS CNAME.

apiVersion: v1
kind: Service
metadata:
name: my-database
spec:
type: ExternalName
externalName: mydb.rds.amazonaws.com # External hostname
Inside cluster:
jdbc:postgresql://my-database:5432/mydb
β†’ resolves to mydb.rds.amazonaws.com via DNS

Use case: Reference external services (RDS, ElastiCache) from within the cluster using Kubernetes DNS names.


5. Headless Service

No ClusterIP β€” direct Pod IPs returned by DNS. Used by StatefulSets.

apiVersion: v1
kind: Service
metadata:
name: postgres-headless
spec:
clusterIP: None # ← headless
selector:
app: postgres
ports:
- port: 5432
DNS lookup for postgres-headless returns ALL Pod IPs:
nslookup postgres-headless β†’ 10.244.1.1, 10.244.2.1, 10.244.3.1

StatefulSet Pods get individual DNS:
postgres-0.postgres-headless.default.svc.cluster.local β†’ 10.244.1.1

Ingress

HTTP/HTTPS routing into the cluster from outside. One LoadBalancer handles all HTTP services.

Without Ingress: With Ingress:
/api β†’ LoadBalancer #1 One LoadBalancer
/web β†’ LoadBalancer #2 β†’ Ingress Controller
/docs β†’ LoadBalancer #3 β†’ Routes by path/host
Cost: 3Γ— load balancers Cost: 1 load balancer

Ingress Resource

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod" # Auto TLS cert

spec:
ingressClassName: nginx # Which Ingress Controller to use

# TLS
tls:
- hosts:
- api.example.com
- www.example.com
secretName: my-tls-secret # Certificate stored as Secret

# Routing rules
rules:
# Route by host
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-v1-svc
port:
number: 80

- path: /v2
pathType: Prefix
backend:
service:
name: api-v2-svc
port:
number: 80

- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80

Path Types

TypeBehaviour
ExactExactly matches /foo β€” not /foo/ or /foo/bar
PrefixMatches /foo and /foo/bar and /foo/baz
ImplementationSpecificController-defined
ControllerNotes
nginxMost common. kubectl apply -f ingress-nginx.yaml
TraefikDynamic config, auto-discovers services
AWS ALBNative AWS integration (aws-load-balancer-controller)
GCENative GKE integration
IstioFull service mesh with gateway
# Install nginx ingress controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml

# Check Ingress status
kubectl get ingress
kubectl describe ingress my-ingress

Gateway API (The Modern Standard)

Ingress is legacy. The modern standard for Kubernetes traffic routing is the Gateway API. It separates concerns so infrastructure providers manage the Gateway, while application developers manage the Routes.

Ingress (Legacy):
Single object mixing L4/L7 routing, TLS, and infrastructure setup.

Gateway API (Modern):
GatewayClass β†’ Describes infrastructure (e.g., AWS ALB, Istio)
Gateway β†’ Provisions the Loadbalancer / IP
HTTPRoute β†’ Developer specifies routing logic

HTTPRoute Example

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: production
spec:
parentRefs:
- name: my-gateway # Attach to infrastructure gateway
rules:
- matches:
- path:
type: PathPrefix
value: /api/v2
backendRefs:
- name: api-v2-svc
port: 8080
weight: 90 # Canary rollouts natively supported!
- name: api-v2-canary
port: 8080
weight: 10

Why it's better: Supports header matching, traffic splitting (canary deploys), cross-namespace routing, and generic L4/L7 routing natively without using non-standard annotations.


Kubernetes DNS

Every Service gets a DNS entry: <service>.<namespace>.svc.cluster.local

Service: my-api in namespace: production

Full name: my-api.production.svc.cluster.local
Short name: my-api.production (from other namespaces)
Shortest: my-api (within same namespace)
# Test DNS from inside a Pod
kubectl run -it --rm dns-test --image=busybox --restart=Never -- sh
$ nslookup my-api
$ nslookup my-api.production.svc.cluster.local
$ nslookup kubernetes.default.svc.cluster.local

CoreDNS

Kubernetes uses CoreDNS as its cluster DNS server. Runs as a Deployment in kube-system.

kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get configmap coredns -n kube-system -o yaml # CoreDNS config

Network Policy

Controls which Pods can communicate with each other. Default: all traffic allowed.

# Deny ALL ingress to "api" Pods β€” then explicitly allow needed traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
spec:
podSelector:
matchLabels:
app: my-api # Apply to Pods labeled app=my-api

policyTypes:
- Ingress
- Egress

ingress:
# Allow traffic from nginx ingress controller
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 8080

# Allow monitoring from Prometheus
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- port: 9090

egress:
# Allow outbound to postgres
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- port: 5432

# Allow DNS
- to:
- namespaceSelector: {}
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP

⚠ NetworkPolicy requires a CNI plugin that supports it: Calico, Cilium, WeaveNet. Flannel does NOT support NetworkPolicy.


Traffic Flow: Internet to Pod

1. User β†’ DNS β†’ myapp.example.com β†’ External IP
2. External IP β†’ Cloud Load Balancer (AWS ALB)
3. ALB β†’ Kubernetes NodePort (30080) on any Node
4. Node iptables/IPVS β†’ kube-proxy rules β†’ Service ClusterIP
5. ClusterIP β†’ load balanced to one of the backing Pods
6. Pod β†’ Container listening on port 8080

In full:
User β†’ ALB:443 β†’ NodePort:30443 β†’ Service:443 β†’ Pod:8080

Service Discovery Pattern for Spring Boot

# application.yml in Kubernetes
spring:
datasource:
url: jdbc:postgresql://postgres-svc.production.svc.cluster.local:5432/mydb
# OR short name (same namespace):
url: jdbc:postgresql://postgres-svc:5432/mydb
data:
redis:
host: redis-svc # K8s Service name as hostname
port: 6379

Interview Questions

  1. What is a Kubernetes Service and why is it needed?
  2. What are the four Service types? When would you use each?
  3. What is the difference between a ClusterIP and a LoadBalancer service?
  4. What is an Ingress and why is it preferable to multiple LoadBalancer services?
  5. How does Kubernetes DNS work? What is the format of a fully qualified service name?
  6. What is a headless Service and why do StatefulSets use them?
  7. What is a NetworkPolicy? What is the default behaviour without one?
  8. Trace the path of an HTTP request from a user's browser to a container running in Kubernetes.
  9. What is an Ingress Controller and how does it relate to the Ingress resource?
  10. What CNI plugin do you need for NetworkPolicy to work?
πŸ“–
Track Page Progress0 / 635 Read
Knowledge Base Completion0%