Skip to content

[WIP] Run Kubernetes node conformance tests in Build Azure SIG Image workflow - #2013

Draft
mboersma wants to merge 7 commits into
kubernetes-sigs:mainfrom
mboersma:azure-sig-node-conformance
Draft

[WIP] Run Kubernetes node conformance tests in Build Azure SIG Image workflow#2013
mboersma wants to merge 7 commits into
kubernetes-sigs:mainfrom
mboersma:azure-sig-node-conformance

Conversation

@mboersma

Copy link
Copy Markdown
Contributor

Status: WIP / Draft — opening for iteration and review.

What this does

Adds an opt-in, non-blocking step to the Build Azure SIG Image workflow that
runs the [[NodeConformance]] subset of Kubernetes' e2e_node test suite
against the freshly-baked SIG image's test VM. The goal is to give us real
signal that the produced node image actually behaves like a conformant
Kubernetes node, beyond the existing version/smoke checks.

Changes

  • New optional workflow input run_node_conformance (default false).
  • New helper script images/capi/hack/node-conformance.sh that runs on the
    test VM:
    • Downloads the version-matched kubernetes-test-linux-${ARCH}.tar.gz
      from dl.k8s.io (rather than the stale registry.k8s.io/node-test:0.2).
    • Stops the system kubelet so the framework can start its own under-test
      kubelet.
    • Runs e2e_node.test --standalone-mode=true against the system containerd
      socket, focused on [NodeConformance], skipping
      [Flaky]|[Serial]|[Slow]|[Alpha].
    • Drops JUnit + logs in /tmp/node-conformance-results/.
  • Workflow:
    • Linux only; Windows is skipped (node conformance is Linux; the Windows
      e2e subset requires a real cluster).
    • continue-on-error: true — failures surface as a workflow warning but
      don't block the promote stage while we iterate.
    • node-conformance-results is uploaded as an artifact.
    • timeout-minutes for the test job is conditionally bumped to 150
      only when conformance is enabled; default 15 is preserved otherwise.

Why opt-in / non-blocking initially

  • The official registry.k8s.io/node-test:0.2 image is stale; we're using the
    versioned binary tarball from dl.k8s.io instead, but the standalone-mode
    invocation arguments may need tuning per OS (Ubuntu vs AzureLinux, cgroup
    paths, hugepages, AppArmor, etc.).
  • First runs are likely to surface real environment-specific failures on
    Azure VMs. We want signal, not a broken pipeline, while we triage.
  • Adds non-trivial runtime (~20–40 min) and compute spend — keeping it
    opt-in lets us run it on demand from the workflow dispatch UI.

Open questions / follow-ups

  • Tune --kubelet-flags per OS distro (current values are conservative
    defaults aimed at containerd + systemd cgroup driver).
  • Consider bumping the test VM size from Standard_D2s_v3 when conformance
    is enabled — some tests are memory-hungry.
  • Once the baseline pass-rate is understood, decide whether to make this
    blocking (default-on) for promote.
  • AzureLinux may need an additional GINKGO_SKIP set.

Testing

  • Helper script passes shellcheck -x.
  • Workflow YAML parses cleanly.
  • Not yet run end-to-end — opening this draft so we can dispatch the
    workflow with run_node_conformance: true and iterate from real output.

Adds an opt-in, non-blocking step to the Build Azure SIG Image workflow
that runs the [NodeConformance] subset of e2e_node.test against the
freshly-booted test VM.

- New optional workflow input run_node_conformance (default false).
- New helper script images/capi/hack/node-conformance.sh that downloads
  the version-matched kubernetes-test tarball from dl.k8s.io and runs
  e2e_node.test in standalone mode against the system containerd.
- Linux only; Windows is skipped (node conformance is Linux-only and
  the Windows e2e subset requires a real cluster).
- Step is continue-on-error so it surfaces signal as a warning without
  blocking promote while we iterate.
- Results are uploaded as the node-conformance-results artifact.
- Test job timeout-minutes bumped to 150 only when conformance is on.
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 13, 2026
@k8s-ci-robot
k8s-ci-robot requested a review from drew-viles May 13, 2026 20:45
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign mboersma for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels May 13, 2026
mboersma added 6 commits May 13, 2026 14:51
Fetch the matching .sha256 file from dl.k8s.io and verify the test
tarball before extracting it. The published checksum file contains
only the hex digest, so we synthesize a sha256sum-compatible line
and use sha256sum --check --strict for verification.
The runtime cgroup path was hardcoded to containerd. When CRI-O is the
detected runtime, set --runtime-cgroups to /system.slice/crio.service
instead so kubelet tracks the correct slice.
Previously the node-conformance step used continue-on-error: true,
which masked all failures equally — including SSH/SCP transport,
auth, and network problems — as ordinary conformance test failures.

Drop continue-on-error and handle exit codes explicitly:
- scp helper-up failures fail the step (transport error).
- ssh exit 255 (its own transport/auth errors) fails the step.
- Any other non-zero remote exit is treated as a conformance result
  and surfaced as a workflow warning without failing the job.
- scp results-back failure is a warning only (we already have a
  conformance verdict at that point).
systemd materializes a slice only when something is first launched
into it. On a fresh image-builder VM the system kubelet has never
been started, so /kubelet.slice may not exist when the test kubelet
is launched. Letting kubelet pick its own cgroup avoids a needless
assumption and works on systems where the slice does exist as well.
First real run surfaced three issues:

1. e2e_node.test died with "Could not locate kubelet binary" because
   the framework searches dirname(argv[0]) and a Kubernetes source
   checkout for the kubelet binary, neither of which contains it on a
   prebuilt image. Pass --k8s-bin-dir=$(dirname $KUBELET_BIN) so the
   framework execs the version-matched kubelet that's already on PATH.

2. klog.Fatalf exits with 255 — the same code ssh uses for its own
   transport/auth failures. Add an EXIT trap in the helper that
   translates remote exit 255 -> 254, so the workflow can distinguish
   conformance failures from SSH transport problems.

3. The workflow exited on the suspected SSH-transport path before
   trying to scp results back, which destroyed the partial logs that
   would have made triage easier. Move the results-scp ahead of the
   exit-decision so we always attempt to retrieve whatever was
   produced before reporting failure.
First successful run produced 4 pass / 19 fail / 742 skip over 2h with
kubelet.log showing 1,425 copies of:

  Container runtime network not ready ... cni plugin not initialized

The node never reaches Ready, so pods do not schedule and almost every
NodeConformance test times out waiting on its pod.

CAPI images ship CNI plugin binaries under /opt/cni/bin but no CNI
config under /etc/cni/net.d — that file is normally written by the CNI
provider on cluster join. For standalone node-conformance there's no
provider, so write a minimal bridge + loopback config ourselves before
launching e2e_node.test. Pre-existing CNI config is left alone so we
don't conflict with a real CNI install. Plugin binaries are downloaded
from containernetworking/plugins only when missing from the image.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants