Pods are ephemeral — they can be created, destroyed, and rescheduled at any time. Their IP addresses change constantly. Services provide a stable network endpoint so that clients can always reach your application, regardless of which pods are running behind it.
The Networking Problem
When you scale a deployment to 3 replicas, you get 3 pods with 3 different IP addresses. Which one should clients connect to? What happens when a pod dies and gets replaced with a new IP?
Services solve this by providing a single, stable IP and DNS name that automatically routes traffic to healthy pods.
Service Types
Kubernetes offers four service types:
| Type | Description | Use Case |
|---|---|---|
| ClusterIP | Internal cluster IP only | Service-to-service communication |
| NodePort | Exposes on each node's IP at a static port | Development, testing |
| LoadBalancer | Provisions an external load balancer | Production traffic from the internet |
| ExternalName | Maps to an external DNS name | Connecting to external services |
ClusterIP Service (Default)
A ClusterIP service is only accessible from within the cluster:
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
type: ClusterIP
selector:
app: api
ports:
- port: 80 # Service port (what clients connect to)
targetPort: 3000 # Container port (where the app listens)
protocol: TCPkubectl apply -f service.yaml
# Other pods can now reach the API at:
# http://api-service (within the same namespace)
# http://api-service.default.svc.cluster.local (fully qualified)
NodePort Service
A NodePort service exposes the application on a port on every node:
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 3000
nodePort: 30080 # Port on every node (30000-32767)Access it at http://<any-node-ip>:30080.
LoadBalancer Service
In cloud environments, a LoadBalancer service provisions an external load balancer:
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 3000kubectl apply -f service.yaml
# Get the external IP
kubectl get service web-service
# NAME TYPE EXTERNAL-IP PORT(S)
# web-service LoadBalancer 203.0.113.10 80:31234/TCPThe cloud provider (AWS, GCP, Azure) creates and manages the load balancer automatically.
Service Discovery with DNS
Kubernetes has a built-in DNS service. Every Service gets a DNS entry:
<service-name>.<namespace>.svc.cluster.local
Within the same namespace, you can use just the service name:
# From a pod in the default namespace
curl http://api-service # Same namespace
curl http://api-service.default # Explicit namespace
curl http://api-service.default.svc.cluster.local # Fully qualified
This means your application code uses service names as hostnames:
// In your application code
const API_URL = "http://api-service:80";
const DB_URL = "postgres://db-service:5432/mydb";
const CACHE_URL = "redis://cache-service:6379";Ingress
An Ingress routes external HTTP/HTTPS traffic to services based on hostnames and paths. It is the standard way to expose web applications:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: admin.myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80Ingress requires an Ingress Controller (like nginx-ingress or traefik) to be installed in the cluster:
# Install nginx ingress controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.0/deploy/static/provider/cloud/deploy.yaml
TLS with Ingress
Secure your services with HTTPS:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.com
secretName: myapp-tls
rules:
- host: myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80With cert-manager installed, TLS certificates are automatically provisioned and renewed from Let's Encrypt.
Network Policies
Network Policies control which pods can communicate with each other. By default, all pods can talk to all other pods. Network Policies add firewall rules:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
# Only allow traffic from the frontend pods
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 3000
egress:
# Allow traffic to the database
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
# Allow DNS
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53This policy ensures the API can only receive traffic from the frontend and can only connect to the database and DNS.
Debugging Networking
# Check service endpoints
kubectl get endpoints api-service
# Test DNS resolution from inside a pod
kubectl run dns-test --image=busybox --rm -it -- nslookup api-service
# Test connectivity from inside a pod
kubectl run curl-test --image=curlimages/curl --rm -it -- curl http://api-service
# View service details
kubectl describe service api-service
# Check if an Ingress has an IP assigned
kubectl get ingress
# View Ingress controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginxComplete Networking Example
Here is a full-stack application with proper networking:
# Frontend Deployment + Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: my-frontend:1.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 80
---
# API Deployment + Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: my-api:1.0
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
value: "postgres://db-service:5432/myapp"
---
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- port: 80
targetPort: 3000Summary
Services provide stable networking for ephemeral pods. ClusterIP handles internal communication, LoadBalancer exposes services externally, and Ingress routes HTTP traffic by hostname and path. Network Policies add security by controlling which pods can communicate. In the next lesson, you will learn about ConfigMaps and Secrets for managing application configuration.