☸️ kubectl Zero-To-Hero β€” A Hands-On Learning in 10 Days Roadmap

Learn kubectl from zero to production-ready in 10 focused days.
Each day has a clear goal, key concepts, commands to practice, and a checkpoint task to commit to your repo.


πŸ“‹ Table of Contents


Prerequisites

You don’t need Kubernetes experience. You just need:

  • A terminal (Linux/macOS/WSL on Windows)
  • Basic command-line comfort (cd, ls, cat)
  • A cluster to practice on β€” pick one:
  • Minikube β€” runs locally on your machine
  • Kind β€” Kubernetes in Docker
  • k3s β€” lightweight, great for VMs
  • Play with Kubernetes β€” free browser-based cluster

How to Use This Guide

  1. Fork or clone this repo to track your progress
  2. Work through one day at a time β€” don’t skip ahead
  3. Run every command yourself β€” reading is not enough
  4. Complete the checkpoint at the end of each day
  5. Commit your work β€” push your YAML files and notes to this repo as you go

Suggested repo structure as you progress:

kubectl-learning/
β”œβ”€β”€ README.md
β”œβ”€β”€ day-01/
β”‚   └── notes.md
β”œβ”€β”€ day-02/
β”‚   └── notes.md
β”œβ”€β”€ day-03/
β”‚   β”œβ”€β”€ my-first-pod.yaml
β”‚   └── notes.md
β”œβ”€β”€ day-04/
β”‚   β”œβ”€β”€ deployment.yaml
β”‚   └── notes.md
...
└── day-10/
    β”œβ”€β”€ deployment.yaml
    β”œβ”€β”€ service.yaml
    β”œβ”€β”€ configmap.yaml
    β”œβ”€β”€ secret.yaml
    └── notes.md

Roadmap Overview

Day Topic Goal
1 Why kubectl exists Understand the problem it solves
2 First commands Get comfortable with the CLI
3 Pods Understand what actually runs
4 Deployments & ReplicaSets Run apps the Kubernetes way
5 Services & Networking Make apps reachable
6 Config & Secrets Stop hardcoding configs
7 Debugging Be useful during outages
8 YAML mastery Read & write manifests confidently
9 Multiple environments Real-world kubectl usage
10 Mini project Cement everything

Day 1 – Why kubectl Exists

Goal: Understand the problem kubectl solves before touching any commands.

Concepts

  • Kubernetes is a system that manages containers across multiple machines. It has two parts:
  • Control plane β€” the brain (API server, scheduler, etcd)
  • Nodes β€” the workers that actually run your containers
  • kubectl is a command-line tool that talks to the Kubernetes API server. It’s how you tell Kubernetes what you want.
  • Declarative vs Imperative:
  • Imperative β€” β€œDo this now” (kubectl run, kubectl delete)
  • Declarative β€” β€œHere’s what I want, make it so” (kubectl apply -f file.yaml)
  • Kubernetes prefers declarative. So should you.
  • kubectl vs other tools:
  • Kubernetes Dashboard β€” GUI, good for viewing, not for automation
  • Helm β€” package manager built on top of kubectl
  • GitOps tools (ArgoCD, Flux) β€” apply YAML from Git automatically; kubectl is still under the hood

Setup

Install kubectl:

# macOS
brew install kubectl

# Linux
curl -LO "https://dl.k8s.io/release/$(curl -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl && sudo mv kubectl /usr/local/bin/

# Verify
kubectl version --client

Start a local cluster (choose one):

# Minikube
minikube start

# Kind
kind create cluster

# Verify cluster access
kubectl cluster-info
kubectl get nodes

βœ… Day 1 Checkpoint

  • [ ] kubectl installed and kubectl version --client shows output
  • [ ] Cluster running and kubectl get nodes shows a Ready node
  • [ ] Create day-01/notes.md explaining in your own words: what is the API server, and why does kubectl talk to it?

Day 2 – First kubectl Commands

Goal: Get comfortable navigating a cluster from the CLI.

Core Commands

# List resources
kubectl get pods
kubectl get nodes
kubectl get all

# Get more details
kubectl get pods -o wide          # shows IP, node
kubectl get pods -o yaml          # full YAML output

# Inspect a specific resource
kubectl describe pod <pod-name>   # human-readable details + events

