- Update init.sh with smart checkout, patch application, sync-inventory alias, and runbook output - Rewrite bootstrap/README.md with step-by-step upgrade guide, architectural invariants, and troubleshooting - Update bootstrap/AGENTS.md with single-node operational rules and OS constraints
6.3 KiB
Bootstrap
This directory contains the automation, configurations, and playbooks used to provision and upgrade the single-node Kubernetes cluster haumdaucher (136.243.23.215) using Kubespray.
Architecture & Single-Node Cluster Constraints
haumdaucher is a single-node cluster (control plane, etcd, and worker all run on the same machine). This topology requires specific configuration choices during cluster maintenance:
Important
Crucial Single-Node Invariants
- Never Cordon or Drain the Node: Draining a single-node cluster evicts all workloads with nowhere to schedule them, causing pods to stay in
Pendingstate and breaking critical cluster services (such as DNS, CNI, ingress, and local storage). In inventory/prod/group_vars/k8s_cluster/k8s-cluster.yml, the following settings are enforced:drain_nodes: false upgrade_node_always_cordon: false upgrade_node_fail_if_drain_fails: false- In-Place Upgrades via
cluster.yml: Instead ofupgrade-cluster.yml(which defaults to draining nodes), single-node upgrades should use the in-place upgrade mechanism:ansible-playbook -i inventory/prod/inventory.ini -e upgrade_cluster_setup=true cluster.yml- Version Number Formatting: Kubespray 2.28 interpolates
v{{ kube_version }}across many internal tasks. Therefore,kube_versionink8s-cluster.ymlMUST NOT include a leadingv:kube_version: 1.32.13 # Correct # kube_version: v1.32.13 # INCORRECT (leads to v1.32.13 -> vv1.32.13 errors)- Host OS Lifecycle Constraint (Ubuntu 20.04 LTS): Kubespray
release-2.28is the final release line supporting Ubuntu 20.04. Kubesprayrelease-2.29+ drops Ubuntu 20.04 support and requires Ubuntu 22.04 or 24.04. Do not bumpVERSIONininit.shbeyondrelease-2.28until the host OS is upgraded.
Quickstart
1. Environment Initialization
Source init.sh from this directory. It clones Kubespray, applies patches from patches/, configures the Python virtualenv, and syncs ./inventory/ into ./kubespray/inventory/:
source ./init.sh
(Note: init.sh also exports the sync-inventory alias to quickly sync local ./inventory/ modifications into ./kubespray/inventory/ without re-cloning).
Step-by-Step Upgrade Runbook
Upgrades are conducted in two decoupled phases:
- Phase 1: Upgrade the Kubespray tooling baseline while keeping the Kubernetes version unchanged
\rightarrowApply\rightarrowVerify. - Phase 2: Upgrade Kubernetes components (API server, controller manager, scheduler, kubelet, kube-proxy)
\rightarrowApply\rightarrowVerify.
Step 0: Pre-Flight Checks & Backups
-
Verify SSH and sudo access:
ssh moritz@136.243.23.215 "sudo kubectl get nodes -o wide" -
Check Pod Health:
ssh moritz@136.243.23.215 "sudo kubectl get pods -A | grep -v -E 'Running|Completed'" -
Take a Manual etcd Snapshot:
ssh moritz@136.243.23.215 "sudo etcdctl \ --cacert=/etc/ssl/etcd/ssl/ca.pem \ --cert=/etc/ssl/etcd/ssl/node-haumdaucher.pem \ --key=/etc/ssl/etcd/ssl/node-haumdaucher-key.pem \ snapshot save /var/backups/etcd/etcd-pre-upgrade-\$(date +%Y%m%d%H%M%S).db"
Step 1: Reconcile Kubespray Baseline (Phase 1)
- Verify
VERSIONininit.shmatches the target Kubespray branch (e.g.release-2.28). - Run
source ./init.shto initialize the environment. - Apply the baseline configuration:
cd kubespray ansible-playbook -i inventory/prod/inventory.ini cluster.yml - Verify cluster health:
kubectl get nodes -o wide kubectl get pods -n kube-system
Step 2: Upgrade Kubernetes Version (Phase 2)
-
In
bootstrap/inventory/prod/group_vars/k8s_cluster/k8s-cluster.yml, updatekube_version:kube_version: 1.32.13 -
Sync the configuration into the
kubespray/workspace:sync-inventory -
Run the in-place upgrade playbook:
cd kubespray ansible-playbook -i inventory/prod/inventory.ini -e upgrade_cluster_setup=true cluster.yml
Step 3: Post-Upgrade Verification
-
Check component versions:
kubectl versionEnsure both
Client VersionandServer Versionreportv1.32.13. -
Verify Node status:
kubectl get nodes -o wideEnsure status is
Readyand version matchesv1.32.13. -
Verify System Pods:
kubectl get pods -n kube-systemAll control plane components (
kube-apiserver,kube-controller-manager,kube-scheduler,coredns,kube-flannel,kube-proxy,traefik) should be1/1 Running. -
Verify Workloads:
kubectl get pods -A | grep -v -E "Running|Completed"
Troubleshooting & Edge Cases
Kubeadm Preflight CreateJob Failure
Kubeadm 1.31+ preflight executes an ephemeral upgrade-health-check-... batch job with a 15-second timeout. On single-node clusters or under load, this may exceed 15s. To prevent the upgrade from halting:
CreateJobis included inkubeadm_ignore_preflight_errorsin k8s-cluster.yml.- The patch
patches/kubeadm-upgrade-ignore-preflight.patchensures Kubespray'sv1beta4kubeadm configuration propagates this flag duringupgrade apply.
Kubelet Housekeeping Stalls / Static Pod Timeout
If kubeadm upgrade apply times out waiting for static pod hash changes:
- Check
journalctl -u kubelet -n 100forHousekeeping took longer than expectedororphaned pod ... failed to rmdir(). - If an old container unmount left a stale bind-mount busy, lazily detach it:
sudo umount -l /var/lib/kubelet/pods/<orphaned-pod-uid>/volumes/... sudo systemctl restart kubelet
Directory Layout
init.sh: Environment bootstrapping script and upgrade instructions.inventory/: Source-of-truth inventory and variable files.patches/: Git patches applied to upstream Kubespray on checkout.kubespray/: (Ephemeral) Cloned Kubespray repository.