Misadventures in Kubernetes: Creating Workers

Published: (May 9, 2026 at 09:31 PM EDT)
3 min read
Source: Dev.to

Source: Dev.to

Duncan

We built a control plane from scratch—useful but also hard. The control plane is just the brain; we still need worker nodes (the muscle) to run our containerized applications. Manually configuring each worker would be a nightmare, so this part of the series shows how to create a Golden Image from a pre‑configured machine and rapidly provision identical workers.

Creating a Golden Image

The goal is to stop repetitive manual configuration. When we set up the control node we:

  • Loaded the overlay and br_netfilter kernel modules.
  • Tweaked network bridge settings for iptables.
  • Disabled swap (required for kubelet).
  • Installed containerd and set systemd as the cgroup driver.

All of these prerequisites—OS tuning and Kubernetes binaries (kubeadm, kubelet, kubectl)—are baked into the k8s-seed VM. A Golden Image is a frozen snapshot of that perfect setup, enabling automated, image‑based provisioning.

Step 1: Generalize the Seed Instance

Before using k8s-seed as a template we must clear unique identifiers so each new VM gets its own identity.

  1. SSH into the seed machine

    gcloud compute ssh k8s-seed --zone=us-central1-a
  2. Clean up unique identifiers

    sudo cloud-init clean --seed --logs --machine-id
    exit
  3. Stop the instance (run from your local machine)

    gcloud compute instances stop k8s-seed --zone=us-central1-a

Step 2: Create the Custom Image

Create a Google Compute Engine image from the stopped seed disk.

gcloud compute images create k8s-node-image-v1 \
  --source-disk=k8s-seed \
  --source-disk-zone=us-central1-a \
  --family=k8s-node-family

The --family flag lets you reference the “latest” version of the image later.

Step 3: Provision Worker Nodes

Spin up new workers instantly using the golden image.

gcloud compute instances create worker-1 \
  --zone=us-central1-a \
  --image-family=k8s-node-family \
  --tags=k8s-worker

gcloud compute instances create worker-2 \
  --zone=us-central1-a \
  --image-family=k8s-node-family \
  --tags=k8s-worker

Step 4: Join the Cluster

Workers need to register with the control plane using kubeadm join.

  1. Locate your join command (saved from kubeadm init on the control node):

    kubeadm join 10.128.0.x:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
  2. Run the command on each worker (example for worker-1):

    gcloud compute ssh worker-1 --zone=us-central1-a
    sudo kubeadm join 10.128.0.x:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
    exit

    Repeat the same steps for worker-2.

  3. Verify the nodes

    kubectl get nodes

    Both workers should appear with a Ready status.

For Worker 2: Repeat the Same Steps

gcloud compute ssh worker-2 --zone=us-central1-a
sudo kubeadm join ...   # Paste your command here
exit

Step 5: Verify the Cluster

From the control plane, confirm that all nodes are registered.

kubectl get nodes

Expected output:

NAME            STATUS   ROLES           AGE   VERSION
control-plane   Ready    control-plane   10m   v1.35.0
worker-1        Ready    <none>          2m    v1.35.0
worker-2        Ready    <none>          1m    v1.35.0

The Easy Way (GKE)

If you used Google Kubernetes Engine, the entire process could be replaced with a single command:

gcloud container clusters create k8s-easy-cluster \
  --zone us-central1-a \
  --num-nodes 3 \
  --machine-type e2-medium

What’s Next?

Your multi‑node cluster is up, but it’s still static. If a worker crashes, you must manually replace it, and scaling requires manual provisioning and kubeadm join. Future posts may cover automating node lifecycle and scaling to achieve a truly cloud‑native, resilient cluster.

Go Deeper

0 views
Back to Blog

Related posts

Read more »