# Understand any resource
kubectl explain pod
kubectl explain pod.spec
kubectl explain deployment.spec.template

Namespaces

Namespaces are like folders β€” they group and isolate resources.

kubectl get namespaces
kubectl get pods --namespace kube-system   # system pods
kubectl get pods -n kube-system            # shorthand
kubectl get pods --all-namespaces          # everything

Contexts & Clusters

A context = cluster + user + namespace. Useful when you have multiple clusters.

kubectl config view                        # see all contexts
kubectl config current-context            # which context is active
kubectl config use-context <name>         # switch context
kubectl config get-contexts               # list all contexts

βœ… Day 2 Checkpoint

  • [ ] Run kubectl get all -n kube-system and understand what you see
  • [ ] Use kubectl explain on at least 3 different resources
  • [ ] Create day-02/notes.md: What’s the difference between get and describe?

Day 3 – Pods (The Core Unit)

Goal: Understand what actually runs in Kubernetes.

What is a Pod?

  • The smallest deployable unit in Kubernetes
  • Wraps one or more containers that share network and storage
  • Pods are ephemeral β€” they die, they don’t come back on their own
  • You rarely create pods directly in production (use Deployments instead)

Create a Pod β€” Imperative

# Run a pod quickly
kubectl run my-pod --image=nginx

# Check it
kubectl get pods
kubectl describe pod my-pod

Create a Pod β€” Declarative (YAML)

Save this as day-03/my-first-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: demo
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
# Apply it
kubectl apply -f day-03/my-first-pod.yaml

# Difference between apply and create:
# apply  β€” creates if not exists, updates if exists (idempotent)
# create β€” fails if resource already exists

Pod Lifecycle

Phase Meaning
Pending Scheduled but container not started yet
Running At least one container is running
Succeeded All containers exited successfully
Failed At least one container exited with error
Unknown Node communication lost

Logs & Exec

# View logs
kubectl logs my-pod
kubectl logs my-pod -f                    # follow (stream live)
kubectl logs my-pod --previous            # logs from last crashed container

# Execute commands inside a container
kubectl exec -it my-pod -- /bin/bash
kubectl exec -it my-pod -- ls /etc/nginx
kubectl exec my-pod -- cat /etc/hosts

# Clean up
kubectl delete pod my-pod
kubectl delete -f day-03/my-first-pod.yaml

βœ… Day 3 Checkpoint

  • [ ] Create a pod using YAML and commit the file to day-03/
  • [ ] Shell into the pod and run a command
  • [ ] Create day-03/notes.md: Why are pods ephemeral, and why does that matter?

Day 4 – Deployments & ReplicaSets

Goal: Run apps the right way in Kubernetes.

Why Not Just Use Pods?

Problem What Happens
Pod crashes It’s gone β€” nothing restarts it
Need 3 copies You have to create 3 pods manually
Want to update your app You have to delete and recreate pods

Deployments solve all of this.

How It Works

Deployment
  └── manages ReplicaSet
        └── manages Pods (n replicas)

A ReplicaSet ensures N copies of a pod are always running. A Deployment manages ReplicaSets and handles updates.

Create a Deployment

# Imperative
kubectl create deployment my-app --image=nginx --replicas=3

# Check what was created
kubectl get deployments
kubectl get replicasets
kubectl get pods

Save as day-04/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
kubectl apply -f day-04/deployment.yaml

Scaling

kubectl scale deployment my-app --replicas=5
kubectl get pods    # watch 5 pods come up

Rolling Updates & Rollbacks

# Update the image (triggers a rolling update)
kubectl set image deployment/my-app nginx=nginx:1.26

# Watch the rollout
kubectl rollout status deployment/my-app

# See history
kubectl rollout history deployment/my-app

# Undo last update
kubectl rollout undo deployment/my-app

# Undo to a specific revision
kubectl rollout undo deployment/my-app --to-revision=1

βœ… Day 4 Checkpoint

  • [ ] Deploy 3 replicas, then scale to 5
  • [ ] Do a rolling update and watch kubectl rollout status
  • [ ] Roll back and confirm the old image is running
  • [ ] Commit day-04/deployment.yaml

Day 5 – Services & Networking

Goal: Make your application reachable.

The Problem

Pods have IP addresses, but they change when pods restart. You need a stable endpoint to reach your app. That’s what a Service is.

Service Types

