{"slug": "one-command-one-working-kubernetes-cluster-building-my-daily-driver-lab-on", "title": "One Command, One Working Kubernetes Cluster! Building My Daily-Driver Lab on OrbStack.", "summary": "Part 2 of a series documenting the setup of a production-mirror Kubernetes lab on a Mac using OrbStack. The author demonstrates how to create a single-node cluster with a single command, which automatically provides real LoadBalancer IPs and wildcard DNS without needing tools like MetalLB or manual host file edits. The guide then walks through installing Istio, Vault, and Crossplane via Helm in about ten minutes, highlighting how OrbStack simplifies local Kubernetes development.", "body_md": "Part 2 of 7 — The Mac Kubernetes Lab: A Production-Mirror Setup from Scratch.\nPreviously in Part 1: I walked through why I replaced Multipass with OrbStack, the dual-cluster architecture I settled on, and a preview of the M1 vs M4 CNI problem that’s coming in Part 4.\nThe cluster I am going to set up in this article is the one I spend most of my working day inside. It’s a single-node Kubernetes cluster, always on, idles at around 512 MB of memory, has real LoadBalancer IPs and wildcard DNS out of the box. No MetalLB, /etc/hosts\nediting,kubectl port-forward muscle\nmemory. By the time this article is done, it will also have Istio, Vault, and Crossplane running. Total elapsed time, the first time you do it: about ten minutes.\nIf you’ve ever built a local Kubernetes cluster and then spent the next twenty minutes wiring up MetalLB and editing /etc/hosts so you can actually reach a service from a browser, this is going to feel almost suspicious.\n# 💻 Mac\norb start k8s\n# Confirm cluster is udr\nkubectl get nodes\n# NAME STATUS ROLES AGE VERSION\n# orbstack Ready control-plane,master 30s v1.33.x\nkubectl config current-context\n# orbstack\nThat’s all! No kubeadm, no CNI configuration, no certificate management. The cluster is up and reachable in under thirty seconds the first time, and instantly on every subsequent start.\nThis is where OrbStack genuinely earns its keep. On a typical local cluster; kind, minikube, kubeadm, LoadBalancer services stay in pending\nstate until you install MetalLB on OrbStack:\n⚠️ The wildcard DNS only resolves on your Mac. Other devices on your network won’t see *.k8s.orb.local. If you need a service reachable from another machine, that's what Cluster 2 (Parts 3–6) is for.\nI use Helm rather than istioctl for two reasons.\nFirst, it's how I manage Istio on the production EKS clusters at work, so the muscle memory transfers.\nSecond, Helm gives fine-grained control over resource requests, which matters on a laptop.\n# 💻 Mac\nkubectx orbstack\n# Add helm charts\nhelm repo add istio https://istio-release.storage.googleapis.com/charts\nhelm repo update\n# Step 1 - Base CRDs\nhelm install istio-base istio/base \\\n--namespace istio-system --create-namespace \\\n--set defaultRevision=default\n# Step 2 - Control plane\n# The PILOT_ENABLE_WORKLOAD_ENTRY_AUTOREGISTRATION flag is required on OrbStack\n# to prevent DNS resolution conflicts with the host network.\nhelm install istiod istio/istiod \\\n--namespace istio-system \\\n--set pilot.env.PILOT_ENABLE_WORKLOAD_ENTRY_AUTOREGISTRATION=true \\\n--set global.proxy.resources.requests.cpu=10m \\\n--set global.proxy.resources.requests.memory=64Mi \\\n--wait\n# Step 3 - Ingress gateway\n# OrbStack assigns a real LoadBalancer IP automatically - no MetalLB needed.\nhelm install istio-ingress istio/gateway \\\n--namespace istio-ingress --create-namespace \\\n--set service.type=LoadBalancer\n# Verify the gateway got an EXTERNAL-IP\nkubectl get svc -n istio-ingress\n# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)\n# istio-ingress LoadBalancer 10.x.x.x 198.19.x.x 80:xxx/TCP\n# Enable sidecar injection on the default namespace\nkubectl label namespace default istio-injection=enabled\nThis is the moment OrbStack feels like cheating. You create a Gateway pointing at *.k8s.orb.local\n, and it just works from your Mac browser. No IP lookups. No /etc/hosts\n, no 127.0.0.1:8080\nproxying.\nThe Gateway resource binds to the istio-ingress LoadBalancer service, OrbStack intercepts traffic to the *.k8s.orb.localwildcard domain at the Mac level and routes it to that LoadBalancer IP. The Virtual Service then routes inside the cluster to the right service.\n# 💻 Mac\nkubectl apply -f - <<EOF\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: httpbin\nspec:\nreplicas: 1\nselector:\nmatchLabels:\napp: httpbin\ntemplate:\nmetadata:\nlabels:\napp: httpbin\nspec:\ncontainers:\n- name: httpbin\nimage: kennethreitz/httpbin:latest\nports:\n- containerPort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\nname: httpbin\nspec:\nselector:\napp: httpbin\nports:\n- port: 80\ntargetPort: 80\n---\napiVersion: networking.istio.io/v1beta1\nkind: Gateway\nmetadata:\nname: httpbin-gateway\nspec:\nselector:\nistio: ingress\nservers:\n- port:\nnumber: 80\nname: http\nprotocol: HTTP\nhosts:\n- \"httpbin.k8s.orb.local\"\n---\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\nname: httpbin\nspec:\nhosts:\n- \"httpbin.k8s.orb.local\"\ngateways:\n- httpbin-gateway\nhttp:\n- route:\n- destination:\nhost: httpbin\nport:\nnumber: 80\nEOF\nOpen http://httpbin.k8s.orb.local\nin your Mac browser. It works immediately.\nThe same pattern used in production canary deployments:\n# 💻 Mac\nkubectl apply -f - <<EOF\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\nname: myapp-split\nspec:\nhosts:\n- \"myapp.k8s.orb.local\"\ngateways:\n- myapp-gateway\nhttp:\n- route:\n- destination:\nhost: myapp-v1\nport:\nnumber: 80\nweight: 80\n- destination:\nhost: myapp-v2\nport:\nnumber: 80\nweight: 20\nEOF\nRoute /v1 and /v2 to different backend services:\n# 💻 Mac\nkubectl apply -f - <<EOF\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\nname: path-routing\nspec:\nhosts:\n- \"api.k8s.orb.local\"\ngateways:\n- api-gateway\nhttp:\n- match:\n- uri:\nprefix: /v1\nroute:\n- destination:\nhost: api-v1-svc\nport:\nnumber: 80\n- match:\n- uri:\nprefix: /v2\nroute:\n- destination:\nhost: api-v2-svc\nport:\nnumber: 80\nEOF\nDo not use httpsRedirect: true in a Gateway on the native cluster. OrbStack intercepts LoadBalancer traffic in a way that causes an infinite 301 redirect loop when TLS redirect is enabled.\n# ❌ This breaks on OrbStack native K8s\nservers:\n- tls:\nhttpsRedirect: true\n# ✅ Use plain HTTP on the native cluster\nservers:\n- port:\nnumber: 80\nprotocol: HTTP\nFor TLS testing, use Cluster 2 (the VM cluster, coming in Part 3), where you have full control over the network stack.\nDev mode trades durability for speed. No unsealing, no persistence concerns, instant startup. It’s the right call for the daily-driver cluster where I’m testing AppRole workflows, PKI policies, or Kubernetes auth configurations, and the value is in iteration speed, not data preservation.\n# 💻 Mac\nhelm repo add hashicorp https://helm.releases.hashicorp.com\nhelm repo update\nhelm install vault hashicorp/vault \\\n--namespace vault --create-namespace \\\n--set \"server.dev.enabled=true\"\nkubectl get pods -n vault\n# vault-0 1/1 Running 0 30s\nFor production-grade Vault with HA Raft storage, use Cluster 2 (Part 3). Dev mode here is intentional — it trades durability for speed.\nCrossplane turns the Kubernetes cluster into a universal control plane for cloud infrastructure. I use it heavily with the AWS provider at work.\n# 💻 Mac\nhelm repo add crossplane-stable https://charts.crossplane.io/stable\nhelm repo update\n# Note: --enable-composition-functions was removed in newer versions.\n# Composition Functions are enabled by default now.\nhelm install crossplane crossplane-stable/crossplane \\\n--namespace crossplane-system --create-namespace\nkubectl get pods -n crossplane-system\n# 💻 Mac\n# Stop - releases all CPU and RAM\norb stop k8s\n# Start - full state persists (deployments, services, secrets, configmaps)\norb start k8s\n# Verify\nkubectx orbstack\nkubectl get nodes\nkubectl get pods -A\nThe native cluster state persists across stop/start. Vault dev mode data is lost on restart by design, but everything else, Crossplane installations, Istio configuration, and your workload deployments come back exactly as provisioned.\nThe daily-driver cluster is the easy half of this lab. The hard half is the one that mirrors production, a real multi-node kubeadm cluster running on four VMs, with HashiCorp Vault as its certificate authority.\nThat’s where Part 3 picks up: creating the VMs, wiring their networking, and standing up a 3-tier Vault PKI that will sign every certificate in the cluster.\n← Part 1: Why I Replaced Multipass with OrbStack.. | Part 3: Building a Production-Grade Vault PKI for a Local kubeadm Cluster Without the Shortcuts →\nI’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.\nOriginally published at blog.arkilasystems.com.", "url": "https://wpnews.pro/news/one-command-one-working-kubernetes-cluster-building-my-daily-driver-lab-on", "canonical_source": "https://dev.to/nkmakau/one-command-one-working-kubernetes-cluster-building-my-daily-driver-lab-on-orbstack-34k5", "published_at": "2026-05-22 09:41:26+00:00", "updated_at": "2026-05-22 09:44:55.664685+00:00", "lang": "en", "topics": ["developer-tools", "cloud-computing", "open-source"], "entities": ["OrbStack", "Kubernetes", "MetalLB", "Istio", "Vault", "Crossplane", "Multipass", "kubectl"], "alternates": {"html": "https://wpnews.pro/news/one-command-one-working-kubernetes-cluster-building-my-daily-driver-lab-on", "markdown": "https://wpnews.pro/news/one-command-one-working-kubernetes-cluster-building-my-daily-driver-lab-on.md", "text": "https://wpnews.pro/news/one-command-one-working-kubernetes-cluster-building-my-daily-driver-lab-on.txt", "jsonld": "https://wpnews.pro/news/one-command-one-working-kubernetes-cluster-building-my-daily-driver-lab-on.jsonld"}}