k8s: optionally mount externals from an image volume instead of copying in fs-init - #399
Open
DJRH wants to merge 1 commit into
Open
k8s: optionally mount externals from an image volume instead of copying in fs-init#399DJRH wants to merge 1 commit into
DJRH wants to merge 1 commit into
Conversation
The kubernetes/kubernetes-novolume hooks copy the runner's externals (~600MB) from the runner image into an emptyDir via the fs-init init container on every job, which adds materially to job pod startup time. Add an opt-in ACTIONS_RUNNER_K8S_EXTERNALS_FROM_IMAGE=true that instead mounts the externals directly from an image volume (the runner image, from ACTIONS_RUNNER_IMAGE) read-only at /__e via subPath home/runner/externals, and skips the fs-init copy entirely. Defaults to off, preserving the current emptyDir behaviour exactly. Requires the ImageVolume feature gate (default-on in Kubernetes 1.35+).
DJRH
force-pushed
the
feat/novolume-externals-image-volume
branch
from
July 23, 2026 16:53
780390d to
40c63c4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an opt-in
ACTIONS_RUNNER_K8S_EXTERNALS_FROM_IMAGE=truethat mounts the runner's externals directly from an image volume (the runner image, fromACTIONS_RUNNER_IMAGE) instead of copying them into anemptyDirin thefs-initinit container on every job.When enabled:
image:volume referencingACTIONS_RUNNER_IMAGE, mounted read-only at/__eviasubPath: home/runner/externals.fs-initno longermvs/home/runner/externals/*into anemptyDir(and no longer mounts that volume).Default (unset/
false) is unchanged — the externalsemptyDiris seeded byfs-initexactly as today.Why
In
kubernetes/kubernetes-novolumemode,fs-initcopies the full externals tree (~600MB) into anemptyDiron every job pod. That copy is pure startup latency on every job. Kubernetes image volumes let the kubelet mount the runner image's already-present externals directly, so the per-job copy disappears (the image is pulled once per node and cached). In our environment this removed a multi-minute cold-start under burst.Safety / gating
ImageVolumefeature gate, default-on in Kubernetes 1.35+ (beta). On clusters where it's unavailable the API server silently drops theimage:volume source and the job would start with nothing at/__e, so this is deliberately not auto-enabled — the operator opts in when they know their cluster supports it. Documented inpackages/k8s/README.md.Implementation
utils.ts:ENV_EXTERNALS_FROM_IMAGE,externalsFromImage(),runnerImage(),externalsVolume();CONTAINER_VOLUMES→containerVolumes()(the/__emount gainssubPath+readOnlyonly when enabled).index.ts: gate thefs-initseed commands + externals mount, and useexternalsVolume()in bothcreateJobPodandcreateContainerStepPod.prepare-job.ts/run-container-step.ts: usecontainerVolumes().Testing
npm run bootstrap && npm run build-all— clean (TypeScript compiles;image:volume typechecks against@kubernetes/client-node ^1.3.0).prettier --check— clean.emptyDir+fs-initcopy; enabled =image:volume, no copy, read-only/__esubPath).Happy to add unit coverage for
containerVolumes()/externalsVolume()if you'd like.