Kubernetes: Zero to Hero
Complete Kubernetes guide from fundamentals to production. Learn architecture, kubectl, k9s, pods, deployments, services, ConfigMaps, Secrets, Helm and more. With practical examples and real commands.

Table of Contents
1. Introduction to Kubernetes
Kubernetes (K8s) is a container orchestration platform developed by Google. It automates deployment, scaling, and management of containerized applications.

What is Kubernetes?
# Kubernetes (K8s) = Container Orchestration Platform# Developed by Google, now maintained by CNCF# The problem Kubernetes solves:# - How do you manage 100s or 1000s of containers?# - How do you ensure high availability?# - How do you scale automatically?# - How do you update without downtime?# - How do you recover from failures?# Kubernetes provides:# ✓ Automatic container deployment# ✓ Scaling (up/down based on load)# ✓ Load balancing# ✓ Self-healing (restart failed containers)# ✓ Rolling updates & rollbacks# ✓ Service discovery# ✓ Secret & configuration management# ✓ Storage orchestration# Think of K8s as a "datacenter operating system"# It manages your containers like an OS manages processes
The name "Kubernetes" comes from Greek κυβερνήτης (kybernḗtēs), meaning "helmsman". It's abbreviated K8s because there are 8 letters between K and s.
Kubernetes vs Docker
# Kubernetes vs Docker - They're COMPLEMENTARY!# DOCKER:# - Builds container images# - Runs individual containers# - Great for development# - Single host focus# KUBERNETES:# - Orchestrates containers across MULTIPLE hosts# - Manages container lifecycle at scale# - Production-grade features# - Cluster management# Analogy:# Docker = A musician who can play instruments# Kubernetes = The conductor of an orchestra# Docker builds and runs containers# Kubernetes tells containers WHERE and HOW to run# You need BOTH:# 1. Build images with Docker (or alternatives)# 2. Deploy and manage with Kubernetes
Essential Terminology
# Essential Kubernetes Terminology# CLUSTER# - A set of machines (nodes) running Kubernetes# - Has Control Plane + Worker Nodes# NODE# - A machine (physical or VM) in the cluster# - Worker nodes run your containers# - Control plane nodes manage the cluster# POD# - Smallest deployable unit in K8s# - Contains one or more containers# - Containers in a pod share network/storage# - Pods are ephemeral (can be replaced anytime)# DEPLOYMENT# - Manages pods declaratively# - Defines desired state (replicas, image, etc.)# - Handles rolling updates & rollbacks# SERVICE# - Stable network endpoint for pods# - Load balances traffic to pods# - Types: ClusterIP, NodePort, LoadBalancer# NAMESPACE# - Virtual cluster within a cluster# - Isolates resources (like folders)# - Examples: dev, staging, production# CONFIGMAP & SECRET# - External configuration for pods# - ConfigMap: non-sensitive data# - Secret: sensitive data (encoded)
2. Kubernetes Architecture
A Kubernetes cluster consists of a Control Plane and Worker Nodes. The Control Plane makes global decisions; Workers run the containers.

Control Plane Components
# Control Plane Components (Master Node)# These manage the cluster state# API SERVER (kube-apiserver)# - Front door to Kubernetes# - All communication goes through here# - RESTful API# - Validates and configures data# ETCD# - Distributed key-value store# - Stores ALL cluster state# - The "source of truth"# - Highly available (usually 3+ replicas)# SCHEDULER (kube-scheduler)# - Assigns pods to nodes# - Considers resources, constraints, affinity# - "Where should this pod run?"# CONTROLLER MANAGER (kube-controller-manager)# - Runs controllers (control loops)# - Node Controller: monitors node health# - Replication Controller: maintains pod count# - Endpoints Controller: populates Services# - Service Account Controller: creates accounts# CLOUD CONTROLLER MANAGER# - Integrates with cloud providers# - Manages load balancers, routes, volumes# - Only in cloud deployments
etcd is the brain of the cluster. If lost, we lose all state. That's why it's always deployed in high availability (3+ replicas) with backups.

