Part 1 of 7 — "The Mac Kubernetes Lab: A Production-Mirror Setup from Scratch"
Here’s something nobody warned me about running Kubernetes on Apple Silicon: the same lab setup will work on one chip and fail silently on another. I learned this twice.
The first time was when my Multipass-based cluster broke after I moved from an M1 Pro to an M4. Everything I’d put together over months — four VMs, a kubeadm cluster, the lot — stopped working in a way the error messages couldn’t quite explain. The QEMU drivers Multipass relies on weren’t compatible with the M4’s hardware, and there was no quick fix. The setup was gone.
The second time was months later. I’d long since replaced Multipass with OrbStack on the M4, and it had been working beautifully. Out of curiosity, I tried to put the same OrbStack cluster on my old M1. The VMs came up fine. kubeadm finished. Calico installed. And then everything sat in NotReady for an entire evening while I read kernel docs to figure out why iptables NAT was silently misbehaving inside an unprivileged LXC container on one chip but not the other.
What I ended up with is a Kubernetes lab that runs on either chip, mirrors a real EKS production cluster, and taught me more about Apple’s Virtualization Framework and Linux container capabilities than I ever wanted to know.
This is part one of a seven-part series walking through that setup from scratch. By the end, you’ll have a dual-cluster Kubernetes environment on your Mac — one fast daily-driver cluster for iteration, one full VM-based cluster that mirrors production EKS, complete with Vault PKI, Istio, and Crossplane. We’ll start by replacing Multipass.
The Multipass setup that worked, then didn’t.
For most of 202,4 my local Kubernetes setup was on Multipass. Four Ubuntu VMs on my M1 Pro, a kubeadm cluster, and a working developer loop. It wasn’t fast: Multipass VMs took 30 to 60 seconds to boot, and pre-allocated memory, whether you used it or not. It worked, and it was familiar. Then I upgraded to an M4, and it stopped.
Multipass on macOS uses QEMU under the hood. The QEMU driver bundled with the version of Multipass I had didn’t play nicely with the M4’s silicon. VMs failed to launch, with errors that didn’t map cleanly to actionable issues. I spent a weekend on the Multipass GitHub issues, looking for someone with the same problem and a fix. That weekend is when I tried OrbStack instead, and I never went back.
What OrbStack is, and why the switch wasn’t just about boot time.
OrbStack is a macOS-native tool for running Linux VMs and Docker containers. The thing that matters for our purposes is that it’s built specifically for Apple Silicon, using Apple’s Virtualization Framework, written in Swift, Go, Rust, and C — not a port of something originally designed for x86.
The numbers that made me commit:
The boot time alone is a different category of experience. Spinning up a four-VM cluster used to be a “go make coffee” event. With OrbStack, the whole cluster is up in under 15 seconds.
But the part I underestimated was the networking. OrbStack shiwith a built-in Kubernetes cluster: one command and you have a working cluster with real LoadBalancer IPs and wildcard DNS out of the box. No MetalLB, and/etc/hosts editing. You apply a Service of type LoadBalancer, and you can hit it from your Mac browser at something.k8s.orb.local. The first time it just worked, I genuinely thought I had misconfigured it.
💡 Pricing note: OrbStack is free for personal use, which covers everything in this series. If you’re rolling it out across a team or using it commercially at work, check orbstack.dev/pricing. The grey area worth knowing: a home lab on your own Mac is free. A work laptop doing your day job is commercial use.
The Architecture: Two Clusters, One Tool
After a few weeks with OrbStack, I settled on a dual-cluster setup. Two clusters, two purposes.
Cluster 1 — OrbStack Native K8s (Daily Driver)
The built-in cluster handles fast iteration work:
- Crossplane compositions and provider development
- HashiCorp Vault AppRole workflows
- Helm chart testing
- Istio Gateway and VirtualService experimentation — though I break this constantly, which is fine
Switch to it with kubectx orbstack. Services are reachable at *.k8s.orb.local from your browser immediately.
Cluster 2 — VM kubeadm Cluster (EKS Mirror + CKS Lab)
Four OrbStack Linux VMs running a real kubeadm-bootstrapped cluster:
- K8s 1.34 — matching our upcoming EKS upgrade target at Arkila Systems
- Vault PKI as the cluster Certificate Authority
- Istio with revision-based upgrades, identical to our EKS approach
- Crossplane with AWS provider
- Multi-node topology (control plane + 2 workers) mirroring production
This is also my CKS exam preparation environment — Pod Security Admission, audit policies, NetworkPolicy, short-lived admin certificates via Vault.
Apple Silicon Compatibility — M1 vs M4
This is the part I didn’t see coming until I tried it.
OrbStack works flawlessly on M4. I built the entire dual-cluster setup, including the kubeadm VM cluster, and every component came up on the first try. Months later, on a whim, I tried to replicate the same setup on my M1 Pro. The VMs booted, kubeadm initialised, and I installed Calico.
Nothing worked!!
Nodes stayed NotReady. kube-proxy crashed in a loop. The tigera-operator pod logged dial tcp 10.96.0.1:443: connect: connection refused. The Calico pods looked healthy from the outside, but were completely non-functional from the inside.
The root cause turned out to be a kernel capability difference:
| M4 Mac | M1 / M2 / M3 Mac | |
|---|---|---|
| OrbStack VM type | Unprivileged LXC | Unprivileged LXC |
| iptables NAT | ✅ Works | ❌ Restricted |
| Recommended CNI | Calico | Cilium (eBPF) |
| kube-proxy | Standard | Replaced by Cilium |
OrbStack VMs run as unprivileged LXC containers on both chips. On M4, the iptables NAT table is fully writable from inside the container. On M1, M2, and M3, it isn’t! Kube-proxy can’t write the KUBE-SERVICES chain, which means ClusterIP services aren't reachable, which means any CNI plugin that tries to call the Kubernetes API server through the ClusterIP 10.96.0.1 fails to start. Calico is one of those plugins. So is half the ecosystem!
The fix is Cilium, which uses eBPF-based service routing instead of iptables and completely replaces kube-proxy. I’ll cover the full debugging walk-through and the Cilium install in Part 4, because it’s the most technically interesting thing in this series — and probably useful to anyone running unprivileged Linux containers in restricted environments, not just OrbStack on Apple Silicon.
What You'll Need
- Apple Silicon Mac (M1, M2, M3, or M4)
- Homebrew installed
- At least 16 GB RAM — 8 GB will technically work but you'll feel it when all four VMs are running
- About 20 GB free disk space
# 💻 Mac — check your chip
system_profiler SPHardwareDataType | grep Chip
# Check available disk
df -h ~
If you’re on an Intel Mac, this series isn’t for you — none of it depends on x86, but the whole point is the Apple Silicon experience, and I haven’t tested any of it on Intel.
The Multipass → OrbStack migration, if you’re coming from Multipass.
The command mapping in short:
| Multipass | OrbStack |
|---|---|
multipass launch ubuntu |
orb create ubuntu |
multipass shell <name> |
ssh <name>@orb |
multipass exec <name> -- cmd |
orb run -m <name> cmd |
multipass list |
orb list |
multipass delete <name> |
orb delete <name> |
multipass stop <name> |
orb stop <name> |
multipass stop --all |
orb stop -a |
Install OrbStack and clean out Multipass:
# 💻 Mac
brew install orbstack
open -a OrbStack # required once for first-time GUI setup
# Remove Multipass
brew uninstall multipass
sudo rm -rf /var/root/Library/Application\ Support/multipassd
sudo rm -rf ~/Library/Application\ Support/multipass
OrbStack auto-installs orb, docker, and kubectl on your PATH. If you already have any of those installed via Homebrew, you may want to check which version comes first in your shell.
What's Coming in This Series
- Part 1 (this article): Why I Replaced Multipass with OrbStack and what an M1 vs M4 Mac taught me about local Kubernetes.
- Part 2: Cluster 1 — Native K8s daily driver with Istio, Vault, Crossplane
- Part 3: Cluster 2 — VM creation, networking, and Vault PKI bootstrap
- Part 4: kubeadm 1.34 — M1 vs M4 CNI deep dive (Calico vs Cilium)
- Part 5: Istio revision-based upgrades and MetalLB on the VM cluster
- Part 6: Vault K8s auth and Crossplane — mirroring your EKS stack
- Part 7: Day 2 operations, CKS lab scenarios, and making it all stick
Part 2: One Command, One Working Kubernetes Cluster! Building My Daily-Driver Lab on OrbStack →
I’m Noah Makau, a DevSecOps engineer based in Nairobi. I run a small DevOps consultancy and hold CKA, CKAD, and AWS Solutions Architect Professional certifications, currently preparing for CKS. I write about Kubernetes, Vault, Crossplane, and the day-to-day of running platforms that actually have to stay up.
Originally publisher at blog.arkilasystems.com


Top comments (0)