Type Access When to Use
ClusterIP Inside cluster only (default) Internal microservices
NodePort Via node’s IP + a port (30000-32767) Local dev / testing
LoadBalancer External IP via cloud load balancer Production on cloud

How Services Find Pods

Services use label selectors to find pods. If a pod has the label app: my-app, a service with selector app: my-app will route traffic to it.

Expose a Deployment

# Imperative
kubectl expose deployment my-app --port=80 --type=NodePort

# Check it
kubectl get svc
kubectl describe svc my-app

Save as day-05/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
spec:
  selector:
    app: my-app        # matches pods with this label
  ports:
  - port: 80           # service port
    targetPort: 80     # container port
  type: NodePort
kubectl apply -f day-05/service.yaml

# On Minikube, get the URL
minikube service my-app-svc --url

# Port-forward (works on any cluster)
kubectl port-forward svc/my-app-svc 8080:80
# Now open http://localhost:8080

βœ… Day 5 Checkpoint

  • [ ] Expose your deployment and reach it from your browser or curl
  • [ ] Commit day-05/service.yaml
  • [ ] Create day-05/notes.md: What would happen if a pod’s label didn’t match the service selector?

Day 6 – Config & Secrets

Goal: Never hardcode configuration again.

ConfigMaps

Store non-sensitive config (URLs, feature flags, settings).

# Create from literal values
kubectl create configmap app-config \
  --from-literal=APP_ENV=production \
  --from-literal=LOG_LEVEL=info

# Create from a file
kubectl create configmap app-config --from-file=config.properties

# View it
kubectl get configmap app-config -o yaml

Save as day-06/configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: "production"
  LOG_LEVEL: "info"
  DATABASE_URL: "postgres://db-service:5432/mydb"

Secrets

Store sensitive data (passwords, tokens, API keys). Base64-encoded, not encrypted by default β€” but can be encrypted at rest.

# Create a secret
kubectl create secret generic db-secret \
  --from-literal=DB_PASSWORD=supersecret \
  --from-literal=API_KEY=myapikey123

# View it (values are base64 encoded)
kubectl get secret db-secret -o yaml

# Decode a value
kubectl get secret db-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d

Use Config in a Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: nginx
        env:
        # From ConfigMap
        - name: APP_ENV
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_ENV
        # From Secret
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DB_PASSWORD

βœ… Day 6 Checkpoint

  • [ ] Create a ConfigMap and a Secret
  • [ ] Deploy an app that reads from both
  • [ ] Exec into the pod and verify: kubectl exec -it <pod> -- env | grep APP_ENV
  • [ ] Commit day-06/configmap.yaml (never commit real secrets to Git!)

Day 7 – Debugging Like a Pro

Goal: Be useful when things break.

The Debug Workflow

1. kubectl get pods           β†’ Is the pod running?
2. kubectl describe pod       β†’ What events happened?
3. kubectl logs               β†’ What did the app say?
4. kubectl exec               β†’ Can I get inside?

Common Problems & How to Fix Them

CrashLoopBackOff

kubectl describe pod <pod-name>   # look at Events section
kubectl logs <pod-name>           # app crash logs
kubectl logs <pod-name> --previous # logs from before last crash

Causes: app error on startup, bad config, missing env vars, wrong command

ImagePullBackOff / ErrImagePull

kubectl describe pod <pod-name>   # check Events for image pull error

Causes: wrong image name, wrong tag, private registry without credentials

Pending Pod (never starts)

kubectl describe pod <pod-name>   # look for "Insufficient CPU/memory"
kubectl get nodes                 # are nodes Ready?

Causes: not enough resources, node selector mismatch, taints

OOMKilled (Out of Memory)

kubectl describe pod <pod-name>   # look for OOMKilled in Last State

Causes: memory limit too low, memory leak in app

Useful Debug Commands

# Watch pods in real time
kubectl get pods -w

# Get events for the whole namespace
kubectl get events --sort-by=.lastTimestamp

# Describe a node (check capacity)
kubectl describe node <node-name>

# Run a temporary debug pod
kubectl run debug --image=busybox --rm -it --restart=Never -- sh

# Check resource usage (requires metrics-server)
kubectl top pods
kubectl top nodes

