Kubernetes · lesson 1 of 10
Intermediate
6Advanced
1Also part of Kubernetes
5- + Deploying FastAPI with Docker and Kubernetes: Images, Signals, and Probes from FastAPI
- + Deployment Strategies Compared: Rolling, Blue-Green, and Canary from DevOps
- + GitOps in Practice: Git as the Source of Truth from DevOps
- + Kubernetes Pod Security Admission: Enforcing the Restricted Profile from Cloud Security
- + CIS Kubernetes Benchmark Checks with kube-bench in kind from Cloud Security
Kubernetes Fundamentals
Learn the core concepts of Kubernetes—clusters, pods, deployments, services, namespaces, and how to reason about orchestration.
By SkillByExample · Updated
What is Kubernetes?
Kubernetes (often abbreviated as K8s) is a system for running and managing containerized applications across a cluster of machines.
Instead of running a single container on a single server, Kubernetes helps you run many containers as a coordinated application — with automatic scheduling, self-healing, scaling, and rolling updates.
Theory first: desired state over manual operations
Kubernetes is fundamentally a control system: you declare desired state, and controllers continuously reconcile actual state to match it. This is different from imperative server operations where each command directly mutates runtime state.
Once this idea is clear, YAML is easier to reason about: specs describe intent, controllers handle convergence, and observability tells you whether reconciliation is succeeding.
Without Kubernetes With Kubernetes
────────────────────── ──────────────────────────────────
One server, one container Cluster of nodes
"ssh in and docker run" desired state declared in YAML
manual restarts if crash auto-restart, auto-scale, rolling update
no load balancing built-in load balancing via Services
Key Building Blocks
| Object | Role |
|---|---|
| Cluster | The full set of machines managed by Kubernetes |
| Control plane | Brain of the cluster: scheduler, API server, etcd |
| Node | A worker machine that runs your containers |
| Pod | Smallest deployable unit — wraps one or more containers |
| Deployment | Manages desired replica count and rolling updates |
| Service | Stable network endpoint that routes to matching Pods |
| Namespace | Logical partition inside a cluster for isolation |
Setting Up a Local Cluster
Option 1 — minikube (recommended for learning)
# Install minikube (macOS)
brew install minikube
# Install minikube (Linux)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Start a local cluster
minikube start
# Check cluster status
minikube status
Option 2 — kind (Kubernetes IN Docker)
# Install kind
go install sigs.k8s.io/kind@latest
# or via brew: brew install kind
# Create a cluster
kind create cluster --name dev
# Delete when done
kind delete cluster --name dev
Installing kubectl
kubectl is the CLI for talking to any Kubernetes cluster.
# macOS
brew install kubectl
# Linux
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install kubectl /usr/local/bin/kubectl
# Verify
kubectl version --client
Exploring Your Cluster
# Show cluster info (API server address)
kubectl cluster-info
# List all nodes in the cluster
kubectl get nodes
# Detailed info about a node
kubectl describe node minikube
# List all resources across namespaces
kubectl get all --all-namespaces
# Show available API resource types
kubectl api-resources
Namespaces
Namespaces give you logical isolation inside one cluster.
# List namespaces
kubectl get namespaces
# Create a namespace
kubectl create namespace my-app
# Run commands scoped to a namespace
kubectl get pods -n my-app
# Set a default namespace for your current context
kubectl config set-context --current --namespace=my-app
Built-in namespaces:
default— where resources land if you don’t specify onekube-system— Kubernetes system componentskube-public— publicly readable resources
Mental Model: Desired State
Kubernetes is built around declared desired state.
# You write this:
replicas: 3 # "I want 3 copies running"
image: nginx:1.25 # "using this image"
# Kubernetes continuously ensures:
# - if a pod crashes → start a new one
# - if a node fails → reschedule pods elsewhere
# - if you update → rolling replacement
You never say “start container X on server Y”. Instead you say “I want 3 replicas of X” and Kubernetes figures out the rest.
Your First Resource (Imperative)
# Create a pod running nginx (imperative — good for quick tests)
kubectl run my-nginx --image=nginx:1.25
# Check it's running
kubectl get pods
# See pod details
kubectl describe pod my-nginx
# View pod logs
kubectl logs my-nginx
# Open a shell inside the pod
kubectl exec -it my-nginx -- bash
# Delete it when done
kubectl delete pod my-nginx
kubectl Cheat Sheet
# Get resources
kubectl get pods
kubectl get pods -o wide # extra info (node, IP)
kubectl get pods -o yaml # full YAML spec
kubectl get pods --watch # live updates
# Describe (human-readable deep-dive)
kubectl describe pod <name>
kubectl describe node <name>
kubectl describe service <name>
# Apply a manifest file
kubectl apply -f pod.yaml
# Delete from a manifest
kubectl delete -f pod.yaml
# Shorthand resource names
kubectl get po # pods
kubectl get svc # services
kubectl get deploy # deployments
kubectl get ns # namespaces
Learning Outcomes
By the end of this tutorial you should be able to:
- Explain pods, deployments, and services
- Set up a local Kubernetes cluster with minikube or kind
- Use
kubectlto explore and manage cluster resources - Understand why desired state matters
Practice
- Create a namespace called
practice, then run themy-nginxPod from “Your First Resource” inside it. Before you list Pods, predict what a plainkubectl get podsshows.
Solution
kubectl create namespace practice
kubectl run my-nginx --image=nginx:1.25 -n practice
kubectl wait -n practice --for=condition=Ready pod/my-nginx --timeout=180s
kubectl get pods
kubectl get pods -n practice
$ kubectl create namespace practice
namespace/practice created
$ kubectl run my-nginx --image=nginx:1.25 -n practice
pod/my-nginx created
$ kubectl wait -n practice --for=condition=Ready pod/my-nginx --timeout=180s
pod/my-nginx condition met
$ kubectl get pods
No resources found in default namespace.
$ kubectl get pods -n practice
NAME READY STATUS RESTARTS AGE
my-nginx 1/1 Running 0 17s
Without -n, kubectl reads from your context’s namespace, which is default. The Pod exists,
just not where you looked. kubectl wait blocks until the Pod is Ready, so you don’t have to
re-run get pods while the image pulls.
- Use
kubectl execto ask the running container which nginx version it has and what its hostname is, without opening an interactive shell.
Solution
kubectl exec -n practice my-nginx -- nginx -v
kubectl exec -n practice my-nginx -- hostname
$ kubectl exec -n practice my-nginx -- nginx -v
nginx version: nginx/1.25.5
$ kubectl exec -n practice my-nginx -- hostname
my-nginx
Everything after -- runs inside the container, and without -it you get its output back and
nothing more. The nginx:1.25 tag resolved to patch release 1.25.5, and the container’s
hostname is the Pod’s name.
- Delete
my-nginxand list the namespace again. Does Kubernetes bring it back? Explain the answer using the desired-state model.
Solution
kubectl delete pod my-nginx -n practice
kubectl get pods -n practice
$ kubectl delete pod my-nginx -n practice
pod "my-nginx" deleted from practice namespace
$ kubectl get pods -n practice
No resources found in practice namespace.
It stays gone. kubectl run created a bare Pod, and nothing declared “I want one of these
running”, so no controller recreates it. A Deployment with replicas: 1 would replace it within
seconds, which is what the next lessons build on.
- The cheat sheet uses
nsanddeployas short names. Usekubectl api-resourcesto confirm them, and to find out which of the two objects lives inside a namespace.
Solution
kubectl api-resources | grep -E '^NAME|deployments|namespaces'
$ kubectl api-resources | grep -E '^NAME|deployments|namespaces'
NAME SHORTNAMES APIVERSION NAMESPACED KIND
namespaces ns v1 false Namespace
deployments deploy apps/v1 true Deployment
NAMESPACED false means a Namespace is cluster-wide, so it can’t sit inside another namespace.
A Deployment is namespaced, which is why kubectl get deploy needs -n to look outside
default.
Clean up with kubectl delete namespace practice. That also deletes anything left inside it.