Repository navigation
fix(kubernetes): alias canonical pause image for SecureBuild packages (sc-140326) - #6242
Conversation
… (sc-140326) Airgapped upgrades stepping onto k8s 1.36.5/1.37.1 fail deterministically: kubeadm's upgrade-health-check Job uses the canonical pause image (registry.k8s.io/pause:3.10.2), but the SecureBuild switch (#6167) loads pause as docker.io/kurlsh/pause and kubeadm-image-overrides never aliased it back. In airgap the Job cannot pull, never completes, and 'kubeadm upgrade plan' fails its CreateJob preflight (staging run STAGING-release-v2026.10.18-1, 7/7 airgap legs, kurl_upgrade). use_securebuild_images() now appends an idempotent pause alias to kubeadm-image-overrides whenever it rewrites pause to the kurlsh repo, including future versions without a securebuild-<version> dir, and fails generation on unrecognised (e.g. digest-only) pause references. Backfill packages/kubernetes/1.36.5 and 1.37.1. kubernetes_configure_kubeadm_images skips the pause component: it is not a static pod, the line exists only for the load-time retag.
…e shipped 1.36.5 file The fixture comment claims fidelity to packages/kubernetes/1.36.5/kubeadm-image-overrides but its etcd line used a proxy.replicated.com source while the shipped file uses docker.io/kurlsh/etcd. Align the fixture; the proxy-referenced etcd line stays in the default etcd-only fixture, whose proxy-propagation assertion depends on it.
|
This pull request is closed. No approval action remains. Reviewed commit: |
| # kubeadm's upgrade-health-check Job (and `kubeadm config images`) reference the | ||
| # canonical pause image, not the SecureBuild one; without this alias the Job cannot | ||
| # start in airgap and `kubeadm upgrade plan` fails its CreateJob preflight (sc-140326). | ||
| pause_alias_target="registry.k8s.io/pause:${pause_image##*:}" |
There was a problem hiding this comment.
This alias only exists on the node that runs kubernetes_load_images, which in upgrade_kubernetes_local_master is the local primary (scripts/common/upgrade.sh:426). The upgrade-health-check Job has no nodeSelector or affinity, only a control-plane toleration (cmd/kubeadm/app/phases/upgrade/health.go in v1.37.1), so in a multi-node airgap cluster its pod can land on a worker or another primary that hasn't loaded the target package yet. That node has no registry.k8s.io/pause:3.10.2, and kubeadm upgrade plan still fails CreateJob.
This gap predates SecureBuild (any pause tag bump hits it), so it could be a follow-up. The simplest fix I can see is to add CreateJob to the ignored preflight errors for plan when AIRGAP=1. kubeadm upgrade apply already runs with --ignore-preflight-errors=all for the same reason.
local ignore_preflight="$KUBERNETES_UPGRADE_IGNORE_PREFLIGHT_ERRORS"
if [ "$AIRGAP" = "1" ]; then
ignore_preflight="${ignore_preflight:+$ignore_preflight,}CreateJob"
fi
( set -x; kubeadm upgrade plan "v${targetK8sVersion}" --ignore-preflight-errors="$ignore_preflight" )There was a problem hiding this comment.
Good catch, and thanks for checking the Job's scheduling semantics. You're right — on multi-node airgap the health-check pod can land on a node that has not loaded the target package, alias or no alias. Since that gap predates SecureBuild (any pause tag bump) and this PR is scoped to the deterministic single-node regression blocking the staging release, I've filed it as a follow-up with your --ignore-preflight-errors=CreateJob-in-airgap sketch (consistent with apply's existing --ignore-preflight-errors=all): https://app.shortcut.com/replicated/story/140366
…st at load time Rework per PR review: instead of appending a pause line to kubeadm-image-overrides (which would leave future >=1.36.5 versions that have no securebuild dir with a pause-only overrides file, tripping kubernetes_configure_kubeadm_images into creating an empty patch dir and kustomization stanza on every init/join), alias the pause image to the canonical registry.k8s.io name directly in kubernetes_load_images, derived from the package Manifest's 'image pause' line. kubeadm's upgrade-health-check Job needs the canonical name locally in airgap or CreateJob fails (sc-140326). Reverts the script.sh/kubeadm-image-overrides approach and the configure_kubeadm_images pause skip; no override-file format changes.
fix(kubernetes): alias canonical pause image for SecureBuild packages (sc-140326)
Shortcut: https://app.shortcut.com/replicated/story/140326
Summary
Airgapped Kubernetes upgrades that step onto 1.36.5 or 1.37.1 fail deterministically on every OS. kubeadm's
upgrade planruns itsupgrade-health-checkJob with the canonical pause imageregistry.k8s.io/pause:3.10.2, but since the SecureBuild switch (#6167) the package loads pause asdocker.io/kurlsh/pause:3.10.2and nothing aliases it back — so in airgap the Job cannot pull, never completes, and the CreateJob preflight is fatal.Observed in staging release run
STAGING-release-v2026.10.18-1-cd94753d5-20261026211729: "Upgrade from k8s 1.31 to latest - Airgap" failed 7/7 supported legs withkurl_upgradeatErrImagePull: registry.k8s.io/pause:3.10.2. 1.36.4 was unaffected (its Manifest shipped pause under the canonical name directly). Online upgrades and fresh installs are unaffected.Changes
scripts/common/kubernetes.sh—kubernetes_load_imagesnow callskubernetes_alias_canonical_pause_image, which reads the package Manifest'simage pauseline and tags it (ctr images tag --force, ordocker tagon docker-era clusters) to the canonicalregistry.k8s.io/pause:<tag>when it ships under a non-canonical repository. No-op for already-canonical references (pre-SecureBuild packages), digest suffixes are stripped, and untaggable references get alogWarnrather than a failure.scripts/common/kubernetes-test.sh— new tests for the alias (kurlsh pause → canonical tag, digest-pinned → tag stripped, canonical pause → no-op). The "multi" kubeadm-image-overrides fixture's etcd line is also corrected to match the shipped 1.36.5 file (docker.io/kurlsh/etcd:v3.6.15).The alias is derived from the Manifest at load time rather than added to
kubeadm-image-overrides: pause is not a kubeadm-managed static pod, and a pause-only overrides file would makekubernetes_configure_kubeadm_imagescreate an empty patch dir and kustomization stanza on every init/join for future versions that have nosecurebuild-<version>dir.Known follow-up (out of scope, filed as sc-140366): in multi-node airgap clusters the upgrade-health-check Job can schedule on a node that has not loaded the target package yet, so CreateJob can still fail there — that gap predates SecureBuild (any pause tag bump) and is untouched by this PR.
UAT
make test-shell(or CIbuild-test):kubernetes-test.sh31/31,script-test.sh40/40,add-minor-test.sh14/14.upgrade-health-check-*Job completes on the 1.36.5 (and 1.37.1) steps; instance logs should show noErrImagePullforregistry.k8s.io/pause:3.10.2.sudo ctr -n k8s.io images ls | grep pauseshows bothdocker.io/kurlsh/pause:3.10.2andregistry.k8s.io/pause:3.10.2.