Set Up a Kubernetes Cluster with kind, minikube or a Cloud Service
Install kubectl, kind and Helm, create a three-node Kubernetes 1.37 cluster locally, use contexts and namespaces, or create a DOKS, EKS or kubeadm cluster.
TLDR: Install kubectl, kind and helm, then run kind create cluster --config kind-config.yaml to get a three-node Kubernetes 1.37 cluster inside Docker in about a minute. kubectl talks to it through a context in ~/.kube/config. For production, use a managed service such as DigitalOcean Kubernetes, EKS, GKE or AKS, or build your own with kubeadm.
In this part you install the tools, create the cluster that the rest of the guide uses, learn how kubeconfig contexts and namespaces work, and see the other ways to run Kubernetes, from minikube to kubeadm on your own servers.
Prerequisites
- Docker Desktop (macOS, Windows) or Docker Engine (Linux), running. On Windows, use WSL 2 with Docker Desktop's WSL integration, and run every command of this guide in the WSL terminal; the commands are written for Bash. kind starts each Kubernetes node as a container. Podman also works with kind, but kind's support for it is experimental.
- Give Docker at least 4 CPUs and 6 GB of memory if you use Docker Desktop (Settings, Resources).
- The companion repository, cloned. Every command in this guide runs from its root directory:
git clone https://github.com/The-DevOps-Daily/guide-kubernetes-demo-2026-10-24.git
cd guide-kubernetes-demo-2026-10-24
Ways to Run Kubernetes
| Option | What it is | Good for |
|---|---|---|
| kind | Kubernetes nodes as Docker containers; the project's own test tool | Learning, CI, multi-node tests on a laptop |
| minikube | A single- or multi-node cluster in a VM or container | Learning, with built-in add-ons |
| k3d / k3s | k3s, a small Kubernetes distribution, in Docker or on a server | Laptops, edge devices, small servers |
| Docker Desktop / Rancher Desktop | A cluster you switch on in the app's settings | A quick start if you already use the app |
| Managed (DOKS, EKS, GKE, AKS) | The provider runs the control plane; you pay for worker nodes | Production for most teams |
| kubeadm (or Kubespray, Talos) | You install and run every component on your own machines | Full control, on-premises, learning internals |
This guide uses kind because it gives you real multi-node behavior (scheduling across nodes, draining a node, node-local storage) on one computer, and because the same commands run in CI. Everything you learn applies to the other options.
Install kubectl, kind and Helm
kubectl is the command-line client for the Kubernetes API. kind creates the local cluster. Helm installs packaged applications (charts); you use it in Part 9.
Check the versions:
kubectl supports API servers one minor version older or newer than itself, so kubectl 1.37 works with clusters from 1.36 to 1.38. If you manage clusters on several versions, keep a kubectl that is no more than one minor version away from each.
Create the Cluster
The cluster for this guide has one control plane node and two worker nodes. The file also maps port 30080 of the control plane container to port 30080 on 127.0.0.1, which Part 5 uses for a NodePort Service. Binding to 127.0.0.1 keeps other machines on your network from reaching it:
# A local cluster with one control plane node and two worker nodes.
# kind v0.33.0 runs Kubernetes v1.37.0 on these nodes by default.
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: k8s-guide
nodes:
- role: control-plane
extraPortMappings:
# Makes NodePort 30080 reachable as localhost:30080 (Part 5), and only from this computer
- containerPort: 30080
hostPort: 30080
listenAddress: '127.0.0.1'
- role: worker
- role: worker
Create the cluster. kind pulls the node image the first time, so this takes a minute or two:
kind create cluster --config kind-config.yaml
Creating cluster "k8s-guide" ...
âĸ Ensuring node image (kindest/node:v1.37.0) đŧī¸ ...
â Ensuring node image (kindest/node:v1.37.0) đŧī¸
âĸ Preparing nodes đĻ đĻ đĻ ...
â Preparing nodes đĻ đĻ đĻ
âĸ Writing configuration đ ...
â Writing configuration đ
âĸ Starting control-plane đšī¸ ...
â Starting control-plane đšī¸
âĸ Installing CNI đ ...
â Installing CNI đ
âĸ Installing StorageClass đž ...
â Installing StorageClass đž
âĸ Joining worker nodes đ ...
â Joining worker nodes đ
Set kubectl context to "kind-k8s-guide"
You can now use your cluster with:
kubectl cluster-info --context kind-k8s-guide
Have a nice day! đ
kind also wrote a context called kind-k8s-guide into ~/.kube/config and made it the current one, so kubectl now talks to the new cluster:
The nodes report NotReady for the first few seconds, until the network plugin runs on each of them. Wait for them instead of guessing:
Each node is a Debian 13 container that runs containerd and the kubelet. You can see them with Docker; the API server is published on a random port on 127.0.0.1:
kind also installed a default StorageClass that creates volumes in a directory on the node (Part 7):
kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
standard (default) rancher.io/local-path Delete WaitForFirstConsumer false 24s
Contexts and kubeconfig
kubectl reads its configuration from ~/.kube/config (or the files listed in the KUBECONFIG variable). The file has three lists: clusters (API server addresses and CA certificates), users (credentials) and contexts, which pair a cluster with a user and a default namespace. The current context decides where every kubectl command goes.
kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kind-k8s-guide kind-k8s-guide kind-k8s-guide
When you have several clusters, switch with kubectl config use-context <name>, or run a single command elsewhere with --context <name>. Before any command that changes something, check where you are with kubectl config current-context; running a delete against the wrong cluster is one of the most common and expensive Kubernetes mistakes.
Your own preferences, such as aliases and default flags, belong in ~/.kube/kuberc (beta and on by default since Kubernetes 1.34), not in the kubeconfig file. That keeps them out of the credentials you share with tools and CI.
Namespaces
Every namespaced command runs in the current context's namespace, which is default until you change it. Create a namespace for the guide's app and make it the default for this context, so you do not have to type -n demo every time:
For a single command, -n <namespace> overrides the default and -A (--all-namespaces) lists objects in every namespace. More on this in how to switch namespaces in Kubernetes.
Stopping and Deleting the Cluster
The cluster keeps running until you delete it, and it starts again after a reboot if Docker does. Delete it when you are done with the guide:
kind delete cluster --name k8s-guide
Deleting cluster "k8s-guide" ...
Deleted nodes: ["k8s-guide-worker" "k8s-guide-worker2" "k8s-guide-control-plane"]
To start a later part on a fresh cluster, create it again and recreate the namespace; each part lists the manifests from earlier parts that it needs.
Other Local Options
The same app runs on these, with small differences you will notice in Parts 5 and 7 (how LoadBalancer Services get an address, and which StorageClass is the default):
# minikube v1.39 (Kubernetes 1.37 by default)
minikube start --nodes 3 --cpus 2 --memory 4g
minikube tunnel # in a second terminal: gives LoadBalancer Services an address
# k3d v5.9 (k3s in Docker, with Traefik and a LoadBalancer implementation built in)
k3d cluster create k8s-guide --agents 2
These are examples; the outputs in this guide come from kind.
Managed Kubernetes
With a managed service, the provider runs and upgrades the control plane, backs up etcd and connects the cluster to its load balancers and disks. You manage worker nodes (or not even those, with GKE Autopilot or EKS Auto Mode) and pay for them by the hour.
DigitalOcean Kubernetes (DOKS) is one of the simplest to start with. Install doctl, create an API token in the control panel, and create a cluster with two worker nodes:
doctl auth init
doctl kubernetes cluster create k8s-guide \
--region fra1 \
--node-pool "name=workers;size=s-2vcpu-4gb;count=2"
kubectl get nodes # doctl adds the context and switches to it
If you do not have a DigitalOcean account yet, you can sign up through our referral link. A new account gets DigitalOcean's standard signup credit ($5 that expires 90 days after sign-up), and you must add a payment method before you can create resources. If you later spend $25 on DigitalOcean, this site gets $25 of credit (referral program). The worker nodes are billed while they exist; delete the cluster and the load balancers and volumes it created with doctl kubernetes cluster delete k8s-guide --dangerous.
The other large providers, each with its own CLI (examples, not run for this guide):
# Amazon EKS with eksctl; Auto Mode also manages the nodes for you
eksctl create cluster --name k8s-guide --region eu-central-1 --enable-auto-mode
# Google GKE Autopilot: no nodes to manage
gcloud container clusters create-auto k8s-guide --region europe-west1
gcloud container clusters get-credentials k8s-guide --region europe-west1
# Azure AKS
az group create --name k8s-guide --location westeurope
az aks create --resource-group k8s-guide --name k8s-guide --node-count 2 --generate-ssh-keys
az aks get-credentials --resource-group k8s-guide --name k8s-guide
Managed services usually offer a new Kubernetes minor version a few weeks or months after the upstream release, and each has its own support window. Check which versions your provider offers before you plan an upgrade.
Self-Managed Clusters with kubeadm
kubeadm is the official tool for building a cluster on machines you control. Each machine needs a supported Linux with cgroup v2, swap turned off (or configured for Kubernetes), and containerd 2.x configured with the systemd cgroup driver. Install the Kubernetes packages from pkgs.k8s.io, which has one repository per minor version; the old apt.kubernetes.io and packages.cloud.google.com repositories that older guides use stopped working on 4 March 2024.
These commands are an example for Ubuntu and Debian, not run for this guide:
# On every node: the Kubernetes 1.37 package repository
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.37/deb/Release.key |
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.37/deb/ /' |
sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl # upgrade them on purpose, never by accident
sudo systemctl enable --now kubelet
# On the first control plane node
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
mkdir -p "$HOME/.kube"
sudo cp /etc/kubernetes/admin.conf "$HOME/.kube/config"
sudo chown "$(id -u):$(id -g)" "$HOME/.kube/config"
# Install a network plugin (CNI), for example Cilium or Calico, with its own instructions,
# then join each worker with the command that kubeadm init printed:
sudo kubeadm join CONTROL_PLANE_IP:6443 --token TOKEN --discovery-token-ca-cert-hash sha256:HASH
For production, run three control plane nodes behind a load balancer (kubeadm init --control-plane-endpoint), back up etcd with etcdctl snapshot save, and plan for upgrades: Kubernetes supports each minor version for about 14 months, and you upgrade one minor version at a time, control plane first, then the nodes. Kubespray automates kubeadm with Ansible, and Talos Linux and k3s are lighter alternatives.
Common Mistakes
- Running commands against the wrong cluster. Check
kubectl config current-contextbefore changes, and use a different color or prompt for production contexts. - Too little memory for Docker Desktop. Pods stay
Pendingor nodes goNotReadywhen the VM runs out of memory. Give it at least 6 GB for this guide. - Copying old install steps.
apt-key,apt.kubernetes.io, Docker as the runtime andkubernetes-xeniallines are from before 2024 and no longer work. - A kubectl far from the cluster version. Stay within one minor version of the API server.
- Forgetting cloud clusters. Managed nodes, load balancers and volumes cost money until you delete them.
Summary
kind create cluster --config kind-config.yamlgives you a three-node Kubernetes 1.37 cluster in Docker.kubectluses contexts from~/.kube/config; each context names a cluster, a user and a default namespace.- This guide's app lives in the
demonamespace, set as the default for thekind-k8s-guidecontext. - Managed services run the control plane for you; kubeadm builds a cluster on your own machines from
pkgs.k8s.iopackages.
Keep Learning
- How to switch kubectl between clusters
- List all pods and nodes in a cluster
- A 5-minute Kubernetes cluster health check
Next, in Part 3, you run your first pod on this cluster.
Tags
Found an issue?