diff --git a/Makefile b/Makefile index 89124b37a..fe90c5284 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,10 @@ NPD_NAME_VERSION?=node-problem-detector-$(VERSION) # TARBALL is the name of release tar. Include binary version by default. TARBALL=$(NPD_NAME_VERSION).tar.gz +# IMAGE_ARCHIVE is the single-arch (linux/amd64) image tarball built by +# `build-image-archive` for side-loading onto node e2e VMs. +IMAGE_ARCHIVE?=node-problem-detector-image.tar + # IMAGE_TAGS contains the image tags of the node problem detector container image. IMAGE_TAGS=--tag $(REGISTRY)/node-problem-detector:$(TAG) IMAGE_TAGS_WINDOWS=--tag $(REGISTRY)/node-problem-detector-windows:$(TAG) @@ -304,6 +308,12 @@ build-container: clean Dockerfile docker buildx create --platform $(DOCKER_PLATFORMS) --use docker buildx build --platform $(DOCKER_PLATFORMS) $(IMAGE_TAGS) --build-arg LOGCOUNTER=$(LOGCOUNTER) . +# build-image-archive builds the linux/amd64 image into a docker-archive tarball +# ($(IMAGE_ARCHIVE)) for side-loading onto node e2e VMs with `ctr images import`. +build-image-archive: clean Dockerfile + docker buildx create --platform linux/amd64 --use + docker buildx build --platform linux/amd64 --output type=docker,dest=$(IMAGE_ARCHIVE) $(IMAGE_TAGS) --build-arg LOGCOUNTER=$(LOGCOUNTER) . + build-container-windows: clean Dockerfile.windows docker buildx create --platform windows/amd64 --use docker buildx build --platform windows/amd64 $(IMAGE_TAGS_WINDOWS) -f Dockerfile.windows . diff --git a/test/build.sh b/test/build.sh index 6a351cf56..82b7b88a2 100755 --- a/test/build.sh +++ b/test/build.sh @@ -23,7 +23,11 @@ set -o pipefail NPD_STAGING_PATH=${NPD_STAGING_PATH:-"gs://k8s-staging-npd"} -NPD_STAGING_REGISTRY=${NPD_STAGING_REGISTRY:-"gcr.io/node-problem-detector-staging"} +NPD_STAGING_REGISTRY=${NPD_STAGING_REGISTRY:-"gcr.io/k8s-staging-npd"} +# IMAGE_ARCHIVE is a single-arch (linux/amd64) image tarball that the node e2e +# VM side-loads into containerd (see test/sideload-image.sh), so the test runs +# the image built from this PR/CI run without pushing to a registry. +IMAGE_ARCHIVE=${IMAGE_ARCHIVE:-"node-problem-detector-image.tar"} PR_ENV_FILENAME=${PR_ENV_FILENAME:-"pr.env"} CI_ENV_FILENAME=${CI_ENV_FILENAME:-"ci.env"} CI_CUSTOM_FLAGS_ENV_FILENAME=${CI_CUSTOM_FLAGS_ENV_FILENAME:-"ci-custom-flags.env"} @@ -81,6 +85,7 @@ export NODE_PROBLEM_DETECTOR_RELEASE_PATH=${UPLOAD_PATH/gs:\/\//${GCS_URL_PREFIX export NODE_PROBLEM_DETECTOR_VERSION=${VERSION} export NODE_PROBLEM_DETECTOR_TAR_HASH=$(sha1sum ${ROOT_PATH}/node-problem-detector-${VERSION}-linux_amd64.tar.gz | cut -d ' ' -f1) export EXTRA_ENVS=NODE_PROBLEM_DETECTOR_IMAGE=${REGISTRY}/node-problem-detector:${TAG} +export NODE_PROBLEM_DETECTOR_IMAGE_ARCHIVE_URL=${UPLOAD_PATH/gs:\/\//${GCS_URL_PREFIX}}/${IMAGE_ARCHIVE} EOF if [[ -n "${NODE_PROBLEM_DETECTOR_CUSTOM_FLAGS:-}" ]]; then @@ -129,7 +134,8 @@ function build-pr() { export REGISTRY="${NPD_STAGING_REGISTRY}/pr/${PR}" export VERSION=$(get-version) export TAG="${VERSION}" - make push-tar + make push-tar build-image-archive + gsutil cp "${ROOT_PATH}/${IMAGE_ARCHIVE}" "${UPLOAD_PATH}/" write-env-file ${PR_ENV_FILENAME} } @@ -139,10 +145,11 @@ function build-ci() { export REGISTRY="${NPD_STAGING_REGISTRY}/ci" export VERSION="$(get-version)-$(date +%Y%m%d.%H%M)" export TAG="${VERSION}" - # e2e tests consume the tarball, not the container - # this is simpler to manage in the infra, and we still ensure the container - # build works locally - make push-tar build-container + # The cluster e2e jobs consume the tarball; the node e2e test side-loads the + # image archive built here (see test/sideload-image.sh). Nothing is pushed to + # a registry. + make push-tar build-image-archive + gsutil cp "${ROOT_PATH}/${IMAGE_ARCHIVE}" "${UPLOAD_PATH}/" # Create the env file with and without custom flags at the same time. build-npd-custom-flags diff --git a/test/sideload-image.sh b/test/sideload-image.sh new file mode 100755 index 000000000..707fee701 --- /dev/null +++ b/test/sideload-image.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Copyright 2026 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Side-loads the node-problem-detector image built by this PR/CI run onto a +# node e2e VM so the kubernetes "NodeProblemDetector" test exercises that image +# instead of pulling one from a registry. +# +# It is wired in as the instance startup-script by the ci-/pull-npd-e2e-node +# jobs, and reads the archive URL (uploaded by test/build.sh) from instance +# metadata. With --prepull-images=false and the pod's IfNotPresent policy, the +# imported image is used without any registry pull. No-op when the metadata is +# absent, so the job is safe to enable before build.sh starts publishing it. + +set -o errexit +set -o nounset +set -o pipefail + +readonly META="http://metadata.google.internal/computeMetadata/v1/instance/attributes" + +url="$(curl -sf -H 'Metadata-Flavor: Google' "${META}/npd-image-url" || true)" +if [[ -z "${url}" ]]; then + echo "npd-image-url instance metadata not set; nothing to side-load" + exit 0 +fi + +echo "Downloading node-problem-detector image archive from ${url}" +curl -fsSL --retry 5 --retry-delay 3 -o /tmp/npd-image.tar "${url}" + +# init.yaml restarts containerd near the end of node setup; wait for it before +# importing into the CRI (k8s.io) namespace that the kubelet uses. +for _ in $(seq 1 90); do + if ctr -n k8s.io version >/dev/null 2>&1; then + break + fi + sleep 2 +done + +echo "Importing node-problem-detector image into containerd" +ctr -n k8s.io images import /tmp/npd-image.tar +ctr -n k8s.io images ls | grep node-problem-detector || true