Kubernetes Packages¶
Part of: Install a Kubernetes Cluster with kubeadm
Phases 5 & 6 of 9 — Installs kubelet and kubeadm on all nodes; kubectl, helm, and k9s on the control plane only.
Prerequisite: Container Runtime must be complete. Next: Cluster Bootstrap — run kubeadm init and join workers.
Phase 5 and Phase 6 install the Kubernetes binaries. Worker nodes receive kubelet and kubeadm only. Control plane nodes additionally receive kubectl, helm, and k9s.
Scripts¶
| Script | Phase | Installed on |
|---|---|---|
packages/install-kubeadm-kubelet.sh | 5 | All nodes |
packages/install-controlplane-cli.sh | 6 | Control plane only |
lib/k8s-version-resolver.sh | Pre-5 | Sourced by both |
Version Resolution¶
Before any package is installed, the version resolver is sourced into the running shell. It accepts a MAJOR.MINOR string and resolves the exact patch release via the official Kubernetes release API.
Input:
Resolution logic:
Exported variables:
| Variable | Example value | Used by |
|---|---|---|
K8S_MAJOR_MINOR | 1.36 | APT repo URL |
K8S_PATCH_VERSION | 1.36.0 | Validation output |
K8S_IMAGE_TAG | v1.36.0 | kubeadm config images pull, kubeadm init |
KUBE_PKG_VERSION | 1.36.0-1.1 | apt-get install kubelet=... |
The -1.1 suffix is the Debian package revision appended by the Kubernetes packaging team. Without it, apt-get cannot find the exact package version.
The resolver performs no installation and makes no system changes. It is safe to source multiple times.
Phase 5 — kubelet + kubeadm (install-kubeadm-kubelet.sh)¶
What the script does:
- Logs the resolved version context (
K8S_MAJOR_MINOR,K8S_PATCH_VERSION,KUBE_PKG_VERSION) - Installs
ca-certificates,curl,gpg - Removes any legacy
kubernetes.listsource file - Downloads the Kubernetes signing key from
pkgs.k8s.ioand stores it at/etc/apt/keyrings/kubernetes-apt-keyring.gpg(skips if already present) - Writes a Deb822-format APT source pointing to
https://pkgs.k8s.io/core:/stable:/v<MAJOR.MINOR>/deb/ -
Installs exact versions:
-
Pins both packages with
apt-mark holdto prevent accidental upgrade - Enables
kubeletvia systemd (it will crashloop untilkubeadm initorkubeadm joincompletes — this is expected and handled byensure-k8s-services.sh)
Verify:
Worker nodes stop here
init-worker-node.sh ends after Phase 5. kubectl and the remaining CLI tools are not installed on workers. The kubeadm join command (printed by init-controlplane.sh) is run manually after the control plane is ready.
Phase 6 — Control Plane CLI Tools (install-controlplane-cli.sh)¶
Installs three tools that are only useful from the control plane:
kubectl¶
Installed from the same pkgs.k8s.io APT repository using the same KUBE_PKG_VERSION. The script checks if kubectl is already present and skips if so.
Helm 4¶
Downloaded via the official Helm install script:
Skipped if helm is already installed.
k9s¶
Downloaded as a tarball from derailed/k9s GitHub releases (pinned to v0.50.16). Architecture is auto-detected (amd64 / arm64).
- Downloads
k9s_Linux_<arch>.tar.gz - Extracts the
k9sbinary - Installs to
/usr/local/bin/k9swithinstall -m 0755
Skipped if k9s is already installed.
Why kubelet Is Not Started Here¶
After installation, kubelet is enabled as a systemd service but does not start successfully yet — it has no cluster configuration. It will restart repeatedly (this is normal) until kubeadm init writes its configuration in Phase 9. Phase 8 (ensure-k8s-services.sh) waits for this condition before proceeding.
APT Repository Structure¶
The Kubernetes APT repository at pkgs.k8s.io uses a per-minor-version repo structure. Installing v1.36.x requires pointing the source at /core:/stable:/v1.36/deb/. Switching versions means updating the source file and re-running apt-get update.
The source is written in Deb822 format (.sources extension), which is the current standard that replaces the legacy single-line .list format. Any existing kubernetes.list file is deleted before writing the new source to prevent repository conflicts.
Version Pinning Strategy¶
apt-mark hold is applied to kubelet and kubeadm immediately after installation. This prevents apt-get upgrade from accidentally upgrading Kubernetes components, which would create a version skew between the control plane and worker nodes.
To upgrade intentionally:
apt-mark unhold kubelet kubeadm kubectl
apt-get install kubelet=<new-version> kubeadm=<new-version> kubectl=<new-version>
apt-mark hold kubelet kubeadm kubectl
cluster-params-2.sh (the advanced wizard variant) enforces an additional safety rule: it detects the currently installed kubelet version and refuses to install a version more than one minor version away, preventing unsupported upgrade or downgrade jumps.