Worker Node Components
# Worker Node Components# These run on every worker node# KUBELET# - Agent that runs on each node# - Ensures containers are running in pods# - Communicates with API server# - Reports node and pod status# KUBE-PROXY# - Network proxy on each node# - Implements Service concept# - Manages network rules (iptables/IPVS)# - Enables pod-to-pod communication# CONTAINER RUNTIME# - Runs containers (Docker, containerd, CRI-O)# - Kubernetes is container-runtime agnostic# - containerd is most common today# The flow:# 1. You: kubectl apply -f deployment.yaml# 2. API Server: validates and stores in etcd# 3. Scheduler: assigns pods to nodes# 4. Kubelet: pulls image, starts containers# 5. Kube-proxy: sets up networking
3. Installation
There are several ways to run Kubernetes locally. The most popular are Minikube, Kind, and K3s.
Install kubectl
# Install kubectl - The Kubernetes CLI# macOS (Homebrew):brew install kubectl# macOS (curl):curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl"chmod +x kubectlsudo mv kubectl /usr/local/bin/# Linux (curl):curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"chmod +x kubectlsudo mv kubectl /usr/local/bin/# Windows (Chocolatey):choco install kubernetes-cli# Verify installation:kubectl version --client# Output:# Client Version: v1.29.0# Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Minikube
# Minikube - Local Kubernetes for Development# macOS:brew install minikube# Linux:curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64sudo install minikube-linux-amd64 /usr/local/bin/minikube# Windows:choco install minikube# Start a cluster:minikube start# With specific resources:minikube start --cpus=4 --memory=8192 --driver=docker# Check status:minikube status# Access Kubernetes dashboard:minikube dashboard# Stop cluster:minikube stop# Delete cluster:minikube delete# Useful addons:minikube addons enable ingressminikube addons enable metrics-serverminikube addons list
Kind (Kubernetes in Docker)
# Kind - Kubernetes IN Docker (for CI/CD)# Install Kind:# macOS:brew install kind# Linux:curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64chmod +x ./kindsudo mv ./kind /usr/local/bin/kind# Create a cluster:kind create cluster# Create with custom name:kind create cluster --name my-cluster# Multi-node cluster (create config file first):cat <<EOF | kind create cluster --config=-kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-plane- role: worker- role: workerEOF# List clusters:kind get clusters# Delete cluster:kind delete cluster --name my-cluster# Load local Docker image to Kind:kind load docker-image my-app:latest
K3s
# K3s - Lightweight Kubernetes for Edge/IoT# Install K3s (single command!):curl -sfL https://get.k3s.io | sh -# Check if running:sudo systemctl status k3s# Get kubeconfig:sudo cat /etc/rancher/k3s/k3s.yaml# Use kubectl (included with k3s):sudo k3s kubectl get nodes# Or copy config for regular kubectl:mkdir -p ~/.kubesudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/configsudo chown $(id -u):$(id -g) ~/.kube/config# Add a worker node:# On master, get token:sudo cat /var/lib/rancher/k3s/server/node-token# On worker:curl -sfL https://get.k3s.io | K3S_URL=https://master-ip:6443 K3S_TOKEN=<token> sh -# Uninstall:/usr/local/bin/k3s-uninstall.sh
Beginners: Minikube. CI/CD: Kind. Edge/IoT: K3s. Cloud production: EKS, GKE, AKS.
4. kubectl Basics
kubectl is the command-line tool for interacting with Kubernetes. Mastering it is essential.
Configuration
# kubectl Configuration# View current context:kubectl config current-context# List all contexts:kubectl config get-contexts# Switch context:kubectl config use-context my-cluster# View config:kubectl config view# Set default namespace for context:kubectl config set-context --current --namespace=my-namespace# Create a new context:kubectl config set-context my-context \--cluster=my-cluster \--user=my-user \--namespace=my-namespace# Kubeconfig file location:# Default: ~/.kube/config# Override with: export KUBECONFIG=/path/to/config# Merge multiple kubeconfig files:export KUBECONFIG=~/.kube/config:~/.kube/other-configkubectl config view --flatten > ~/.kube/merged-config
Essential Commands
# Essential kubectl Commands# ========== GET RESOURCES ==========kubectl get pods # List pods in current namespacekubectl get pods -A # List pods in ALL namespaceskubectl get pods -o wide # More details (IP, node)kubectl get pods -o yaml # Full YAML outputkubectl get pods -o json # Full JSON outputkubectl get pods --watch # Watch for changeskubectl get pods -l app=nginx # Filter by labelkubectl get nodes # List cluster nodeskubectl get services # List serviceskubectl get deployments # List deploymentskubectl get all # List common resources# ========== DESCRIBE (detailed info) ==========kubectl describe pod my-podkubectl describe node my-nodekubectl describe service my-service# ========== CREATE / APPLY ==========kubectl apply -f manifest.yaml # Create/update from filekubectl apply -f ./manifests/ # Apply all files in directorykubectl apply -f https://url.com/manifest.yamlkubectl create deployment nginx --image=nginxkubectl create namespace my-ns# ========== DELETE ==========kubectl delete pod my-podkubectl delete -f manifest.yamlkubectl delete deployment my-deploykubectl delete pods --all # Delete all pods in namespace
Advanced Commands
# Advanced kubectl Commands# ========== LOGS ==========kubectl logs my-pod # View pod logskubectl logs my-pod -c my-container # Specific containerkubectl logs my-pod -f # Follow logs (stream)kubectl logs my-pod --tail=100 # Last 100 lineskubectl logs my-pod --since=1h # Last hourkubectl logs -l app=nginx # Logs by label# ========== EXEC (run commands in pod) ==========kubectl exec my-pod -- ls -lakubectl exec my-pod -- cat /etc/configkubectl exec -it my-pod -- /bin/bash # Interactive shellkubectl exec -it my-pod -c container -- sh# ========== PORT FORWARD ==========kubectl port-forward pod/my-pod 8080:80kubectl port-forward svc/my-service 8080:80kubectl port-forward deploy/my-deploy 8080:80# ========== COPY FILES ==========kubectl cp my-pod:/path/file ./local-filekubectl cp ./local-file my-pod:/path/file# ========== DEBUGGING ==========kubectl get events # Cluster eventskubectl get events --sort-by='.lastTimestamp'kubectl top pods # Resource usagekubectl top nodeskubectl api-resources # List all resource types# ========== DRY RUN (test without applying) ==========kubectl apply -f manifest.yaml --dry-run=clientkubectl apply -f manifest.yaml --dry-run=server
Shortcuts & Aliases
# kubectl Shortcuts & Aliases# Built-in short names:kubectl get po # podskubectl get svc # serviceskubectl get deploy # deploymentskubectl get ns # namespaceskubectl get no # nodeskubectl get cm # configmapskubectl get secret # secretskubectl get pv # persistentvolumeskubectl get pvc # persistentvolumeclaimskubectl get ing # ingresseskubectl get ds # daemonsetskubectl get sts # statefulsetskubectl get rs # replicasetskubectl get ep # endpointskubectl get sa # serviceaccounts# Recommended bash aliases (~/.bashrc or ~/.zshrc):alias k='kubectl'alias kgp='kubectl get pods'alias kgpa='kubectl get pods -A'alias kgs='kubectl get services'alias kgd='kubectl get deployments'alias kgn='kubectl get nodes'alias kdp='kubectl describe pod'alias kl='kubectl logs'alias klf='kubectl logs -f'alias ke='kubectl exec -it'alias kaf='kubectl apply -f'alias kdf='kubectl delete -f'# Enable kubectl autocompletion:# Bash:echo 'source <(kubectl completion bash)' >> ~/.bashrc# Zsh:echo 'source <(kubectl completion zsh)' >> ~/.zshrc
5. Pods
A Pod is the smallest unit Kubernetes can deploy. It represents one or more containers sharing resources.

Pod Basics
# Pods - The Smallest Deployable Unit# A Pod is:# - One or more containers that share:# - Network namespace (same IP, localhost)# - Storage volumes# - Lifecycle (created/deleted together)# - Ephemeral - can be replaced anytime# - Usually managed by a controller (Deployment)# When to use multi-container pods:# - Sidecar pattern (logging, proxies)# - Adapter pattern (format conversion)# - Ambassador pattern (connection proxying)# Pod lifecycle states:# - Pending: scheduled, waiting for resources# - Running: at least one container running# - Succeeded: all containers completed successfully# - Failed: at least one container failed# - Unknown: cannot determine state
Pod YAML
# pod.yaml - Simple Pod definitionapiVersion: v1kind: Podmetadata:name: my-nginxlabels:app: nginxenvironment: developmentannotations:description: "Demo nginx pod"spec:containers:- name: nginximage: nginx:1.25-alpineports:- containerPort: 80name: httpresources:requests:memory: "64Mi"cpu: "100m"limits:memory: "128Mi"cpu: "200m"env:- name: NGINX_HOSTvalue: "localhost"volumeMounts:- name: html-volumemountPath: /usr/share/nginx/htmlvolumes:- name: html-volumeemptyDir: {}restartPolicy: Always
Multi-Container Pod (Sidecar)
# Multi-container Pod (Sidecar Pattern)apiVersion: v1kind: Podmetadata:name: web-with-sidecarspec:containers:# Main application container- name: web-appimage: nginx:alpineports:- containerPort: 80volumeMounts:- name: shared-logsmountPath: /var/log/nginx# Sidecar: Log shipper- name: log-shipperimage: fluent/fluent-bit:latestvolumeMounts:- name: shared-logsmountPath: /var/log/nginxreadOnly: true- name: fluent-configmountPath: /fluent-bit/etc/# Sidecar: Metrics exporter- name: metrics-exporterimage: nginx/nginx-prometheus-exporter:latestargs:- "-nginx.scrape-uri=http://localhost/nginx_status"ports:- containerPort: 9113name: metricsvolumes:- name: shared-logsemptyDir: {}- name: fluent-configconfigMap:name: fluent-bit-config
Lifecycle Hooks & Probes
# Pod Lifecycle Hooks & ProbesapiVersion: v1kind: Podmetadata:name: lifecycle-demospec:containers:- name: appimage: my-app:latest# Startup Probe - for slow-starting containersstartupProbe:httpGet:path: /healthzport: 8080failureThreshold: 30periodSeconds: 10# Liveness Probe - restart if unhealthylivenessProbe:httpGet:path: /healthzport: 8080initialDelaySeconds: 10periodSeconds: 5failureThreshold: 3# Readiness Probe - remove from service if not readyreadinessProbe:httpGet:path: /readyport: 8080initialDelaySeconds: 5periodSeconds: 3# Lifecycle hookslifecycle:postStart:exec:command: ["/bin/sh", "-c", "echo Started > /tmp/started"]preStop:exec:command: ["/bin/sh", "-c", "nginx -s quit; sleep 10"]
Never create Pods directly in production. Use Deployments or StatefulSets. Pods won't be recreated automatically.
6. Deployments
Deployments are the recommended way to manage applications. They provide updates, scaling, and self-healing.

