7. Deployment View

The Pandur cluster is bootstrapped in two clearly separated steps — infrastructure, then GitOps — documented in full in pandur-cluster-bootstrap/README.md and automated (with manual token/secret input) in pandur-cluster-bootstrap/create-pandur.sh.

1. Infrastructure Level 1

The bootstrap sequence: CAPH creates network and load balancer, OpenTofu attaches NAT, CAPH then creates nodes, and finally GitOps takes over.
Figure 1. The bootstrap sequence: CAPH creates network and load balancer, OpenTofu attaches NAT, CAPH then creates nodes, and finally GitOps takes over.
Motivation

Infrastructure (network, load balancer, nodes) and Kubernetes add-ons are deliberately kept in separate tools and separate failure domains ([CT-002 Kubernetes via Cluster API ], [CT-004 GitOps single source of truth ]): CAPH only ever manages Hetzner resources and the cluster’s machines, OpenTofu only ever manages the NAT gateway and the default route, and everything above "a running kubelet" is GitOps.

Quality and/or Performance Features
  • Nodes have neither public IPv4 nor IPv6 ([CT-003 No public node IPs ]); the only public entry point is the Control-Plane Load Balancer (Kubernetes API) and, after Traefik is installed, the ingress Load Balancer.

  • MachineHealthCheck + HCloudRemediationTemplate (part of Phase 2) automatically replace unhealthy control-plane or worker machines, supporting [RE01 24/7 Availability] .

  • The two-phase split means a broken OpenTofu run can be retried/destroyed without touching CAPH-owned resources, and vice versa.

Mapping of Building Blocks to Infrastructure

Steps 5, 7 and 8 above install the Level 1 building blocks: networking (Cilium, Traefik), argocd, and — once Argo CD exists — security, storage, operators, cnpg-system and observability are all reconciled onto the same pandur cluster shown here.

2. Infrastructure Level 2

2.1. Phase 1: CAPH base infrastructure

kubectl apply -f clusterctl/pandur-01-infrastructure.yaml against the temporary kind-management cluster creates and CAPH continues to own:

  • Cluster/pandur and HetznerCluster/pandur

  • the private network 10.0.0.0/16 with cloud subnet 10.0.0.0/24

  • the Hetzner network gateway 10.0.0.1

  • the control-plane load balancer

  • placement groups

No Kubernetes nodes exist yet at the end of this phase.

2.2. OpenTofu: NAT gateway and default route

Once the network exists (its ID is read back via hcloud network describe pandur), pandur-cluster-bootstrap/opentofu creates and owns:

  • the NAT server and its stable public IPv4 (nat_public_ipv4)

  • the NAT firewall

  • the NAT’s attachment to the private network (private IP 10.0.0.254 by default; 10.0.0.1 is reserved for the CAPH gateway and must not be reused)

  • the Hetzner network route 0.0.0.0/0 → 10.0.0.254

This step is a hard prerequisite for Phase 2: control-plane and worker nodes have no public IP and rely on this route for all outbound traffic (package installs, container image pulls, kubeadm).

2.3. Phase 2: CAPH control plane and workers

kubectl apply -f clusterctl/pandur-02-cluster.yaml — only after the NAT route is confirmed working — creates:

  • KubeadmControlPlane (multiple replicas)

  • MachineDeployment for workers

  • KubeadmConfigTemplate

  • HCloudMachineTemplate for both control-plane and worker machines, with publicNetwork.enableIPv4/enableIPv6: false

  • MachineHealthCheck and HCloudRemediationTemplate

Each machine’s cloud-init sets the OS default route via the private gateway 10.0.0.1 and configures DNS before kubeadm runs, since the node has no other way to reach the internet at that point.

2.4. Workload kubeconfig and Kubernetes add-ons

Once KubeadmControlPlane reports INITIALIZED=true, a workload kubeconfig is extracted with clusterctl get kubeconfig pandur --namespace clusters. Nodes are NotReady until CNI and the cloud controller manager exist, so create-pandur.sh installs, directly via helm upgrade --install (i.e. not yet via Argo CD, which does not exist yet):

  • the Hetzner Cloud Controller Manager (HCCM), after patching the kube-system/hcloud secret with the network ID

  • Cilium (CNI)

  • the kubelet CSR approver (needed to approve kubelet serving certificates during the upcoming pivot)

  • Traefik (ingress controller)

2.5. Cluster pivot

clusterctl move transfers the Cluster API custom resources (Cluster, HetznerCluster, KubeadmControlPlane, MachineDeployment, …​) from the temporary kind-management cluster to the pandur cluster itself (after clusterctl init runs against pandur too), so that Pandur becomes self-managing. The kind-management cluster is then deleted.

2.6. Argo CD installation

Finally, Argo CD is installed via helm upgrade --install using pandur/argocd/config/argocd.yml. From this point on, every further change — including Argo CD’s own configuration, via argocd-resources — is reconciled through GitOps ([CT-004 GitOps single source of truth ]) as described in 4. Solution Strategy and GitOps Reconciliation.

Ownership summary
Owner Resources

CAPH

Network, Subnet, Control-Plane Load Balancer, Placement Groups, Control-Plane and Worker machines

OpenTofu

NAT public IPv4, NAT server, NAT firewall, NAT network attachment, 0.0.0.0/0 network route

Workload / GitOps (Argo CD, once installed)

HCCM, Cilium, Traefik, security, storage, operators, cnpg-system, observability

HCCM and the kubelet CSR approver are both installed once via helm upgrade --install during bootstrap, before Argo CD exists, and are both immediately adopted into GitOps afterwards as Argo CD Application`s (`pandur/argocd/apps/hccm.yml and pandur/security/apps/kubelet-csr-approver.yml); [TR-002 HCCM is not GitOps-managed] is resolved.