Introduction
Kubernetes has become the standard for container orchestration. This beginner-friendly guide explains core concepts through practical examples, helping you deploy and manage containerized applications at scale without drowning in complexity.
Understanding Kubernetes Architecture
Kubernetes cluster consists of control plane and worker nodes. Control plane components: API Server (entry point for all operations), etcd (distributed key-value store for cluster state), Scheduler (assigns pods to nodes), Controller Manager (handles node failures, pod replication). Worker nodes: kubelet (agent managing containers), kube-proxy (networking rules, load balancing), container runtime (Docker, containerd, CRI-O). Understanding this architecture explains many Kubernetes behaviors.
Setting Up Your First Cluster
Local development: Minikube (single node), Docker Desktop (built-in Kubernetes), Kind (Kubernetes in Docker). Production: managed services (EKS, GKE, AKS) or kubeadm for self-managed. For learning: install minikube: curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64, sudo install minikube-linux-amd64 /usr/local/bin/minikube, minikube start --driver=docker. Verify: kubectl cluster-info, kubectl get nodes.
Pods: The Smallest Deployable Units
A pod contains one or more containers sharing network and storage. Single-container pod definition (pod.yaml): apiVersion: v1, kind: Pod, metadata: name: nginx-pod, spec: containers: - name: nginx, image: nginx:latest, ports: - containerPort: 80. Deploy: kubectl apply -f pod.yaml. Inspect: kubectl get pods, kubectl describe pod nginx-pod, kubectl logs nginx-pod. Delete: kubectl delete pod nginx-pod. Multi-container pods for sidecar patterns (logging, proxy).
Deployments: Managing Pod Lifecycle
Deployments provide declarative updates, rollbacks, and scaling. deployment.yaml: apiVersion: apps/v1, kind: Deployment, metadata: name: nginx-deployment, spec: replicas: 3, selector: matchLabels: app: nginx, template: metadata: labels: app: nginx, spec: containers: - name: nginx, image: nginx:1.25, ports: - containerPort: 80. Commands: kubectl apply -f deployment.yaml, kubectl get deployments, kubectl scale deployment nginx-deployment --replicas=5, kubectl rollout status deployment/nginx-deployment, kubectl rollout history deployment/nginx-deployment, kubectl rollout undo deployment/nginx-deployment.
Services: Stable Networking
Services provide stable IP and DNS for dynamic pods. ClusterIP (default, internal-only): selector: app: nginx, ports: - port: 80, targetPort: 80. NodePort (exposes on node IP at high port): type: NodePort, ports: - port: 80, nodePort: 30080. LoadBalancer (cloud provider LB): type: LoadBalancer. Ingress for HTTP/HTTPS routing: routes to services based on host/path. Service discovery via DNS: nginx-service.default.svc.cluster.local. Test with kubectl port-forward service/nginx-service 8080:80.
ConfigMaps and Secrets
ConfigMaps for non-sensitive config: kubectl create configmap app-config --from-literal=app.name=myapp --from-literal=log.level=debug. Or from file: kubectl create configmap nginx-config --from-file=nginx.conf. Use in pod: env: - name: APP_NAME, valueFrom: configMapKeyRef: name: app-config, key: app.name. Or volume mount: volumes: - name: config, configMap: name: nginx-config. Secrets for sensitive data (base64 encoded, not encrypted): kubectl create secret generic db-secret --from-literal=password=mypass. Use similarly but base64 decode automatically. Better: use external secrets management (Hashicorp Vault, External Secrets Operator).
Persistent Storage
PersistentVolume (cluster storage) and PersistentVolumeClaim (request storage). Example PVC: kind: PersistentVolumeClaim, spec: accessModes: ["ReadWriteOnce"], resources: requests: storage: 10Gi, storageClassName: standard. Pod uses PVC: volumes: - name: data, persistentVolumeClaim: claimName: my-pvc, containers: volumeMounts: - name: data, mountPath: /data. StorageClasses for different performance tiers (SSD, HDD, network). StatefulSets for stateful applications (databases) with stable network identity and ordered deployment.
Namespaces and Resource Quotas
Namespaces virtualize cluster for multiple teams/projects: kubectl create namespace dev, kubectl get pods --namespace=dev, kubectl config set-context --current --namespace=dev. ResourceQuotas limit consumption: apiVersion: v1, kind: ResourceQuota, metadata: name: dev-quota, spec: hard: requests.cpu: "4", requests.memory: "8Gi", limits.cpu: "8", limits.memory: "16Gi", persistentvolumeclaims: "10", pods: "20". LimitRanges for per-container defaults.
Helm: Kubernetes Package Manager
Helm simplifies complex application deployment. Install: curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash. Add repo: helm repo add bitnami https://charts.bitnami.com/bitnami. Search: helm search repo mysql. Install: helm install my-mysql bitnami/mysql --set auth.rootPassword=secretpassword, primary.persistence.size=20Gi. List releases: helm list. Upgrade: helm upgrade my-mysql bitnami/mysql --set auth.rootPassword=newpassword. Uninstall: helm uninstall my-mysql. Create custom charts: helm create mychart, values.yaml for configuration, templates/ for Kubernetes YAML with Go templating.
Monitoring and Logging
Metrics Server for resource usage: kubectl top nodes, kubectl top pods. Prometheus for metrics collection (node_exporter, kube-state-metrics). Grafana for visualization (prebuilt dashboards). Logging: kubectl logs pod-name, kubectl logs --previous pod-name (last terminated container). For cluster-level logging: EFK stack (Elasticsearch, Fluentd, Kibana) or Loki (Grafana stack). Enable audit logging for security: --audit-log-path=/var/log/kubernetes/audit.log in API server.
Ingress Controllers
Ingress exposes HTTP/HTTPS routes from outside cluster. Install ingress-nginx: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml. Ingress resource: apiVersion: networking.k8s.io/v1, kind: Ingress, spec: rules: - host: myapp.example.com, http: paths: - path: /, pathType: Prefix, backend: service: name: myapp-service, port: number: 80. TLS: tls: - hosts: - myapp.example.com, secretName: myapp-tls. Cert-manager for automatic Let's Encrypt certificates.
Real-World Example: Deploying WordPress on Kubernetes
Complete example using MySQL and WordPress. Create secrets: DB_PASSWORD, DB_ROOT_PASSWORD. MySQL Deployment with PersistentVolume, Service (ClusterIP). WordPress Deployment with environment variables (WORDPRESS_DB_HOST, WORDPRESS_DB_USER, WORDPRESS_DB_PASSWORD, WORDPRESS_DB_NAME). WordPress Service (LoadBalancer or Ingress). ConfigMap for custom php.ini or wp-config.php overrides. PersistentVolume for uploads. HorizontalPodAutoscaler for WordPress: based on CPU or custom metrics (requests per second). Use Helm: helm repo add bitnami https://charts.bitnami.com/bitnami, helm install wordpress bitnami/wordpress --set mariadb.enabled=true, wordpressUsername=admin, wordpressPassword=mypassword.
Best Practices and Anti-Patterns
Best practices: Use labels for organization (app, environment, version). Resource requests and limits required for all containers (prevents noisy neighbors). Readiness and liveness probes for health checking. Use namespaces for environment separation. Immutable tags: use version tags (v1.2.3) not latest. PodDisruptionBudgets for high availability. Anti-patterns: running databases in Kubernetes (except managed services). Storing secrets in ConfigMaps. Running privileged containers. Using latest tag. Putting multiple processes in one container without proper process management.
Conclusion
Kubernetes learning curve is steep but manageable. Start with local cluster and stateless applications, add storage and config later, then advanced features like autoscaling and service mesh. Use managed services for production unless you have dedicated SRE team.