Concepts
# Deployments - Declarative Pod Management# A Deployment:# - Manages ReplicaSets (which manage Pods)# - Ensures desired number of pods are running# - Handles rolling updates# - Supports rollbacks# - Self-healing (replaces failed pods)# Why use Deployments instead of Pods?# - Pods are ephemeral, no self-healing# - Deployments maintain desired state# - Easy scaling (kubectl scale)# - Rolling updates without downtime# - Rollback to previous versions# Deployment → ReplicaSet → Pods# The Deployment creates ReplicaSets# ReplicaSets ensure pod count# You rarely interact with ReplicaSets directly
deployment.yaml
# deployment.yaml - Production-ready exampleapiVersion: apps/v1kind: Deploymentmetadata:name: nginx-deploymentlabels:app: nginxspec:replicas: 3selector:matchLabels:app: nginx# Update strategystrategy:type: RollingUpdaterollingUpdate:maxUnavailable: 1 # Max pods that can be unavailablemaxSurge: 1 # Max pods above desired counttemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.25-alpineports:- containerPort: 80resources:requests:memory: "64Mi"cpu: "100m"limits:memory: "128Mi"cpu: "200m"livenessProbe:httpGet:path: /port: 80initialDelaySeconds: 10periodSeconds: 5readinessProbe:httpGet:path: /port: 80initialDelaySeconds: 5periodSeconds: 3
Commands
# Deployment Commands# Create deployment imperatively:kubectl create deployment nginx --image=nginx:1.25kubectl create deployment nginx --image=nginx --replicas=3# Apply from file:kubectl apply -f deployment.yaml# View deployments:kubectl get deploymentskubectl get deploy nginx-deployment -o yamlkubectl describe deployment nginx-deployment# ========== SCALING ==========kubectl scale deployment nginx-deployment --replicas=5# Autoscaling (HPA):kubectl autoscale deployment nginx-deployment \--min=2 --max=10 --cpu-percent=80# ========== UPDATES ==========# Update image:kubectl set image deployment/nginx-deployment nginx=nginx:1.26# Update via edit (opens editor):kubectl edit deployment nginx-deployment# ========== ROLLOUT STATUS ==========kubectl rollout status deployment/nginx-deploymentkubectl rollout history deployment/nginx-deployment# ========== ROLLBACK ==========kubectl rollout undo deployment/nginx-deploymentkubectl rollout undo deployment/nginx-deployment --to-revision=2# Pause/resume rollout:kubectl rollout pause deployment/nginx-deploymentkubectl rollout resume deployment/nginx-deployment# ========== DELETE ==========kubectl delete deployment nginx-deployment

7. Services
Services provide a stable network address to access Pods. They are essential for communication.

