Lesson 01 · Foundations

Stand up the cluster

Create the VM, install microk8s, and point your Mac's kubectl at it — understanding the kubeconfig handshake that makes it work.

Why this, first? You can't host a single site until you have a cluster you can talk to. And the way you talk to it — the kubeconfig — is the first place "copy-pasted magic" turns into a model you actually understand.

The mental model

Three layers. Keep them separate in your head and almost nothing about Kubernetes will confuse you later.

Your Mac — the host
multipass kubectl (client) ~/.kube/config
│ multipass launches a VM ▼    kubectl → HTTPS :16443 ▼
microk8s-vm — the node (Ubuntu)
The cluster (microk8s)
API server scheduler etcd kubelet

The control plane lives inside the VM. Your kubectl on the Mac is just an HTTP client; it never runs Kubernetes — it sends requests to the API server over the network and prints the replies.

The "why" that pays off forever Everything in Kubernetes is the same loop: you declare desired state to the API server; controllers make reality match. kubectl is your pen for writing desires. Today you just establish the pen-to-paper connection.

Do it — on your Mac

Run these on the host (your Mac terminal). $ marks a host prompt; vm$ marks a prompt inside the VM.

1

Launch the VM

Give it enough room to be a real node.

$ multipass launch --name microk8s-vm --cpus 2 --memory 4G --disk 40G
$ multipass list   # note the VM's IP, e.g. 192.168.64.x
2

Install microk8s inside the VM

$ multipass shell microk8s-vm        # drop into the VM
vm$ sudo snap install microk8s --classic
vm$ sudo usermod -a -G microk8s $USER  # run microk8s without sudo
vm$ sudo iptables -P FORWARD ACCEPT   # let cluster traffic flow
vm$ exit                              # re-enter so the group applies
$ multipass shell microk8s-vm
Note microk8s bundles its own kubectl — you call it as microk8s kubectl .... We'll use that to verify, then graduate to your Mac's own kubectl.
3

Wait for ready, then look at your node

vm$ microk8s status --wait-ready
vm$ microk8s kubectl get nodes

A line with STATUS = Ready means the cluster is alive. That one node is your VM. Leave the VM (exit) for the last step.

4

Point your Mac's kubectl at the cluster

This is the lesson's real prize. microk8s config prints a complete kubeconfig. Capture it on the host and use it:

$ multipass exec microk8s-vm -- sudo microk8s config > ~/.kube/microk8s.yaml
$ KUBECONFIG=~/.kube/microk8s.yaml kubectl get nodes
$ KUBECONFIG=~/.kube/microk8s.yaml kubectl get pods -A   # everything running

Same Ready node — but now answered by the kubectl on your Mac. You just completed the handshake.

Read your kubeconfig — the handshake, decoded

Open ~/.kube/microk8s.yaml. Three things, nothing more:

clusters: server: https://<VM-IP>:16443 + CA cert   ← which cluster + who to trust

users: client cert / token   ← who you are

contexts: binds a user ⇄ a cluster   ← the active pairing kubectl uses
Gotcha The server: URL is the VM's IP on port 16443. If you later recreate the VM, the IP changes and this file goes stale — re-run Step 4. That staleness is the lesson: kubectl has no magic discovery, only this file.

Where does the Kubernetes control plane actually run?

The control plane (API server, scheduler, etcd) runs inside the VM. kubectl on your Mac is only an HTTP client that calls it.

What does the kubeconfig file actually give kubectl?

It's an address book + keys: the API server URL, the CA to trust, and your client credentials. No discovery magic — just this file.

Primary source — read this next

MicroK8s — Install with Multipass (Canonical, official). The canonical version of exactly what you just did. Skim it and notice where their steps match ours.

Ask your teacher
Stuck on a step, or curious why something is the way it is? I'm your teacher — ask me. Good questions right now: "What's port 16443?", "Why a VM instead of running microk8s on macOS directly?", "What is a snap?"