βœ… Day 7 Checkpoint

  • [ ] Deliberately break a deployment (wrong image tag, e.g. nginx:doesnotexist)
  • [ ] Debug it using only describe, logs, and events
  • [ ] Fix it with a correct image and do a rollout
  • [ ] Create day-07/notes.md: Walk through your debug session step by step

Day 8 – YAML Mastery

Goal: Read and write Kubernetes manifests confidently.

The 4 Top-Level Fields (Every Resource Has These)

apiVersion: apps/v1   # API group + version
kind: Deployment      # what type of resource
metadata:             # name, namespace, labels, annotations
  name: my-app
  namespace: default
  labels:
    app: my-app
    env: production
  annotations:
    description: "My production app"
spec:                 # desired state β€” differs per resource type
  ...

Labels vs Annotations

Labels Annotations
Purpose Selection & grouping Metadata & documentation
Used by Selectors, services Tools, humans
Queryable Yes (-l app=my-app) No

Resource Requests & Limits

spec:
  containers:
  - name: app
    image: nginx
    resources:
      requests:          # minimum guaranteed
        cpu: "100m"      # 100 millicores = 0.1 CPU
        memory: "128Mi"
      limits:            # maximum allowed
        cpu: "500m"
        memory: "256Mi"

Liveness & Readiness Probes

spec:
  containers:
  - name: app
    image: nginx
    livenessProbe:       # if this fails β†’ restart container
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 5
    readinessProbe:      # if this fails β†’ remove from Service endpoints
      httpGet:
        path: /ready
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 3

Validate Your YAML

# Dry run β€” check without applying
kubectl apply -f my-file.yaml --dry-run=client

# Validate server-side
kubectl apply -f my-file.yaml --dry-run=server

# Diff what would change
kubectl diff -f my-file.yaml

βœ… Day 8 Checkpoint

  • [ ] Write a complete Deployment YAML from scratch (no copy-paste)
  • [ ] Include: resource limits, a liveness probe, labels, annotations
  • [ ] Validate with --dry-run=client before applying
  • [ ] Commit as day-08/deployment-with-probes.yaml

Day 9 – Working with Multiple Environments

Goal: Manage apps across dev, staging, and production.

Namespaces for Environment Separation

# Create namespaces
kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace production

# Deploy to a specific namespace
kubectl apply -f deployment.yaml -n dev
kubectl apply -f deployment.yaml -n staging

# View resources per namespace
kubectl get all -n dev
kubectl get all -n staging

Context Switching

A kubeconfig file (usually at ~/.kube/config) holds all your cluster connections.

# View all contexts
kubectl config get-contexts

# Switch context
kubectl config use-context my-prod-cluster

# Set a default namespace for a context
kubectl config set-context --current --namespace=dev

# Rename a context
kubectl config rename-context old-name new-name

Tip: Install kubectx and kubens for faster switching:

brew install kubectx     # includes both kubectx and kubens
kubectx                  # list contexts
kubectx my-prod          # switch cluster
kubens dev               # switch namespace

Safe Cluster Access Practices

# Always check which context you're in before destructive operations
kubectl config current-context

# Use --dry-run before applying in production
kubectl apply -f deployment.yaml --dry-run=server -n production

# Use aliases to reduce mistakes
alias kdev='kubectl -n dev'
alias kprod='kubectl -n production'

βœ… Day 9 Checkpoint

  • [ ] Create dev and staging namespaces
  • [ ] Deploy your app to both with different ConfigMap values
  • [ ] Practice switching between them with kubectx/kubens or kubectl config use-context
  • [ ] Create day-09/notes.md: How would you prevent someone from accidentally running kubectl delete in production?

Day 10 – Mini Project

Goal: Tie everything together into one real-world workflow.

What You’ll Build

A complete application stack managed entirely with kubectl:

nginx (web server)
  β”œβ”€β”€ Deployment (3 replicas)
  β”œβ”€β”€ Service (NodePort)
  β”œβ”€β”€ ConfigMap (app settings)
  └── Secret (fake API key)

Step 1 β€” Create the namespace

kubectl create namespace mini-project

Step 2 β€” Apply all manifests

Save each file in day-10/, then:

kubectl apply -f day-10/ -n mini-project

day-10/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_NAME: "My kubectl App"
  LOG_LEVEL: "info"

day-10/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  API_KEY: bXlzZWNyZXRrZXkxMjM=   # base64 of "mysecretkey123"

