Build conformant Cluster API Node Images for Hetzner Cloud
Faster CAPI HCloud node startup with image-builder Flatcar and Ubuntu Linux machine images
Updated
This blog post is part of a series about some Kubernetes Cluster API topics as I currently work a lot with CAPI (and love it ❤️). We will start here with building the images used by our CAPI worker nodes.
Part 1: (you are here)
- Create conformant Cluster API images for Hetzner Cloud with kubernetes-sigs/image-builder
- Flatcar and Ubuntu Linux
Part 2: "Deploy Cluster API Operator and Providers with Flux"
- Deploy Cluster API Operator
- Deploy Custom Resources (CAPI Providers)
Part 3: "Dive into Cluster API, ClusterClass and CAPH"
- Overview of all CAPI related resources and templates
- Deployment of highly available, multi-region Kubernetes Cluster with Cluster API
- Usage of Cluster API ClusterClass as a template for your Hetzner Cloud Clusters
Part 4: "Kamaji, Cluster API and etcd"
- Deploy Kamaji and run your control plane as Pods
- Deploy the Kamaji Control Plane provider for Cluster API
- Create etcds with kamaji-etcd
So when deploying Cluster API machines, you have the following options on how to provision them with the necessary Kubernetes components (CRI, kubelet, recommended sysctl parameters and so on):
preKubeadmCommandsto install everything when starting a new machine- Custom images which already have everything baked in to improve startup time and fault tolerance
When starting with CAPI and reading about it, you will find a lot of quickstarts and starter tutorials using the first option. This is perfectly fine to get to know CAPI, but always downloading, installing and configuring everything at boot time can be error prone.
And secondly, your new node will take longer to be available in your Cluster as if you would use ready-to-go machine images. Building images varies on your environment (AWS, VMware, etc.) and also takes time to implement everyting fully automated.
But hey, for CAPI, there is already the fantastic kubernetes-sigs/image-builder project, which supports lots of providers.
In this blog post, we will focus on building images for Hetzner Cloud (as this is where my Clusters are running) and these operating systems:
Ubuntu is a very well known generic operating systems which you might already be using. But for running containers, Flatcar is more interesting, as it’s an optimized OS for container workloads (not just for Kubernetes in particular).
The big advantage of using Flatcar is the reduced image size --> less attack surface, less CVEs to asess - you know the drill 🙃 And smaller image size also means faster startup times of your instances and less storage used (and to pay for).
So lets go right into it 🚀
Setup
First we just git clone the image-builder repository.
git clone https://github.com/kubernetes-sigs/image-builder.git
cd image-builderThen we check the image-builder docs for hcloud here: https://image-builder.sigs.k8s.io/capi/providers/hcloud And as we see, its very clear and compact. image-builder uses Packer and Ansible under the hood, but the very convenient Makefile will download everything whats required.
So we start with just switchting to the images/capi directory and getting the dependencies we need for building the images:
cd images/capi
make deps-hcloudPython
If you get an error that ansible is missing, just install it in your preferred way.
Here I show you two examples with good ol' virtualenv and with the new hyped uv:
VirtualEnv
If you haven't already done so, install venv via python -m pip install --user virtualenv or pipx install virtualenv
python3 -m venv .venv
source .venv/bin/activate
pip install ansibleuv
If you haven't already done so, install uv via curl -LsSf https://astral.sh/uv/install.sh | sh or on macOS brew install uv
uv venv
source .venv/bin/activate
uv pip install ansibleSet required Hetzner Cloud environment variables
Last required step is to set EnvVars for the HCloud location and HCloud Token to use.
# Here we go with the Falkenstein datacenter
export HCLOUD_LOCATION="fsn1"
# Keep the leading space to avoid exposing credentials in your shell history
export HCLOUD_TOKEN="xxxxxx"Building the images
Now we are good to go for building some conformant Cluster API images for Hetzner Cloud. First we go with Ubuntu. You can check which OS are suported by image-builder here: https://image-builder.sigs.k8s.io/capi/providers/hcloud
As of this writing it's:
- CentOS 7
- Flatcar
- Flatcar arm64
- Rocky Linux 8
- Rocky Linux 9
- Ubuntu 20.04
- Ubuntu 22.04
- Ubuntu 24.04
When building the images, you will see that a new instance is started by Packer, configured with Ansible, tested/validated with goos and finally a Snapshot will be created.
Ubuntu
We start with the newest Ubuntu version available.
make build-hcloud-ubuntu-2404The image build will take ~10 minutes:
make build-hcloud-ubuntu-2404 37.23s user 23.77s system 9% cpu 10:42.66 total
In the Hetzner Cloud Console, you will see your new image:

Keep in mind the size of 1.42 GB when we continue with Flatcar now.
Flatcar
Now to the fun part and the image I personally use on all my CAPI clusters: Flatcar 🤩
Again we can simply use the nice make target for the build:
make build-hcloud-flatcarThe image build will take ~12 minutes:
make build-hcloud-flatcar 36.87s user 22.03s system 8% cpu 11:51.89 totalIn the Hetzner Cloud Console, you will see your new image:

The resulting image is 1.13GB in size, which is 20% smaller than the Ubuntu image!
This is it for building Cluster API Hetzner Cloud images with image-builder. In the next post of the series, we will configure all relevant Cluster API manifests with our custom image.
