Minikube multi-node is less about simulating a real cluster and more about revealing the fundamental complexities of distributed systems that single-node Kubernetes often hides.

Let’s spin up a 3-node cluster and watch it work. First, ensure you have Minikube and kubectl installed.

minikube start --nodes 3 --driver docker --cpus 2 --memory 4096

This command creates three Minikube nodes within a single Docker VM. --nodes 3 tells Minikube to provision two additional nodes besides the control plane. --driver docker specifies the hypervisor, and --cpus and --memory allocate resources to the VM hosting all nodes.

Once minikube start completes, Minikube automatically configures kubectl to point to this new cluster. You can verify this:

kubectl get nodes

You should see output similar to this, with one node in ControlPlane role and two as Worker:

NAME           STATUS   ROLES           AGE   VERSION
minikube       Ready    control-plane   5m    v1.28.3
minikube-m02   Ready    <none>          4m    v1.28.3
minikube-m03   Ready    <none>          4m    v1.28.3

Now, let’s deploy a simple Nginx application. A Deployment will create Pods, and a Service will expose them. The magic happens when we try to scale this Deployment.

Create a file named nginx-app.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer

Apply this to your cluster:

kubectl apply -f nginx-app.yaml

Check the status of your deployment and pods:

kubectl get deployments
kubectl get pods -o wide

You’ll notice that kubectl get pods -o wide shows which node each pod is running on. This is critical: Kubernetes’ scheduler decided where to place these pods. With multiple nodes, it’s not just about having a place to run, but about balancing load and respecting node taints/tolerations.

Let’s expose the service:

kubectl expose deployment nginx-deployment --type=LoadBalancer --port=80 --target-port=80

Now, get the service IP:

minikube service nginx-service --url

This command will output a URL. Accessing this URL should show you the Nginx welcome page. The LoadBalancer service type, in Minikube, uses MetalLB internally. MetalLB watches for Service objects with type: LoadBalancer and assigns an IP address from a pre-configured pool to them, directing traffic to one of the healthy pods backing the service.

Scaling the deployment further demonstrates the scheduler’s role:

kubectl scale deployment nginx-deployment --replicas=5
kubectl get pods -o wide

You’ll see two new pods appear, and the scheduler will again decide which of the available worker nodes (minikube-m02 or minikube-m03) they should land on. It aims for distribution.

The most surprising part for many is realizing that the "nodes" in Minikube multi-node are not separate VMs. They are distinct Kubernetes node objects running within the same Docker VM. This means they share the same underlying network interface and storage. This is a key limitation compared to a true multi-node setup where each node is an independent machine. Network latency, disk I/O, and resource contention are not simulated as they would be across physical or virtual machines.

However, it’s invaluable for understanding:

  • Scheduling: How the Kubernetes scheduler distributes Pods across available Nodes.
  • Service Discovery: How Services (especially LoadBalancer and NodePort) route traffic to Pods running on different nodes.
  • High Availability: Observing how Deployments maintain their desired replica count even if a node were to become unavailable (though simulating node failure in Minikube multi-node is trickier than in true distributed setups).
  • Resource Management: How resource requests and limits influence scheduling decisions.

The core mechanism that allows multiple Kubernetes nodes to run within a single Minikube VM is the use of containerized Kubernetes components. Each "node" is essentially a set of Docker containers running the kubelet, kube-proxy, and container runtime, all communicating with the control plane components which are also running in containers within the same VM. The minikube node itself acts as the control plane, and the --nodes flag instructs it to provision and manage the additional kubelet and kube-proxy processes for the other logical nodes.

When you create a LoadBalancer service, Minikube integrates with MetalLB (or a similar load balancer implementation). MetalLB is itself a set of Pods running within your cluster. It watches the Kubernetes API for Services of type LoadBalancer. Upon detecting one, it selects an IP address from its configured pool and configures the underlying network (in Minikube’s case, the Docker VM’s networking) to route traffic for that IP to the appropriate Service. For multiple worker nodes, MetalLB will ensure traffic is distributed across the healthy pods backing that service, regardless of which worker node they are running on.

The next concept you’ll likely grapple with is persistent storage, especially understanding how volumes are managed and made available across nodes when the underlying storage is shared.

Want structured learning?

Take the full Minikube course →