Kubernetes Complete Guide 2025 — From Zero to Production Clusters
Advertisement
Introduction
Why This Matters
Docker answers "how do I run a container?" Kubernetes answers "how do I run hundreds of containers reliably across a fleet of servers?" It provides self-healing (restarts failed containers), horizontal scaling (adds pods under load), rolling updates (zero-downtime deploys), and service discovery (containers find each other without hardcoded IPs).
In 2025, Kubernetes runs the majority of production container workloads at companies of all sizes. AWS EKS, Google GKE, and Azure AKS are fully managed Kubernetes services used by millions of engineers. Kubernetes knowledge is one of the most consistently high-paying skills in DevOps, and the Certified Kubernetes Administrator (CKA) and Certified Kubernetes Application Developer (CKAD) certifications are widely recognized.
This guide covers Kubernetes architecture, core resources, and the operations knowledge needed to deploy and manage real applications.
Kubernetes Architecture
A Kubernetes cluster has two planes: the control plane (manages the cluster) and worker nodes (run workloads).
Control Plane components:
kube-apiserver— REST API gateway; all kubectl commands go hereetcd— distributed key-value store; all cluster state stored herekube-scheduler— assigns Pods to worker nodes based on resources and constraintskube-controller-manager— reconciliation loops that drive actual state toward desired state
Worker Node components:
kubelet— agent that runs on each node, receives Pod specs, manages containerskube-proxy— handles network rules for Service IP routingcontainer runtime— containerd or CRI-O (actually runs containers)
Setting Up a Local Cluster
# Option 1: kind (Kubernetes in Docker) — fastest for CI and dev
brew install kind
kind create cluster --name dev
kubectl cluster-info --context kind-dev
# Option 2: minikube — full VM, good for learning
brew install minikube
minikube start --driver=docker --cpus=4 --memory=8g
minikube tunnel # enables LoadBalancer services
# Option 3: k3d (k3s in Docker) — lightweight
brew install k3d
k3d cluster create dev --agents 2
# Verify cluster
kubectl get nodesCore Resources: Pods
A Pod is the smallest deployable unit in Kubernetes. It wraps one or more containers that share a network namespace and storage.
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: api-pod
namespace: production
labels:
app: api
version: "1.2"
spec:
containers:
- name: api
image: myrepo/api:1.2.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: production
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10kubectl apply -f pod.yaml
kubectl get pods -n production
kubectl describe pod api-pod -n production
kubectl logs api-pod -n production -f
kubectl exec -it api-pod -n production -- /bin/shDeployments — Managing Pod Replicas
Deployments manage a ReplicaSet which ensures the desired number of Pods are always running. Use Deployments, not bare Pods, in production.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # zero-downtime rolling update
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: myrepo/api:1.2.0
ports:
- containerPort: 3000
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 5# Apply and verify
kubectl apply -f deployment.yaml
kubectl rollout status deployment/api -n production
# Scale
kubectl scale deployment api --replicas=5 -n production
# Rolling update (change image)
kubectl set image deployment/api api=myrepo/api:1.3.0 -n production
# Rollback to previous version
kubectl rollout undo deployment/api -n production
# View rollout history
kubectl rollout history deployment/api -n productionServices — Stable Networking for Pods
Pods get new IP addresses every time they are created. Services provide a stable IP and DNS name that load-balances across matching Pods.
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: api-service
namespace: production
spec:
selector:
app: api # routes to all pods with this label
ports:
- port: 80 # service port
targetPort: 3000 # pod port
type: ClusterIP # internal only (default)Service types:
ClusterIP— cluster-internal only (default, for pod-to-pod communication)NodePort— exposes on each node's IP at a static port (for simple external access or testing)LoadBalancer— provisions a cloud load balancer (AWS ELB, GCP LB, Azure LB)ExternalName— maps to an external DNS name
kubectl apply -f service.yaml
kubectl get services -n production
# Access from within the cluster (pod-to-pod):
# http://api-service.production.svc.cluster.local:80Namespaces — Cluster Organization
# Create namespace
kubectl create namespace staging
# Apply resources to a namespace
kubectl apply -f deployment.yaml -n staging
# Set default namespace for current context
kubectl config set-context --current --namespace=production
# List all resources across namespaces
kubectl get pods --all-namespaces
kubectl get pods -A # shorthandConfigMaps and Secrets
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
namespace: production
data:
LOG_LEVEL: info
PORT: "3000"
FEATURE_FLAGS: '{"newUI": true, "betaAPI": false}'
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: api-secrets
namespace: production
type: Opaque
stringData:
DATABASE_URL: postgres://app:password@db:5432/mydb
JWT_SECRET: my-super-secret-key# Reference in Deployment
spec:
containers:
- name: api
envFrom:
- configMapRef:
name: api-config
- secretRef:
name: api-secretsEssential kubectl Commands
# Context management
kubectl config get-contexts
kubectl config use-context production
kubectl config current-context
# Resource inspection
kubectl get all -n production
kubectl describe deployment api -n production
kubectl explain deployment.spec.strategy
# Debugging
kubectl logs deployment/api -n production -f --tail=100
kubectl exec -it pod/api-xxx -n production -- /bin/sh
kubectl port-forward service/api-service 8080:80 -n production
# Resource management
kubectl delete pod api-xxx -n production # pod is recreated by deployment
kubectl delete deployment api -n production
kubectl apply -f manifests/ -n production # apply all YAML in directory
# Dry run (preview without applying)
kubectl apply -f deployment.yaml --dry-run=clientCommon Mistakes
- Not setting resource
requestsandlimits— pods get evicted on node memory pressure without requests - Using bare Pods instead of Deployments — bare Pods are not rescheduled if the node fails
- Storing sensitive data in ConfigMaps — use Secrets for passwords, tokens, and keys
- Not configuring readiness probes — traffic is sent to pods that are not ready, causing errors
- Ignoring namespace isolation — all teams dumping resources into
defaultnamespace causes confusion
Best Practices
- Always set both
requests(scheduling) andlimits(runtime enforcement) for all containers - Use rolling update strategy with
maxUnavailable: 0for zero-downtime deployments - Apply resource quotas to namespaces to prevent one team from monopolizing cluster resources
- Use liveness and readiness probes — liveness restarts stuck containers, readiness prevents premature traffic
- Store manifests in Git and apply via CI/CD — never
kubectl applyfrom a local workstation in production - Use
kubectl diff -f manifest.yamlbefore applying to see what will change
Key Takeaways
- Kubernetes runs containers across a cluster with self-healing, scaling, and rolling updates built in
- The control plane (api-server, etcd, scheduler, controller-manager) manages cluster state; worker nodes run workloads
- Deployments manage Pod replicas via ReplicaSets — always use Deployments, never bare Pods in production
- Services provide stable network endpoints for Pods — ClusterIP for internal, LoadBalancer for external traffic
- Resource requests and limits are mandatory in production — without them, pod scheduling and eviction are unpredictable
- Readiness probes prevent traffic from reaching pods that are starting up or temporarily unhealthy
- Namespaces provide logical isolation — use separate namespaces per team or per environment (staging, production)
- All cluster changes should flow through Git and CI/CD pipelines — manual kubectl in production is a reliability risk
Advertisement