Concepts
# Services - Stable Network Endpoints# Problem: Pods are ephemeral# - Pods get new IPs when recreated# - How do other pods find them?# - How does external traffic reach them?# Solution: Services# - Stable DNS name and IP# - Load balances to healthy pods# - Uses labels to select pods# Service Types:# 1. ClusterIP (default)# - Internal cluster IP only# - Only reachable within cluster# - Use for internal communication# 2. NodePort# - Exposes on each node's IP# - Port range: 30000-32767# - External access without load balancer# 3. LoadBalancer# - Provisions cloud load balancer# - External IP assigned by cloud provider# - Most common for production# 4. ExternalName# - Maps to external DNS name# - No proxying, just DNS CNAME
ClusterIP Service
# ClusterIP Service (default)apiVersion: v1kind: Servicemetadata:name: backend-servicespec:type: ClusterIP # Optional, this is defaultselector:app: backend # Selects pods with this labelports:- name: httpport: 80 # Service porttargetPort: 8080 # Container portprotocol: TCP---# Headless Service (no load balancing, direct pod DNS)apiVersion: v1kind: Servicemetadata:name: database-headlessspec:clusterIP: None # Makes it headlessselector:app: databaseports:- port: 5432targetPort: 5432# DNS resolution:# ClusterIP: backend-service.namespace.svc.cluster.local# Headless: pod-name.database-headless.namespace.svc.cluster.local
NodePort Service
# NodePort ServiceapiVersion: v1kind: Servicemetadata:name: web-nodeportspec:type: NodePortselector:app: webports:- name: httpport: 80 # Internal cluster porttargetPort: 8080 # Container portnodePort: 30080 # External port (30000-32767)# If not specified, K8s assigns random port---# Access the service:# http://<any-node-ip>:30080# Get node IPs:# kubectl get nodes -o wide# With Minikube:# minikube service web-nodeport --url
LoadBalancer Service
# LoadBalancer ServiceapiVersion: v1kind: Servicemetadata:name: web-loadbalancerannotations:# Cloud-specific annotationsservice.beta.kubernetes.io/aws-load-balancer-type: nlbservice.beta.kubernetes.io/aws-load-balancer-internal: "false"spec:type: LoadBalancerselector:app: webports:- name: httpport: 80targetPort: 8080- name: httpsport: 443targetPort: 8443# Optional: specify desired external IP# loadBalancerIP: 1.2.3.4# Optional: limit source IPs# loadBalancerSourceRanges:# - 10.0.0.0/8---# Check external IP:# kubectl get svc web-loadbalancer# NAME TYPE EXTERNAL-IP PORT(S)# web-loadbalancer LoadBalancer 203.0.113.10 80:31234/TCP
8. ConfigMaps & Secrets
ConfigMaps and Secrets separate configuration from code. ConfigMaps for non-sensitive data, Secrets for sensitive.
ConfigMaps
# ConfigMaps - External Configuration# ConfigMaps store non-sensitive configuration:# - Environment variables# - Configuration files# - Command-line arguments# Benefits:# - Separate config from container image# - Update config without rebuilding# - Share config across multiple pods# - Environment-specific values
ConfigMap Examples
# ConfigMap Examples# From literal values:kubectl create configmap app-config \--from-literal=DATABASE_HOST=postgres \--from-literal=LOG_LEVEL=info# From file:kubectl create configmap nginx-config --from-file=nginx.conf# From directory:kubectl create configmap configs --from-file=./config-dir/---# configmap.yamlapiVersion: v1kind: ConfigMapmetadata:name: app-configdata:# Simple key-value pairsDATABASE_HOST: "postgres.default.svc.cluster.local"DATABASE_PORT: "5432"LOG_LEVEL: "info"# Multi-line configuration fileapp.properties: |server.port=8080server.host=0.0.0.0feature.enabled=truenginx.conf: |server {listen 80;location / {proxy_pass http://backend:8080;}}
Usage in Pods
# Using ConfigMaps in PodsapiVersion: v1kind: Podmetadata:name: app-with-configspec:containers:- name: appimage: my-app:latest# Method 1: Environment variables from ConfigMapenv:- name: DB_HOSTvalueFrom:configMapKeyRef:name: app-configkey: DATABASE_HOST# Method 2: All keys as environment variablesenvFrom:- configMapRef:name: app-config# optional: true # Don't fail if ConfigMap missing# Method 3: Mount as filesvolumeMounts:- name: config-volumemountPath: /etc/configreadOnly: true# Method 4: Mount specific key as file- name: nginx-configmountPath: /etc/nginx/nginx.confsubPath: nginx.confvolumes:- name: config-volumeconfigMap:name: app-config- name: nginx-configconfigMap:name: app-configitems:- key: nginx.confpath: nginx.conf
Secrets
# Secrets - Sensitive Data Storage# Secrets store sensitive data:# - Passwords# - API keys# - TLS certificates# - SSH keys# Important security notes:# - Secrets are base64 encoded (NOT encrypted!)# - Enable encryption at rest in etcd# - Use RBAC to limit access# - Consider external secret managers# (HashiCorp Vault, AWS Secrets Manager)# Secret types:# - Opaque: arbitrary user-defined data# - kubernetes.io/tls: TLS certificates# - kubernetes.io/dockerconfigjson: Docker registry credentials# - kubernetes.io/basic-auth: basic authentication# - kubernetes.io/ssh-auth: SSH authentication
Secret Examples
# Secret Examples# Create from literal (auto base64 encodes):kubectl create secret generic db-credentials \--from-literal=username=admin \--from-literal=password='S3cr3tP@ssw0rd!'# Create TLS secret:kubectl create secret tls my-tls \--cert=path/to/tls.crt \--key=path/to/tls.key# Create Docker registry secret:kubectl create secret docker-registry regcred \--docker-server=ghcr.io \--docker-username=user \--docker-password=token \--docker-email=user@example.com---# secret.yaml (values must be base64 encoded)apiVersion: v1kind: Secretmetadata:name: db-credentialstype: Opaquedata:# echo -n 'admin' | base64username: YWRtaW4=# echo -n 'password123' | base64password: cGFzc3dvcmQxMjM=---# Using stringData (auto-encodes, easier to read)apiVersion: v1kind: Secretmetadata:name: db-credentialstype: OpaquestringData:username: adminpassword: password123
Using Secrets
# Using Secrets in PodsapiVersion: v1kind: Podmetadata:name: app-with-secretsspec:containers:- name: appimage: my-app:latest# Method 1: Environment variable from Secretenv:- name: DB_PASSWORDvalueFrom:secretKeyRef:name: db-credentialskey: password# Method 2: All keys as environment variablesenvFrom:- secretRef:name: db-credentials# Method 3: Mount as filesvolumeMounts:- name: secret-volumemountPath: /etc/secretsreadOnly: truevolumes:- name: secret-volumesecret:secretName: db-credentials# Optional: set file permissionsdefaultMode: 0400---# Using Docker registry secretapiVersion: v1kind: Podmetadata:name: private-image-podspec:containers:- name: appimage: ghcr.io/myorg/private-app:latestimagePullSecrets:- name: regcred
Secrets are only base64 encoded, NOT encrypted. Enable encryption at rest and consider HashiCorp Vault or AWS Secrets Manager.
9. Volumes & Storage
Kubernetes offers various storage types: temporary, persistent, and dynamic via StorageClasses.
Volume Types
# Kubernetes Storage Concepts# VOLUMES - Temporary or persistent storage for pods# Volume Types:# 1. emptyDir - temporary, deleted with pod# 2. hostPath - mounts host filesystem (dangerous!)# 3. configMap/secret - configuration data# 4. persistentVolumeClaim - persistent storage# 5. nfs - Network File System# 6. cloud volumes - AWS EBS, GCE PD, Azure Disk# PERSISTENT VOLUMES (PV)# - Cluster-level storage resource# - Provisioned by admin or dynamically# - Independent of pod lifecycle# PERSISTENT VOLUME CLAIMS (PVC)# - Request for storage by user# - Binds to a matching PV# - Used by pods to access storage# STORAGE CLASSES# - Define "classes" of storage# - Enable dynamic provisioning# - Examples: fast-ssd, standard, slow-hdd
Volume Examples
# Volume ExamplesapiVersion: v1kind: Podmetadata:name: volume-demospec:containers:- name: appimage: nginxvolumeMounts:# emptyDir - shared between containers- name: cachemountPath: /cache# hostPath - access host filesystem- name: host-logsmountPath: /var/log/host# configMap as volume- name: configmountPath: /etc/configreadOnly: truevolumes:# Temporary storage, deleted with pod- name: cacheemptyDir:sizeLimit: 500Mi# Mount host directory (use with caution!)- name: host-logshostPath:path: /var/logtype: Directory# ConfigMap as files- name: configconfigMap:name: my-config
PersistentVolume & PVC
# PersistentVolume (cluster resource)apiVersion: v1kind: PersistentVolumemetadata:name: my-pvspec:capacity:storage: 10GivolumeMode: FilesystemaccessModes:- ReadWriteOnce # RWO - single node# - ReadOnlyMany # ROX - multiple nodes read-only# - ReadWriteMany # RWX - multiple nodes read-writepersistentVolumeReclaimPolicy: Retain# Retain: keep data after PVC deleted# Delete: delete volume after PVC deleted# Recycle: deprecatedstorageClassName: standardhostPath:path: /data/my-pv---# PersistentVolumeClaim (user request)apiVersion: v1kind: PersistentVolumeClaimmetadata:name: my-pvcspec:accessModes:- ReadWriteOnceresources:requests:storage: 5GistorageClassName: standard---# Using PVC in PodapiVersion: v1kind: Podmetadata:name: app-with-pvcspec:containers:- name: appimage: nginxvolumeMounts:- name: datamountPath: /datavolumes:- name: datapersistentVolumeClaim:claimName: my-pvc
StorageClass
# StorageClass for dynamic provisioningapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: fast-ssdprovisioner: kubernetes.io/aws-ebs # Cloud-specificparameters:type: gp3iopsPerGB: "50"fsType: ext4reclaimPolicy: DeleteallowVolumeExpansion: truevolumeBindingMode: WaitForFirstConsumer---# AWS EBS StorageClassapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: ebs-scprovisioner: ebs.csi.aws.comparameters:type: gp3encrypted: "true"reclaimPolicy: DeletevolumeBindingMode: WaitForFirstConsumer---# GKE StorageClassapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: ssd-scprovisioner: pd.csi.storage.gke.ioparameters:type: pd-ssdreclaimPolicy: DeletevolumeBindingMode: WaitForFirstConsumer---# PVC using StorageClass (dynamic provisioning)apiVersion: v1kind: PersistentVolumeClaimmetadata:name: dynamic-pvcspec:accessModes:- ReadWriteOncestorageClassName: fast-ssdresources:requests:storage: 20Gi
10. Networking & Ingress
Kubernetes has a flat network model where all pods can communicate with each other. Ingress provides external HTTP access.
Networking Model
# Kubernetes Networking Model# Fundamental rules:# 1. All pods can communicate with all other pods (no NAT)# 2. All nodes can communicate with all pods (no NAT)# 3. Pod sees itself with same IP others see it# Network implementations (CNI plugins):# - Calico: most popular, network policies# - Cilium: eBPF-based, advanced features# - Flannel: simple, overlay network# - Weave: mesh network# - AWS VPC CNI: native AWS networking# Service Discovery:# - DNS: my-service.my-namespace.svc.cluster.local# - Environment variables: MY_SERVICE_HOST, MY_SERVICE_PORT# Network Policies:# - Firewall rules for pods# - Control ingress/egress traffic# - Require CNI that supports them
NetworkPolicy
# NetworkPolicy ExamplesapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: deny-allnamespace: productionspec:podSelector: {} # Applies to all podspolicyTypes:- Ingress- Egress# No rules = deny all traffic---# Allow ingress from specific podsapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: allow-frontendspec:podSelector:matchLabels:app: backendpolicyTypes:- Ingressingress:- from:- podSelector:matchLabels:app: frontendports:- protocol: TCPport: 8080---# Allow egress to specific external IPsapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: allow-external-apispec:podSelector:matchLabels:app: my-apppolicyTypes:- Egressegress:- to:- ipBlock:cidr: 203.0.113.0/24ports:- protocol: TCPport: 443

