Introduction
This tutorial explains the process of setting up a Kubernetes cluster on Hetzner Cloud using a tool called "Claudie". Claudie is a platform for managing multi-cloud and hybrid-cloud Kubernetes clusters with support for nodepools across different cloud-providers and on-premise data centers, including Hetzner Cloud.
Prerequisites
- Hetzner Cloud account
- kubectl binary
- kind
- Container runtime, e.g. Docker
Step 1 - Install Claudie
Claudie needs to be installed on an existing Kubernetes cluster, referred to as the Management Cluster, which is used to manage the clusters it provisions. For this tutorial, an ephemeral cluster like kind can be used for simplicity. This step assumes that you have kind installed locally.
For testing, you can use ephemeral clusters like Minikube or kind. However, for production environments, it is recommended to use a more resilient solution since Claudie maintains the state of the infrastructure it creates.
-
Create a kind cluster and export the kubeconfig
holu@<your_host>:~# kind create cluster --name claudie-mgmt Creating cluster "claudie-mgmt" ... ✓ Ensuring node image (kindest/node:v1.27.3) :frame_with_picture: ✓ Preparing nodes :package: ✓ Writing configuration :scroll: ✓ Starting control-plane :joystick: ✓ Installing CNI :electric_plug: ✓ Installing StorageClass :floppy_disk: Set kubectl context to "kind-claudie-mgmt" You can now use your cluster with: kubectl cluster-info --context kind-claudie-mgmt
holu@<your_host>:~# kind get kubeconfig -n claudie-mgmt > ~/.kube/claudie holu@<your_host>:~# export KUBECONFIG=~/.kube/claudie holu@<your_host>:~# kubectl get nodes NAME STATUS ROLES AGE VERSION claudie-mgmt-control-plane Ready control-plane 3m8s v1.27.3
-
Install cert-manager as it is a requirement for the Claudie Management cluster.
holu@<your_host>:~# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.yaml
-
Deploy Claudie
holu@<your_host>:~# kubectl apply -f https://github.com/berops/claudie/releases/latest/download/claudie.yaml
-
Wait for all Pods to get into Ready state
holu@<your_host>:~# kubectl -n claudie get pods NAME READY STATUS RESTARTS AGE ansibler-86d69dc6c7-j2v8w 1/1 Running 0 90s builder-69f8c5f8ff-lrzdp 1/1 Running 0 90s claudie-operator-576595dcfc-nvchm 1/1 Running 0 90s create-table-job-bthcm 0/1 Completed 0 90s dynamodb-6d65df988-dpsbd 1/1 Running 0 90s kube-eleven-5f649b7-xkjbk 1/1 Running 0 90s kuber-6fdc7b5578-bldl6 1/1 Running 0 90s make-bucket-job-zv497 0/1 Completed 0 90s manager-d49f456fd-sjd4k 1/1 Running 0 90s minio-0 1/1 Running 0 90s minio-1 1/1 Running 0 90s minio-2 1/1 Running 0 90s minio-3 1/1 Running 0 90s mongodb-6ccb5f5dff-nv2pr 1/1 Running 0 90s terraformer-7c7bfffc4b-2wnqf 1/1 Running 0 90s
Step 2 - Create Hetzner API Key
-
Login to your Hetzner Cloud Console to generate a new API token with Read & Write permissions. For more information you can follow this guide on creating an API Token.
-
Create a Kubernetes Secret that will contain the Hetzner API Token.
holu@<your_host>:~# kubectl create secret generic hetzner-secret --from-literal=credentials='YOUR_API_TOKEN'
Step 3 - Create a Claudie manifest file
Now, let's create a Claudie manifest file that describes the Kubernetes cluster you want to create on Hetzner. You can use the example manifest below as a starting point.
-
Create the file:
holu@<your_host>:~# nano inputmanifest.yml
-
Add your content:
apiVersion: claudie.io/v1beta1 kind: InputManifest metadata: name: kubernetes-hetzner spec: providers: - name: hetzner-secret providerType: hetzner secretRef: name: hetzner-secret namespace: default nodePools: dynamic: - name: hetzner-ctrl providerSpec: name: hetzner-secret region: fsn1 zone: fsn1-dc14 count: 1 serverType: cpx21 image: ubuntu-22.04 - name: hetzner-cmpt providerSpec: name: hetzner-secret region: fsn1 zone: fsn1-dc14 count: 3 serverType: cpx21 image: ubuntu-22.04 storageDiskSize: 50 kubernetes: clusters: - name: hetzner-cluster version: v1.30.0 network: 192.168.2.0/24 pools: control: - hetzner-ctrl compute: - hetzner-cmpt
The above manifest file is used for defining a Kubernetes cluster. Let's break down some of the key fields in it:
spec.providers
» Contains configurations for supported cloud providers. It is referencing access credentials (previously created in a Secret object) and terraform template files for Hetzner (see more)spec.nodePools.dynamic
» Defines dynamic nodepools. Those are cloud provider VMs that Claudie is expected to create.spec.kubernetes.clusters
» Describes the Kubernetes cluster that will be created.
Provided example is relatively simple and deploys a Kubernetes cluster with one control node and three worker nodes. However, Claudie can be used for more advanced cluster scenarios, including deploying clusters across different cloud providers
and on-premise in multi-cloud/hybrid architecture. Additionally, it's worth noting that the nodes will be connected using a WireGuard network, eliminating the need for a virtual network resource. For more in-depth understanding of Claudie inputmanifest
definition, visit the documentation site.
Step 4 - Deploy the cluster
Important: Please note that applying the YAML file from above will automatically create:
- 4 Hetzner Cloud servers of type CPX21 that will be charged
- 3 Hetzner Cloud Volumes with a storage capacity of 50 GB each that will be charged
- 1 Hetzner Cloud Firewall (free)
- It will also add an SSH key to the project
Save the example above to an inputmanifest.yml
file, and apply it to the kind cluster. If you are not prepared to pay for 4 servers of type CPX21 and 3 Volumes, you can adapt the YAML file above as needed before you run the following command:
holu@<your_host>:~# kubectl apply -f inputmanifest.yml
inputmanifest.claudie.io/kubernetes-hetzner created
Now you can follow the cluster deployment status. When the cluster is deployed, the status will state DONE.
holu@<your_host>:~# kubectl get inputmanifest
NAME STATUS
kubernetes-hetzner IN_PROGRESS
holu@<your_host>:~# kubectl get inputmanifest
NAME STATUS
kubernetes-hetzner DONE
Step 5 - Access the cluster
The kubeconfig will be saved to a Secret object in the claudie
namespace.
holu@<your_host>:~# kubectl get secrets -A
NAMESPACE NAME TYPE DATA AGE
cert-manager cert-manager-webhook-ca Opaque 3 36m
claudie claudie-webhook-certificate kubernetes.io/tls 3 32m
claudie dynamo-secret-6tffbf8bc7 Opaque 2 32m
claudie hetzner-cluster-b87z4jq-kubeconfig Opaque 1 57s
claudie hetzner-cluster-b87z4jq-metadata Opaque 1 57s
claudie minio-secret-6tffbf8bc7 Opaque 2 32m
claudie mongo-secret-k479ht772f Opaque 3 32m
default hetzner-secret Opaque 1 29m
kube-system bootstrap-token-abcdef bootstrap.kubernetes.io/token 6 37m
Run the following command to obtain the kubeconfig of the built cluster
holu@<your_host>:~# kubectl get secrets -n claudie -l claudie.io/cluster=hetzner-cluster,claudie.io/output=kubeconfig -ojsonpath='{.items[0].data.kubeconfig}' | base64 -d
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <your_data>
server: https://<203.0.113.1>:6443
name: hetzner-cluster
contexts:
- context:
cluster: hetzner-cluster
user: kubernetes-admin
name: kubernetes-admin@hetzner-cluster
current-context: kubernetes-admin@hetzner-cluster
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: <your_data>
client-key-data: <your_data>
Confirm that the cluster is up and running:
By running the commands below you can store the kubeconfig of the built cluster to your filesystem and check if the cluster is healthy.
holu@<your_host>:~# kubectl get secrets -n claudie -l claudie.io/cluster=hetzner-cluster,claudie.io/output=kubeconfig -ojsonpath='{.items[0].data.kubeconfig}' | base64 -d > ~/.kube/hetzner
holu@<your_host>:~# export KUBECONFIG=~/.kube/hetzner
holu@<your_host>:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
hetzner-cmpt-qpxeb6w-01 Ready <none> 7m59s v1.30.0
hetzner-cmpt-qpxeb6w-02 Ready <none> 7m59s v1.30.0
hetzner-cmpt-qpxeb6w-03 Ready <none> 7m59s v1.30.0
hetzner-ctrl-78u39wr-01 Ready control-plane 9m10s v1.30.0
Conclusion
In this tutorial we walked through the process of deploying a Kubernetes cluster on Hetzner Cloud using Claudie. We began by setting up Claudie in a local kind cluster, created a Hetzner API key for authentication, and defined a Claudie manifest file. After applying the manifest, we successfully created a Kubernetes cluster on Hetzner Cloud.