day-10/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        env:
        - name: APP_NAME
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_NAME
        - name: API_KEY
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: API_KEY
        resources:
          requests:
            cpu: "100m"
            memory: "64Mi"
          limits:
            cpu: "200m"
            memory: "128Mi"
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5

day-10/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
spec:
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 80
  type: NodePort

Step 3 β€” Verify everything

kubectl get all -n mini-project
kubectl port-forward svc/my-app-svc 8080:80 -n mini-project
curl http://localhost:8080

Step 4 β€” Rolling update

kubectl set image deployment/my-app nginx=nginx:1.26 -n mini-project
kubectl rollout status deployment/my-app -n mini-project

Step 5 β€” Break it and debug it

# Set a bad image
kubectl set image deployment/my-app nginx=nginx:thisdoesnotexist -n mini-project

# Debug it
kubectl get pods -n mini-project
kubectl describe pod <pod-name> -n mini-project

# Roll back
kubectl rollout undo deployment/my-app -n mini-project
kubectl rollout status deployment/my-app -n mini-project

βœ… Day 10 Checkpoint

  • [ ] All 4 manifests applied and app is reachable
  • [ ] Rolling update completed successfully
  • [ ] Deliberately broken, debugged, and rolled back
  • [ ] Everything committed to day-10/
  • [ ] Write a short day-10/notes.md β€” what was the hardest part? What clicked?

Progress Tracker

Update this as you go:

Day Topic Status Notes
1 Why kubectl exists ⬜ Not started
2 First commands ⬜ Not started
3 Pods ⬜ Not started
4 Deployments ⬜ Not started
5 Services ⬜ Not started
6 Config & Secrets ⬜ Not started
7 Debugging ⬜ Not started
8 YAML mastery ⬜ Not started
9 Multi-environment ⬜ Not started
10 Mini project ⬜ Not started

Replace ⬜ with βœ… as you complete each day.


What You’ll Know After This Roadmap

  • βœ… Confident with kubectl in daily use
  • βœ… Understand Kubernetes primitives (Pod, Deployment, Service, ConfigMap, Secret)
  • βœ… Debug real production issues systematically
  • βœ… Manage apps across multiple environments
  • βœ… Write clean, production-ready YAML
  • βœ… Ready for real Kubernetes work

Useful Resources

Resource Link
Official kubectl docs https://kubernetes.io/docs/reference/kubectl/
kubectl cheat sheet https://kubernetes.io/docs/reference/kubectl/cheatsheet/
Kubernetes concepts https://kubernetes.io/docs/concepts/
Minikube getting started https://minikube.sigs.k8s.io/docs/start/
Kind quickstart https://kind.sigs.k8s.io/docs/user/quick-start/
Interactive Kubernetes tutorial https://kubernetes.io/docs/tutorials/kubernetes-basics/
kubectx/kubens https://github.com/ahmetb/kubectx

Quick Reference β€” Most Used Commands

# Get resources
kubectl get pods / nodes / deployments / svc / configmaps / secrets / all

# Inspect
kubectl describe <resource> <name>
kubectl logs <pod-name> [-f] [--previous]
kubectl exec -it <pod-name> -- /bin/bash

# Apply & manage
kubectl apply -f <file.yaml>
kubectl delete -f <file.yaml>
kubectl delete pod/svc/deployment <name>

# Deployments
kubectl scale deployment <name> --replicas=<n>
kubectl set image deployment/<name> <container>=<image>:<tag>
kubectl rollout status / history / undo deployment/<name>

# Namespaces & contexts
kubectl get all -n <namespace>
kubectl config use-context <name>
kubectl config set-context --current --namespace=<ns>

# Debug
kubectl get events --sort-by=.lastTimestamp
kubectl run debug --image=busybox --rm -it --restart=Never -- sh
kubectl apply -f file.yaml --dry-run=client

Good luck! The best way to learn kubectl is to break things, debug them, and fix them. This repo is your record of doing exactly that.


⭐ Support This Project

If this roadmap helped you, please consider starring this repository β€” it helps others find it and keeps the motivation going!

GitHub stars


✍️ Author - SWAPNIL MALI

GitHub Profile

πŸ‘¨πŸ»β€πŸ’»CS Engineer, AWS & DevOps Specialist -🎯focused on building reliable, observable, and scalable systems.