Ingress Concepts
# Ingress - HTTP/HTTPS Routing# Ingress provides:# - External access to services# - URL-based routing# - SSL/TLS termination# - Name-based virtual hosting# - Load balancing# Requires an Ingress Controller:# - NGINX Ingress (most popular)# - Traefik# - HAProxy# - AWS ALB Ingress Controller# - GKE Ingress# - Istio Gateway# Without Ingress:# External → LoadBalancer → Service → Pods# With Ingress:# External → Ingress → Service → Pods# ↘ Ingress → Service → Pods
Ingress YAML
# Ingress ExamplesapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: simple-ingressannotations:nginx.ingress.kubernetes.io/rewrite-target: /spec:ingressClassName: nginxrules:- host: myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: web-serviceport:number: 80---# Multiple hosts and pathsapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: multi-path-ingressspec:ingressClassName: nginxrules:- host: api.example.comhttp:paths:- path: /v1pathType: Prefixbackend:service:name: api-v1port:number: 80- path: /v2pathType: Prefixbackend:service:name: api-v2port:number: 80- host: web.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: web-frontendport:number: 80
Ingress TLS
# Ingress with TLSapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: tls-ingressannotations:# Redirect HTTP to HTTPSnginx.ingress.kubernetes.io/ssl-redirect: "true"# Use cert-manager for auto-renewalcert-manager.io/cluster-issuer: "letsencrypt-prod"spec:ingressClassName: nginxtls:- hosts:- myapp.example.comsecretName: myapp-tls-secretrules:- host: myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: web-serviceport:number: 80---# Create TLS secret manually:# kubectl create secret tls myapp-tls-secret \# --cert=tls.crt --key=tls.key# Or use cert-manager for automatic Let's Encrypt:# 1. Install cert-manager# 2. Create ClusterIssuer for Let's Encrypt# 3. Add annotation to Ingress
11. K9s - Terminal UI
K9s is a terminal UI for Kubernetes that makes it easy to navigate and manage cluster resources.

Installation
# K9s - Terminal UI for Kubernetes# Install K9s:# macOS:brew install derailed/k9s/k9s# Linux (via curl):curl -sS https://webinstall.dev/k9s | bash# Linux (via snap):sudo snap install k9s# Windows (via chocolatey):choco install k9s# Verify installation:k9s version# Launch k9s (uses current kubectl context):k9s# Launch with specific context:k9s --context my-cluster# Launch with specific namespace:k9s -n my-namespace# Launch in read-only mode:k9s --readonly
Navigation & Shortcuts
# K9s Navigation & Shortcuts# GLOBAL SHORTCUTS# : Command mode (type resource name)# / Filter/search# ? Help# Ctrl+a Show all resources# Ctrl+d Delete resource# Esc Back / Cancel# q Quit k9s# NAVIGATION# :pods Switch to pods view# :svc Switch to services view# :deploy Switch to deployments view# :ns Switch to namespaces view# :nodes Switch to nodes view# :secrets Switch to secrets view# :cm Switch to configmaps view# :pv Switch to persistent volumes# :pvc Switch to persistent volume claims# ON A RESOURCE# Enter View details# d Describe# l View logs# s Shell into container# y View YAML# e Edit resource# k Kill/delete# Ctrl+k Kill pod (force)# LOGS VIEW# w Toggle wrap# s Toggle auto-scroll# 0 Jump to start# Shift+g Jump to end# / Search in logs
Advanced Features
# K9s Advanced Features# FILTERING# /nginx Filter by name containing "nginx"# /app=web Filter by label# /-n default Filter by namespace# /!running Exclude "running" from results# CONTEXT SWITCHING# :ctx List contexts# Enter on ctx Switch to that context# BENCHMARKING# :be HTTP benchmarks view# (on a pod) b to run benchmark# PORT FORWARDING# (on a pod) Shift+f to port forward# XRAY VIEW# :xray deploy Shows deployment tree# :xray svc Shows service endpoints# PULSE VIEW# :pulse Cluster health metrics# CONFIGURATION (~/.config/k9s/config.yml)# k9s:# refreshRate: 2# maxConnRetry: 5# readOnly: false# noIcons: false# logger:# tail: 100# buffer: 5000# sinceSeconds: 60# currentContext: minikube# currentCluster: minikube
Custom Hotkeys
# K9s Custom Hotkeys (~/.config/k9s/hotkey.yml)# Define custom hotkeys:hotKey:# Shift-1: Switch to pods in all namespacesshift-1:shortCut: Shift-1description: View all podscommand: pods# Shift-2: Switch to deploymentsshift-2:shortCut: Shift-2description: View deploymentscommand: deploy# Shift-3: Switch to servicesshift-3:shortCut: Shift-3description: View servicescommand: svc# Shift-4: Show node resourcesshift-4:shortCut: Shift-4description: View nodescommand: nodes# Shift-l: Logs with timestampsshift-l:shortCut: Shift-Ldescription: Logs with timestampscommand: "pods -c <pod>"
K9s is much faster than kubectl for interactive tasks. Use / to filter, l for logs, s for shell, and d for describe.
12. Helm Charts
Helm is the package manager for Kubernetes. It allows installing complex applications with a single command.

