intermediate devops Kubernetes 1.31 · Updated April 2026

Kubernetes Guide for Docker Users

Kubernetes 1.31 from the ground up for developers who know Docker: pods, deployments, services, and how to ship your first app to a cluster.

· 12 min read · AI-generated

Kubernetes Guide for Docker Users

Quick Overview

Kubernetes (k8s) is a container orchestration platform: it runs your Docker containers across a cluster of machines, handles restarts when things crash, scales replicas up and down, routes traffic, and manages secrets and config. If Docker answers “how do I run a container?”, Kubernetes answers “how do I run 50 containers across 10 machines reliably?” Kubernetes 1.31 is the current stable release. You already know the hard part — containers — so this guide focuses on the Kubernetes-specific concepts you need to ship something real.

# Install kubectl (the CLI)
brew install kubectl                          # macOS
# or
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl && sudo mv kubectl /usr/local/bin/

# Local cluster for development
brew install minikube && minikube start       # macOS
# or use kind (Kubernetes in Docker)
brew install kind && kind create cluster

Getting Started

# Verify your cluster connection
kubectl cluster-info
kubectl get nodes

# Run a container — the Docker equivalent of `docker run nginx`
kubectl run mynginx --image=nginx --port=80

# Check it's running
kubectl get pods

# Stream logs — same as `docker logs -f`
kubectl logs -f mynginx

# Shell into a running pod — same as `docker exec -it`
kubectl exec -it mynginx -- /bin/bash

# Delete it
kubectl delete pod mynginx

In practice, you never use kubectl run for real workloads. You write YAML manifests and apply them. But kubectl run is useful for quick debugging.

Core Concepts

ConceptDocker equivalentWhat it is
PodContainer (roughly)Smallest deployable unit — one or more containers that share a network and storage
Deploymentdocker run + restart policyManages a set of identical pods, handles rolling updates
ServicePort mapping / reverse proxyStable network endpoint for a set of pods
NamespaceVirtual cluster for isolation — default is used if you don’t specify
ConfigMap--env-fileNon-secret config, mounted as env vars or files
Secret.env with secretsBase64-encoded sensitive values (passwords, tokens)
Ingressnginx reverse proxyHTTP routing rules — maps hostnames/paths to Services
NodeDocker hostA machine (VM or bare metal) in the cluster

The relationship that trips up Docker users: A Pod is not a container — it’s a wrapper around one or more containers that always land on the same machine and share localhost. Most Pods have one container. You define a Deployment that says “I want 3 replicas of this Pod”, and Kubernetes makes it so.

Essential Commands

Viewing resources

# List resources — works for any resource type
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get all                  # everything in the default namespace

# With more detail
kubectl get pods -o wide         # shows IP and node
kubectl get pods -o yaml         # full YAML definition
kubectl describe pod mypod       # human-readable detail + events

# Watch for changes in real time
kubectl get pods -w

Applying and managing manifests

# Apply a manifest (create or update)
kubectl apply -f deployment.yaml

# Apply everything in a directory
kubectl apply -f ./k8s/

# Delete what a manifest created
kubectl delete -f deployment.yaml

# Edit a live resource in your $EDITOR
kubectl edit deployment myapp

# Force restart all pods in a deployment (no config change)
kubectl rollout restart deployment/myapp

Debugging

# Get logs — last 100 lines
kubectl logs deployment/myapp --tail=100

# Logs from a specific container in a multi-container pod
kubectl logs mypod -c sidecar-container

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

# Copy files to/from a pod
kubectl cp mypod:/app/logs/error.log ./error.log

# Port-forward to reach a pod or service locally
kubectl port-forward deployment/myapp 8080:80
kubectl port-forward service/myapp 8080:80

Namespaces

# List namespaces
kubectl get namespaces

# Run a command in a specific namespace
kubectl get pods -n kube-system

# Set a default namespace for your session
kubectl config set-context --current --namespace=myapp

Common Patterns

Pattern 1: A complete web app deployment

This is the minimum viable Kubernetes setup for a stateless web app — a Deployment and a Service.

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myrepo/myapp:v1.2.0   # always use a specific tag, not :latest
          ports:
            - containerPort: 8080
          env:
            - name: PORT
              value: "8080"
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "500m"
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp        # matches pods with this label
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP     # internal-only; use LoadBalancer for cloud or Ingress for HTTP routing
kubectl apply -f deployment.yaml
kubectl get pods -w   # watch pods come up

Pattern 2: Config and secrets

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
data:
  LOG_LEVEL: "info"
  FEATURE_FLAG_DARK_MODE: "true"
---
# secret.yaml — values must be base64 encoded
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
type: Opaque
data:
  # echo -n "mysecretpassword" | base64
  DB_PASSWORD: bXlzZWNyZXRwYXNzd29yZA==
# Reference them in your Deployment
spec:
  containers:
    - name: myapp
      envFrom:
        - configMapRef:
            name: myapp-config     # inject all ConfigMap keys as env vars
      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: myapp-secrets
              key: DB_PASSWORD

Pattern 3: Rolling updates and rollbacks

# Update the image — triggers a rolling update with zero downtime
kubectl set image deployment/myapp myapp=myrepo/myapp:v1.3.0

# Watch the rollout
kubectl rollout status deployment/myapp

# Something went wrong — roll back to the previous version
kubectl rollout undo deployment/myapp

# Roll back to a specific revision
kubectl rollout history deployment/myapp
kubectl rollout undo deployment/myapp --to-revision=2

Gotchas & Tips

Never use :latest in production. If a node restarts and pulls a new :latest image, you can end up with different versions running in the same deployment. Pin to a specific tag (v1.2.0) or image digest.

Resources matter more than you think. Without resources.requests, Kubernetes can’t make scheduling decisions, and your pods may end up on overloaded nodes. Without resources.limits, a runaway process can consume an entire node’s memory. Set both.

kubectl apply vs kubectl create: Use apply — it’s idempotent and works for both creating and updating. create fails if the resource already exists.

Readiness probes prevent bad deploys. Without a readinessProbe, Kubernetes sends traffic to pods the moment they start, before your app is actually ready. Define a health endpoint and use it.

Secrets are not actually secret by default. kubectl get secret myapp-secrets -o yaml will show you the base64-decoded values if you have RBAC access. Base64 is encoding, not encryption. For real secret management, integrate with Vault, AWS Secrets Manager, or use Kubernetes External Secrets Operator.

kubectl delete pod is not destructive. The Deployment controller immediately creates a replacement. If you want to reduce replicas, scale the deployment: kubectl scale deployment/myapp --replicas=2.

As of Kubernetes 1.25, PodSecurityPolicy is removed. If you’re following older tutorials that use PSP, they’re outdated. The replacement is Pod Security Admission (PSA) with labels on namespaces.

Kubeconfig contexts let you switch clusters. If you work with multiple clusters (dev, staging, prod):

# List contexts
kubectl config get-contexts

# Switch context
kubectl config use-context prod-cluster

# Or scope a single command with --context
kubectl get pods --context=staging-cluster

Next Steps

  • Official docs: kubernetes.io/docs — the Tasks and Concepts sections are the best starting point
  • Helm: the package manager for Kubernetes — learn it once you have basic k8s working; most production apps are deployed via Helm charts
  • k9s: a terminal UI for Kubernetes that replaces 80% of your kubectl usage — brew install k9s
  • Related: Kubernetes networking is its own rabbit hole — once you’re comfortable with Deployments and Services, dig into Ingress controllers (ingress-nginx is the standard) and NetworkPolicies

Source: z2h.fyi/cheatsheets/kubernetes-guide — Zero to Hero cheatsheets for developers.