Local Environment
Choose between minikube · kind · Docker Desktop k8s. Compare how each option works and the pros and cons of each, then install kubectl and bring up your first cluster with kind to check the nodes and system Pods — all in one pass.
In Chapter 1 What Kubernetes Is we saw the big picture of a cluster split into control plane and worker nodes. In this chapter we put that picture into practice. We compare the three ways to bring up a Kubernetes cluster on one laptop (minikube · kind · Docker Desktop k8s), install kubectl, then bring up our first cluster with kind to check the nodes and system Pods — all in one pass.
By the end of this chapter you’ll have one local cluster and the kubectl that lets you look into it. That state becomes the starting point for Chapter 3 kubectl and your first Pod onward.
Three options for local K8s #
All three tools do the same thing — “bring up one Kubernetes cluster locally” — but they differ in how they work and in their pros and cons.
| Tool | How it works | Multi-node | Start time | Recommended for |
|---|---|---|---|---|
| Docker Desktop k8s | Runs single-node K8s on a VM inside Docker Desktop | X (single node) | medium | users already using Docker Desktop on macOS · Windows |
| minikube | Runs the cluster on a VM or container driver of your choice | O (optional) | medium | when you want to use addons (ingress, dashboard, etc.) richly |
| kind | Uses each docker container as a K8s node | O | fast | lightweight, or when you want to define multi-node via YAML / CI |
Spelling it out a bit more.
Docker Desktop k8s is the lowest-effort option on macOS and Windows. If you’re already using Docker Desktop, one checkbox in the Kubernetes tab of the settings menu brings up a cluster, and kubectl’s context is automatically set to docker-desktop. The downsides are that it’s macOS · Windows only (Docker Desktop for Linux offers the same option, but circumstances vary by environment), and since it’s K8s running inside the VM Docker Desktop already brings up, it uses a fair amount of memory and CPU.
minikube is among the oldest of the local K8s tools. Depending on the environment, one of several drivers — docker / hyperkit / kvm / virtualbox, etc. — is auto-selected or you can pick one. Its biggest strength is a rich set of addons. Commonly needed extras like ingress, metrics-server, dashboard, and registry can be turned on with a one-line command.
kind is a tool whose name is its description — Kubernetes IN Docker. Since it uses a docker container as a K8s node, it’s lighter and faster than minikube / Docker Desktop, which bring up a separate VM. You can define a multi-node cluster in a short YAML, which makes it great for mimicking an environment with the control plane and workers separated, and that’s why it’s used in K8s’s own CI.
Which to pick #
If you’re already using Docker Desktop on macOS · Windows, Docker Desktop k8s is the easiest to start with. One checkbox brings up a cluster, and it ties naturally into your usual docker setup. If you’re a Linux user, want to mimic a multi-node environment, or want to create and destroy clusters frequently, kind fits well. If you want to flip addons on and off with one-line commands and experiment with various things, minikube is a good choice too.
This book lays down kind as its main option. It’s light and fast, and you can create and destroy a cluster with one or two commands, which suits learning. That said, whichever you pick, the kubectl commands from Chapter 3 on are identical. Only the way the cluster is brought up differs; the K8s resources you handle on top of it are the same. Pick the one that fits your environment and follow along.
Installing kubectl #
Wherever you bring up the cluster, the client that talks to it is the same — kubectl. It’s the CLI that sends commands over HTTP to the K8s control plane’s API server (kube-apiserver).
macOS — Homebrew #
brew install kubectlWindows — winget or Chocolatey #
winget install -e --id Kubernetes.kubectl
# or
choco install kubernetes-cliLinux — official binary #
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/Depending on the distribution you can install via a package manager (apt, dnf, etc.) too, but with K8s it’s safer to keep the client and server versions within the compatible range. If you need the exact install procedure, see the install guide at kubernetes.io.
Once installed, check the client version.
kubectl version --clientClient Version: v1.32.x
Kustomize Version: v5.x.xAt this point there’s no cluster yet, so the server version isn’t picked up. It appears once you bring up a cluster.
Bring up your first cluster with kind #
This is the main flow of the chapter. First install kind itself.
brew install kindwinget install -e --id Kubernetes.kind
# or
choco install kindcurl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
chmod +x kind
sudo mv kind /usr/local/bin/kind uses the docker daemon. Docker Desktop or the docker engine must already be running.
Now create a cluster. For a single node it’s one command.
kind create clusterCreating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.32.x)
✓ Preparing nodes
✓ Writing configuration
✓ Starting control-plane
✓ Installing CNI
✓ Installing StorageClass
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kindThe last line is the key. kubectl’s context is automatically set to kind-kind. From now on kubectl commands go to this cluster.
How kind works #
We said kind uses a docker container as a K8s node. You can confirm that’s really the case from the docker side.
docker psCONTAINER ID IMAGE COMMAND PORTS NAMES
abc123def456 kindest/node:v1.32.x "/usr/local/bin/entr…" 127.0.0.1:xxxxx->6443/tcp kind-control-planeOne container made from the kindest/node image is up, and the control plane and worker run together inside it. An arbitrary host port is mapped to the container’s 6443 (the default port of the K8s API server). kubectl sends commands to this port.
First commands — looking around nodes and system Pods #
The cluster is up, so let’s confirm that the components that were only named in Chapter 1 are actually running.
kubectl get nodesNAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 45s v1.32.xSince it’s a single-node cluster, only one line shows. This one node plays the control plane role and also takes workloads at the same time (a common setup in local environments).
Next, look at the Pods in all namespaces. K8s components often run as Pods on top of the cluster.
kubectl get pods -ANAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-xxxxxxxxxx-aaaaa 1/1 Running 0 1m
kube-system coredns-xxxxxxxxxx-bbbbb 1/1 Running 0 1m
kube-system etcd-kind-control-plane 1/1 Running 0 1m
kube-system kindnet-xxxxx 1/1 Running 0 1m
kube-system kube-apiserver-kind-control-plane 1/1 Running 0 1m
kube-system kube-controller-manager-kind-control-plane 1/1 Running 0 1m
kube-system kube-proxy-xxxxx 1/1 Running 0 1m
kube-system kube-scheduler-kind-control-plane 1/1 Running 0 1m
local-path-storage local-path-provisioner-xxxxxxxxxx-yyyyy 1/1 Running 0 1mThe components only named in Chapter 1 show up directly — kube-apiserver, etcd, kube-scheduler, kube-controller-manager, kube-proxy, and the cluster DNS coredns. On top of that, kind’s own network plugin kindnet and the local-path-provisioner that mimics PersistentVolume in a local environment are running alongside.
The kube-system namespace is the space where the Pods K8s uses for its own operation gather. Apps you create going forward go to the default namespace (or a namespace you create yourself, Chapter 7 Namespace and labels).
Finally, check the cluster’s own meta information.
kubectl cluster-infoKubernetes control plane is running at https://127.0.0.1:xxxxx
CoreDNS is running at https://127.0.0.1:xxxxx/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.The IP and port written in the first line of this output are the same place as the port mapping we saw in docker ps above. That is, kubectl is talking to the kube-apiserver inside the node container through the port docker exposed on the host.
kubeconfig — where kubectl sends its commands #
Which cluster kubectl sends commands to is decided by the kubeconfig file. The default path is as follows.
- macOS / Linux —
~/.kube/config - Windows —
%USERPROFILE%\.kube\config
This file holds three kinds of information.
| Item | Meaning |
|---|---|
| clusters | which clusters exist (API server address, CA certificate) |
| users | with what credentials you access those clusters (certificates, tokens, etc.) |
| contexts | a bundle of “this cluster + this user + this namespace.” kubectl uses one context at a time |
When kind creates a cluster, it automatically adds a context named kind-kind and sets the current context to it. Let’s check directly.
kubectl config get-contextsCURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kind-kind kind-kind kind-kindkubectl config current-contextkind-kindOnce you’re handling several clusters at once (e.g., local kind, the company dev cluster, the company prod cluster), kubectl config get-contexts shows multiple entries. The command to pick one of them and make it the current context is use-context.
kubectl config use-context kind-kindWhen you work back and forth between a company cluster and local, a habit of always being aware of the context so you don’t send commands to the wrong cluster is important. Tools that surface the current context in the shell prompt (kube-ps1, starship, etc.) are also widely used. This perspective is emphasized again in Part 4 EKS in Production (Chapter 21 EKS cluster setup).
If you bring it up with Docker Desktop k8s #
If you’re in an environment already using Docker Desktop, just turning on K8s in the settings menu brings up a cluster. The exact menu path varies slightly by Docker Desktop version, but generally it’s as follows.
- Run Docker Desktop → enter Settings (or Preferences)
- Select the Kubernetes tab in the left menu
- Check Enable Kubernetes → Apply & Restart
The first time you enable it, it takes a few minutes to pull the K8s component images. When done, kubectl’s context is added automatically.
kubectl config use-context docker-desktop
kubectl get nodesNAME STATUS ROLES AGE VERSION
docker-desktop Ready control-plane 2m v1.32.xThe kubectl commands after this are completely identical to kind.
If you bring it up with minikube #
minikube is similar. First install the minikube CLI (official guide: minikube.sigs.k8s.io), then start the cluster.
minikube startIf you want to pick a driver explicitly, pass the --driver option. The default driver is auto-selected as docker / hyperkit / kvm, etc., depending on the environment.
minikube start --driver=dockerOnce minikube is up, the context is set to minikube.
kubectl config use-context minikube
kubectl get nodesOne of minikube’s draws, addons, is handled with the minikube addons command. For example, to turn on the ingress controller, do this.
minikube addons enable ingressCleanup and teardown #
When you’re done learning or want to create a cluster fresh, it’s good to know how to tear things down cleanly too.
kind
kind delete clusterIf you never gave it a name, the cluster with the default name (kind) is deleted. If you ran several clusters at once, specify with --name.
Docker Desktop k8s
Check Disable Kubernetes in the Kubernetes tab of the settings. Or you can reset it with the Reset Kubernetes Cluster button on the same screen.
minikube
minikube stop # pause (can start again next time)
minikube delete # delete completelyA big advantage of a local cluster is the lightness of being able to delete and recreate it anytime. When you decide something is tangled up, deleting it cleanly and bringing it up again is often faster.
Exercises #
- In light of your environment (OS, whether you use Docker Desktop, whether you intend to learn multi-node), decide in one line which of the three options (Docker Desktop k8s / minikube / kind) you’ll use as your main one, and write a paragraph about why, against the criteria in §“Which to pick.” Since in Part 4 EKS in Production you’ll end up talking to the EKS control plane with the same
kubectl, also note how your local choice connects to the EKS flow. - After bringing up a cluster with kind as in the body, organize into a table the roles of the 9 system Pods that appear in the
kubectl get pods -Aoutput, paired with the component descriptions in Chapter 1 §“The big picture of a K8s cluster.”kindnetandlocal-path-provisionerare components that don’t appear in Chapter 1; note which area (network / storage) they belong to. - Check which contexts
kubectl config get-contextsshows in your current environment. If there are two or more contexts (e.g., whenkind-kindanddocker-desktopare both picked up), switch between them withuse-contextand confirm directly howkubectl get nodesresults differ. When you start handling a company cluster too, this habit becomes a safeguard.
In one line: local K8s has three options — Docker Desktop k8s · minikube · kind — and whichever you pick, the K8s resources you handle on top are identical. This book’s main option is kind. Which cluster
kubectlsends commands to is decided by the context in kubeconfig.
Next chapter #
In Chapter 3 kubectl and your first Pod we cover the Pod, K8s’s smallest execution unit. We see both the imperative path of bringing one up with kubectl run and the declarative path of bringing one up with a YAML manifest, and the flow of looking into Pods with everyday commands like kubectl get / describe / logs / exec. It’s the real start of K8s.