What is Helm?
# Helm - The Package Manager for Kubernetes# What is Helm?# - Package manager for Kubernetes# - Uses "charts" (packages of K8s resources)# - Templating engine for YAML# - Release management & upgrades# - Rollback capability# Key concepts:# - Chart: Package of K8s resources# - Release: Instance of a chart# - Repository: Collection of charts# - Values: Configuration for a chart# Why use Helm?# - Avoid repetitive YAML# - Parameterize deployments# - Share configurations# - Version control releases# - Easy upgrades and rollbacks
Installation
# Install Helm# macOS:brew install helm# Linux (script):curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash# Linux (snap):sudo snap install helm --classic# Windows:choco install kubernetes-helm# Verify installation:helm version# Add popular chart repositories:helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo add ingress-nginx https://kubernetes.github.io/ingress-nginxhelm repo add jetstack https://charts.jetstack.iohelm repo add prometheus-community https://prometheus-community.github.io/helm-charts# Update repositories:helm repo update# Search for charts:helm search repo nginxhelm search hub wordpress
Essential Commands
# Essential Helm Commands# ========== REPOSITORY MANAGEMENT ==========helm repo list # List reposhelm repo add name url # Add repohelm repo remove name # Remove repohelm repo update # Update all repos# ========== SEARCH ==========helm search repo nginx # Search in reposhelm search hub wordpress # Search Helm Hub# ========== INSTALL ==========helm install release-name chart # Install charthelm install my-nginx bitnami/nginx# With custom values:helm install my-nginx bitnami/nginx -f values.yamlhelm install my-nginx bitnami/nginx --set replicas=3# Install in namespace:helm install my-nginx bitnami/nginx -n my-namespace# Dry run (preview):helm install my-nginx bitnami/nginx --dry-run# ========== MANAGE RELEASES ==========helm list # List releaseshelm list -A # All namespaceshelm status my-nginx # Release statushelm history my-nginx # Release history# ========== UPGRADE ==========helm upgrade my-nginx bitnami/nginxhelm upgrade my-nginx bitnami/nginx -f new-values.yaml# ========== ROLLBACK ==========helm rollback my-nginx # Rollback to previoushelm rollback my-nginx 2 # Rollback to revision 2# ========== UNINSTALL ==========helm uninstall my-nginx
Chart Structure
# Helm Chart Structuremy-chart/├── Chart.yaml # Chart metadata├── values.yaml # Default values├── charts/ # Chart dependencies├── templates/ # K8s manifests (templates)│ ├── deployment.yaml│ ├── service.yaml│ ├── ingress.yaml│ ├── configmap.yaml│ ├── secret.yaml│ ├── _helpers.tpl # Template helpers│ ├── NOTES.txt # Post-install notes│ └── tests/ # Test hooks└── .helmignore # Files to ignore# Chart.yaml example:apiVersion: v2name: my-appdescription: My application charttype: applicationversion: 1.0.0 # Chart versionappVersion: "2.0.0" # App versiondependencies:- name: postgresqlversion: "12.1.0"repository: "https://charts.bitnami.com/bitnami"condition: postgresql.enabled
Template Example
# Helm Template Example# templates/deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: {{ include "my-app.fullname" . }}labels:{{- include "my-app.labels" . | nindent 4 }}spec:replicas: {{ .Values.replicaCount }}selector:matchLabels:{{- include "my-app.selectorLabels" . | nindent 6 }}template:metadata:labels:{{- include "my-app.selectorLabels" . | nindent 8 }}spec:containers:- name: {{ .Chart.Name }}image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"ports:- containerPort: {{ .Values.service.port }}{{- if .Values.resources }}resources:{{- toYaml .Values.resources | nindent 10 }}{{- end }}env:{{- range $key, $value := .Values.env }}- name: {{ $key }}value: {{ $value | quote }}{{- end }}# values.yaml (defaults)replicaCount: 2image:repository: nginxtag: "1.25"service:port: 80resources:requests:cpu: 100mmemory: 128Milimits:cpu: 200mmemory: 256Mienv:LOG_LEVEL: info
13. Namespaces & RBAC
Namespaces provide logical isolation. RBAC controls who can do what in the cluster.
Namespaces
# Namespaces - Virtual Clusters# Namespaces provide:# - Resource isolation# - Access control boundaries# - Resource quotas per namespace# - Network policy scoping# Default namespaces:# - default: for resources without namespace# - kube-system: K8s system components# - kube-public: publicly readable# - kube-node-lease: node heartbeats# When to use namespaces:# - Separate environments (dev/staging/prod)# - Separate teams or projects# - Separate customers (multi-tenancy)# - Resource quota enforcement
Commands
# Namespace Commands# Create namespace:kubectl create namespace my-namespace# From YAML:kubectl apply -f - <<EOFapiVersion: v1kind: Namespacemetadata:name: my-namespacelabels:environment: developmentEOF# List namespaces:kubectl get namespaceskubectl get ns# Switch default namespace:kubectl config set-context --current --namespace=my-namespace# Run command in namespace:kubectl get pods -n my-namespacekubectl get all -n my-namespace# Delete namespace (DELETES ALL RESOURCES IN IT):kubectl delete namespace my-namespace
ResourceQuota & LimitRange
# ResourceQuota - Limit namespace resourcesapiVersion: v1kind: ResourceQuotametadata:name: compute-quotanamespace: developmentspec:hard:# Compute resourcesrequests.cpu: "4"requests.memory: 8Gilimits.cpu: "8"limits.memory: 16Gi# Object countspods: "20"services: "10"secrets: "20"configmaps: "20"persistentvolumeclaims: "5"---# LimitRange - Default limits for podsapiVersion: v1kind: LimitRangemetadata:name: default-limitsnamespace: developmentspec:limits:- type: Containerdefault:cpu: 200mmemory: 256MidefaultRequest:cpu: 100mmemory: 128Mimax:cpu: "2"memory: 2Gimin:cpu: 50mmemory: 64Mi
RBAC Concepts
# RBAC - Role-Based Access Control# RBAC controls WHO can do WHAT on WHICH resources# Key concepts:# - Subject: user, group, or service account# - Role: set of permissions (verbs on resources)# - RoleBinding: binds role to subject# Role types:# - Role: namespace-scoped# - ClusterRole: cluster-scoped# Binding types:# - RoleBinding: binds to namespace# - ClusterRoleBinding: binds cluster-wide# Verbs (actions):# get, list, watch, create, update, patch, delete# Common ClusterRoles:# - view: read-only access# - edit: read/write (no RBAC)# - admin: full access (no RBAC)# - cluster-admin: superuser
RBAC Examples
# RBAC Examples# Role - namespace permissionsapiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: pod-readernamespace: developmentrules:- apiGroups: [""]resources: ["pods", "pods/log"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["pods/exec"]verbs: ["create"]---# RoleBinding - bind role to userapiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: read-podsnamespace: developmentsubjects:- kind: Username: janeapiGroup: rbac.authorization.k8s.io- kind: ServiceAccountname: my-appnamespace: developmentroleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io---# ClusterRole - cluster-wide permissionsapiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:name: secret-readerrules:- apiGroups: [""]resources: ["secrets"]verbs: ["get", "list"]---# ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: read-secrets-globalsubjects:- kind: Groupname: developersapiGroup: rbac.authorization.k8s.ioroleRef:kind: ClusterRolename: secret-readerapiGroup: rbac.authorization.k8s.io
ServiceAccount
# ServiceAccount - Identity for podsapiVersion: v1kind: ServiceAccountmetadata:name: my-appnamespace: defaultautomountServiceAccountToken: true---# Use ServiceAccount in PodapiVersion: v1kind: Podmetadata:name: my-app-podspec:serviceAccountName: my-appcontainers:- name: appimage: my-app:latest---# Create token for ServiceAccount (K8s 1.24+)kubectl create token my-app# Or create long-lived secret token:apiVersion: v1kind: Secretmetadata:name: my-app-tokenannotations:kubernetes.io/service-account.name: my-apptype: kubernetes.io/service-account-token
14. Monitoring & Logging
Monitoring is essential for running Kubernetes in production. Prometheus + Grafana is the most popular stack.
Monitoring Stack
# Kubernetes Monitoring Stack# Common monitoring tools:# - Prometheus: metrics collection# - Grafana: visualization# - Alertmanager: alerting# - Loki: log aggregation# - Jaeger/Zipkin: distributed tracing# Metrics types:# - Node metrics (CPU, memory, disk)# - Pod metrics (container resources)# - Application metrics (custom)# - Cluster metrics (API server, etcd)# Built-in:# - metrics-server: basic CPU/memory# - kubectl top pods/nodes# Install metrics-server:kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml# View metrics:kubectl top nodeskubectl top podskubectl top pods -A --sort-by=memory
Install Prometheus
# Install Prometheus with Helm# Add repository:helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update# Install full stack (Prometheus + Grafana + Alertmanager):helm install monitoring prometheus-community/kube-prometheus-stack \-n monitoring --create-namespace \--set prometheus.prometheusSpec.retention=30d \--set grafana.adminPassword=admin# Port forward to Grafana:kubectl port-forward -n monitoring svc/monitoring-grafana 3000:80# Access at http://localhost:3000 (admin/admin)# Port forward to Prometheus:kubectl port-forward -n monitoring svc/monitoring-kube-prometheus-prometheus 9090:9090# Access at http://localhost:9090# List installed resources:kubectl get all -n monitoring
Application Metrics
# Application Metrics with Prometheus# ServiceMonitor - auto-discover metrics endpointsapiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata:name: my-app-monitornamespace: monitoringlabels:release: monitoring # Must match Prometheus selectorspec:selector:matchLabels:app: my-appnamespaceSelector:matchNames:- defaultendpoints:- port: metricspath: /metricsinterval: 30s---# PodMonitor - monitor pods directlyapiVersion: monitoring.coreos.com/v1kind: PodMonitormetadata:name: my-app-podsnamespace: monitoringspec:selector:matchLabels:app: my-apppodMetricsEndpoints:- port: metricspath: /metricsinterval: 15s
Logging (Loki)
# Kubernetes Logging# Log collection options:# - Fluentd / Fluent Bit# - Loki + Promtail# - ELK Stack (Elasticsearch + Logstash + Kibana)# - Cloud solutions (CloudWatch, Stackdriver)# Install Loki Stack:helm repo add grafana https://grafana.github.io/helm-chartshelm repo updatehelm install loki grafana/loki-stack \-n logging --create-namespace \--set promtail.enabled=true \--set grafana.enabled=false # Use existing Grafana# Add Loki as datasource in Grafana:# URL: http://loki.logging:3100# View logs in Grafana:# 1. Go to Explore# 2. Select Loki datasource# 3. Use LogQL: {namespace="default", app="my-app"}# LogQL examples:# {job="my-app"} |= "error"# {namespace="default"} | json | level="error"# rate({app="nginx"}[5m])
15. Best Practices
These practices will help you run production workloads safely and efficiently.
Resource Management
# Best Practices: Resource Management# ALWAYS set resource requests and limitsresources:requests:cpu: 100m # Minimum neededmemory: 128Milimits:cpu: 200m # Maximum allowedmemory: 256Mi# Guidelines:# - Start with requests = actual usage# - Set limits 2-3x requests initially# - Monitor and adjust based on metrics# - Use VPA (Vertical Pod Autoscaler) for recommendations# CPU:# - 1 CPU = 1000m (millicores)# - 100m = 0.1 CPU = 10% of a core# - Requests: for scheduling# - Limits: throttled if exceeded# Memory:# - Use Mi (mebibytes) or Gi (gibibytes)# - Requests: for scheduling# - Limits: OOMKilled if exceeded# Anti-patterns to avoid:# - No limits (can starve other pods)# - Limits too low (constant throttling)# - Requests too high (wasted resources)
Security
# Best Practices: Security# 1. Run as non-rootsecurityContext:runAsNonRoot: truerunAsUser: 1000runAsGroup: 1000fsGroup: 1000# 2. Read-only filesystemsecurityContext:readOnlyRootFilesystem: truevolumeMounts:- name: tmpmountPath: /tmpvolumes:- name: tmpemptyDir: {}# 3. Drop all capabilitiessecurityContext:capabilities:drop:- ALL# 4. Use NetworkPolicies# - Default deny all ingress/egress# - Explicitly allow needed traffic# 5. Secrets management# - Never commit secrets to git# - Use external secret managers# - Rotate secrets regularly# 6. Image security# - Use specific image tags (not :latest)# - Scan images for vulnerabilities# - Use private registries# - Sign and verify images
High Availability
# Best Practices: High Availability# 1. Multiple replicasspec:replicas: 3 # At least 2 for HA# 2. Pod Anti-Affinity (spread across nodes)affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchLabels:app: my-apptopologyKey: kubernetes.io/hostname# 3. Pod Disruption BudgetapiVersion: policy/v1kind: PodDisruptionBudgetmetadata:name: my-app-pdbspec:minAvailable: 2 # or maxUnavailable: 1selector:matchLabels:app: my-app# 4. Topology Spread ConstraintstopologySpreadConstraints:- maxSkew: 1topologyKey: topology.kubernetes.io/zonewhenUnsatisfiable: DoNotSchedulelabelSelector:matchLabels:app: my-app# 5. Proper health checkslivenessProbe:httpGet:path: /healthzport: 8080initialDelaySeconds: 10periodSeconds: 5readinessProbe:httpGet:path: /readyport: 8080initialDelaySeconds: 5periodSeconds: 3
General Practices
# General Best Practices# 1. Use declarative YAML (not imperative commands)kubectl apply -f deployment.yaml # Goodkubectl create deployment ... # Avoid in production# 2. Use namespaces# - Separate environments# - Apply resource quotas# - Control access with RBAC# 3. Label everythingmetadata:labels:app: my-appversion: v1.0.0environment: productionteam: backend# 4. Use ConfigMaps and Secrets# - Don't hardcode config in images# - Separate config from code# 5. Implement GitOps# - Store manifests in git# - Use ArgoCD or Flux# - Automated deployments# 6. Monitoring and alerting# - Set up Prometheus + Grafana# - Create dashboards# - Configure alerts# 7. Regular backups# - Backup etcd# - Backup PersistentVolumes# - Test restore procedures# 8. Keep clusters updated# - Regular K8s version upgrades# - Update node OS# - Patch security vulnerabilities
16. Real-World Examples
A complete full-stack application example deployed on Kubernetes with database, cache, backend, frontend, and Ingress.
Full-Stack App (Part 1)
# Full Stack Application Deployment# 1. NamespaceapiVersion: v1kind: Namespacemetadata:name: my-app---# 2. ConfigMapapiVersion: v1kind: ConfigMapmetadata:name: app-confignamespace: my-appdata:DATABASE_HOST: postgres-serviceREDIS_HOST: redis-serviceLOG_LEVEL: info---# 3. SecretapiVersion: v1kind: Secretmetadata:name: app-secretsnamespace: my-apptype: OpaquestringData:DATABASE_PASSWORD: supersecretJWT_SECRET: jwt-secret-key---# 4. PostgreSQL StatefulSetapiVersion: apps/v1kind: StatefulSetmetadata:name: postgresnamespace: my-appspec:serviceName: postgresreplicas: 1selector:matchLabels:app: postgrestemplate:metadata:labels:app: postgresspec:containers:- name: postgresimage: postgres:15-alpineports:- containerPort: 5432env:- name: POSTGRES_PASSWORDvalueFrom:secretKeyRef:name: app-secretskey: DATABASE_PASSWORDvolumeMounts:- name: datamountPath: /var/lib/postgresql/datavolumeClaimTemplates:- metadata:name: dataspec:accessModes: ["ReadWriteOnce"]resources:requests:storage: 10Gi
Full-Stack App (Part 2)
# Full Stack Application (continued)# 5. PostgreSQL ServiceapiVersion: v1kind: Servicemetadata:name: postgres-servicenamespace: my-appspec:selector:app: postgresports:- port: 5432targetPort: 5432clusterIP: None---# 6. Redis DeploymentapiVersion: apps/v1kind: Deploymentmetadata:name: redisnamespace: my-appspec:replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redisspec:containers:- name: redisimage: redis:7-alpineports:- containerPort: 6379---# 7. Redis ServiceapiVersion: v1kind: Servicemetadata:name: redis-servicenamespace: my-appspec:selector:app: redisports:- port: 6379targetPort: 6379---# 8. Backend API DeploymentapiVersion: apps/v1kind: Deploymentmetadata:name: backendnamespace: my-appspec:replicas: 3selector:matchLabels:app: backendtemplate:metadata:labels:app: backendspec:containers:- name: backendimage: myapp/backend:v1.0.0ports:- containerPort: 8080envFrom:- configMapRef:name: app-config- secretRef:name: app-secretsresources:requests:cpu: 100mmemory: 256Milimits:cpu: 500mmemory: 512MilivenessProbe:httpGet:path: /healthport: 8080initialDelaySeconds: 10readinessProbe:httpGet:path: /readyport: 8080
Full-Stack App (Part 3)
# Full Stack Application (final)# 9. Backend ServiceapiVersion: v1kind: Servicemetadata:name: backend-servicenamespace: my-appspec:selector:app: backendports:- port: 80targetPort: 8080---# 10. Frontend DeploymentapiVersion: apps/v1kind: Deploymentmetadata:name: frontendnamespace: my-appspec:replicas: 2selector:matchLabels:app: frontendtemplate:metadata:labels:app: frontendspec:containers:- name: frontendimage: myapp/frontend:v1.0.0ports:- containerPort: 80env:- name: API_URLvalue: "http://backend-service"---# 11. Frontend ServiceapiVersion: v1kind: Servicemetadata:name: frontend-servicenamespace: my-appspec:selector:app: frontendports:- port: 80targetPort: 80---# 12. IngressapiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: app-ingressnamespace: my-appannotations:nginx.ingress.kubernetes.io/ssl-redirect: "true"cert-manager.io/cluster-issuer: letsencrypt-prodspec:ingressClassName: nginxtls:- hosts:- myapp.example.com- api.myapp.example.comsecretName: myapp-tlsrules:- host: myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: frontend-serviceport:number: 80- host: api.myapp.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: backend-serviceport:number: 80
CI/CD Pipeline
# CI/CD Pipeline with Kubernetes# GitHub Actions workflow example:name: Deploy to Kuberneteson:push:branches: [main]jobs:build-and-deploy:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Build Docker imagerun: |docker build -t myapp:${{ github.sha }} .docker tag myapp:${{ github.sha }} ghcr.io/myorg/myapp:${{ github.sha }}- name: Push to registryrun: |echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdindocker push ghcr.io/myorg/myapp:${{ github.sha }}- name: Configure kubectluses: azure/k8s-set-context@v3with:kubeconfig: ${{ secrets.KUBE_CONFIG }}- name: Deploy to Kubernetesrun: |kubectl set image deployment/myapp \myapp=ghcr.io/myorg/myapp:${{ github.sha }} \-n productionkubectl rollout status deployment/myapp -n production
Now that you know the fundamentals, practice by creating your own cluster with Minikube or Kind, and deploy a simple application. Practice is the best way to learn Kubernetes.