Skip to content

fix(ci): use NVMe storage for H100 runner workspaces - #1627

Merged
slin1237 merged 2 commits into
mainfrom
fix/h100-runner-nvme-workspaces-pr
Jun 10, 2026
Merged

slin1237 merged 2 commits into
mainfrom
fix/h100-runner-nvme-workspaces-pr

Conversation

@key4ng

@key4ng key4ng commented Jun 10, 2026 •

Copy link
Copy Markdown
Member

Description

Problem

H100 GitHub Actions runners can evict CI jobs when model downloads, workspaces, temp files, or Docker layer data consume the node boot volume. The live Moirai runners were fixed by moving heavy runner paths onto the local NVMe-backed /raid/actions-runner path and by preparing writable model cache lock directories.

Solution

Persist the same H100-only storage layout in the ARC runner scale-set values. The H100 runner pods now use per-pod subPathExpr directories under /raid/actions-runner for workspace, cache, temp, and Docker storage, and an init container prepares ownership and model cache lock directories before the runner starts. The dind sidecar-style init container also gets a preStop hook that removes /raid/actions-runner/<pod-name> through the mounted parent path to avoid orphaning heavy hostPath directories after normal pod termination.

Changes

  • Update runner-values-1-gpu-h100.yaml, runner-values-2-gpu-h100.yaml, and runner-values-4-gpu-h100.yaml.
  • Move /home/runner/_work, /home/runner/.cache, /tmp, and /var/lib/docker onto /raid/actions-runner with per-pod subdirectories.
  • Add POD_NAME env wiring for subPathExpr in the runner and dind containers.
  • Add prepare-runner-nvme init container to create/chown runner NVMe directories and prepare /models/.locks, /models/hub, and /models/hub/.locks.
  • Mount the parent NVMe path into dind and add a preStop cleanup hook for /runner-nvme/${POD_NAME:?}.
  • Leave non-H100 runner values unchanged because A10 nodes did not safely support the same /raid/actions-runner path during live validation.
  • Document the H100 hostPath cleanup behavior, best-effort cleanup caveat, and the controller-specific Summerwind caveat in the runner resource README.

Test Plan

Live validation in the Moirai dev cluster:

  • Verified the 1-GPU H100 runner patch allowed model download to pass after the earlier /models/.locks permission failure.
  • Verified live H100 runner pods mounted /runner/_work or /home/runner/_work, /home/runner/.cache, /tmp, and /models on the 28T NVMe volume.
  • Verified /models/.locks and /models/hub/.locks are writable by the runner user.
  • Verified arc-runner-2-gpu-h100 and arc-runner-4-gpu-h100 live pods started with the same NVMe mount pattern.
  • Added cleanup for normal pod termination. This is still best-effort because Kubernetes preStop hooks do not run for hard node failure or force deletion, so host-level pruning can still be added later as defense in depth.

Local validation:

git diff --check origin/main...HEAD

Reviewed scripts/k8s-runner-resources/README.md to confirm the H100 NVMe cleanup note documents the hostPath garbage-collection risk and the Summerwind controller caveat.

ruby -ryaml -e 'ARGV.each { |f| data = YAML.load_file(f); spec = data.fetch("template").fetch("spec"); dind = spec.fetch("initContainers").find { |c| c["name"] == "dind" }; mounts = dind.fetch("volumeMounts").map { |m| [m["mountPath"], m["name"]] }.to_h; raise "#{f}: dind missing /runner-nvme mount" unless mounts["/runner-nvme"] == "runner-nvme"; cmd = dind.dig("lifecycle", "preStop", "exec", "command"); raise "#{f}: missing preStop cleanup" unless cmd&.join(" ")&.include?("/runner-nvme/${POD_NAME:?"); puts "OK #{File.basename(f)}" }' scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml

Rendered all three H100 values files with the ARC chart:

helm template 1-gpu-h100 oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set --namespace actions-runner-system -f scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml --set controllerServiceAccount.namespace=actions-runner-system --set controllerServiceAccount.name=arc-gha-runner-scale-set-controller --show-only templates/autoscalingrunnerset.yaml
helm template 2-gpu-h100 oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set --namespace actions-runner-system -f scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml --set controllerServiceAccount.namespace=actions-runner-system --set controllerServiceAccount.name=arc-gha-runner-scale-set-controller --show-only templates/autoscalingrunnerset.yaml
helm template 4-gpu-h100 oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set --namespace actions-runner-system -f scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml --set controllerServiceAccount.namespace=actions-runner-system --set controllerServiceAccount.name=arc-gha-runner-scale-set-controller --show-only templates/autoscalingrunnerset.yaml
Checklist
  • cargo +nightly fmt passes
  • cargo clippy --all-targets --all-features -- -D warnings passes
  • (Optional) Documentation updated
  • (Optional) Please join us on Slack #sig-smg to discuss, review, and merge PRs

Summary by CodeRabbit

  • Chores
    • Switched runner pods to persistent host-path backed storage for work, cache and Docker data to improve retention and isolation.
    • Introduced per-pod directory scoping for work, caches and Docker storage to prevent conflicts across concurrent pods.
    • Injected pod identity into containers; init step now prepares per-pod directories and a lifecycle cleanup removes them on termination.
  • Documentation
    • Added guidance describing the H100 runner NVMe storage layout, isolation behavior and cleanup considerations.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Three H100 runner Helm value templates switch ephemeral volumes to hostPath under /raid/actions-runner, inject POD_NAME into runner and dind containers, and scope mounts with subPathExpr so each pod uses isolated subdirectories; an initContainer creates/chowns per-pod dirs and dind removes them on preStop.

Changes

Per-pod Storage Isolation for Runner Scale Sets

Layer / File(s) Summary
Persistent volume definitions
scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml
Pod volumes are redefined to use hostPath storage rooted at /raid/actions-runner for work and docker-storage (and add runner-nvme), while model-cache remains a PVC.
Pod identity environment variable injection
scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml
POD_NAME is injected into runner and dind containers via fieldRef: metadata.name to enable subPathExpr per-pod mounts.
Runner mounts and init container
scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml
Runner volumeMounts use subPathExpr: $(POD_NAME)/... for _work, .cache, and tmp; prepare-runner-nvme initContainer creates/chowns per-pod directories under /runner-nvme/${POD_NAME}.
DinD lifecycle and mounts
scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml, scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml
Privileged dind receives POD_NAME, mounts Docker and runner paths with subPathExpr, and adds a preStop hook to delete /runner-nvme/${POD_NAME} on termination.
H100 Runner NVMe Storage docs
scripts/k8s-runner-resources/README.md
New subsection documents the /raid/actions-runner hostPath layout, per-pod isolation via subPathExpr and POD_NAME, cleanup behavior, and cautions for reuse on other runner types.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • lightseekorg/smg#659: The main PR’s H100 runner Helm values updates (e.g., scripts/k8s-runner-resources/runner-values-*-gpu-h100.yaml switching work/cache/tmp/Docker mounts to pod-isolated hostPath subpaths via POD_NAME, plus initContainer/dind cleanup) directly build on the runner scale-set Helm values and ARC deployment docs introduced in #659.
  • lightseekorg/smg#551: Related changes to DinD/docker sidecar configuration and docker-storage handling (tmpfs/DOCKER_DRIVER vs hostPath isolation).
  • lightseekorg/smg#402: Similar DinD/docker-storage migration from emptyDir to hostPath with overlapping wiring concerns.

Suggested labels

ci, documentation

Suggested reviewers

  • CatherineSue
  • slin1237
  • gongwei-130

Poem

🐰 I dug a little tunnel, soft and neat,
Each runner now has its own tiny seat,
POD_NAME tucked in, subpaths all in line,
Init plants the folders, dind sweeps them fine,
Hop, build, and run — isolated and sweet!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: moving H100 runner workspaces to NVMe storage to resolve CI job eviction issues.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/h100-runner-nvme-workspaces-pr

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the Kubernetes runner configuration files to use host-path volumes with pod-specific subdirectories instead of empty directories, and adds an init container to prepare these directories. The reviewer identified two critical issues across all modified files: first, using hostPath with pod-specific subdirectories poses a high risk of disk space exhaustion on the host NVMe because Kubernetes does not automatically clean up these directories when ephemeral pods are deleted; second, using a heavy Docker-in-Docker image for the init container to perform basic directory setup introduces unnecessary startup latency, which can be optimized by using a lightweight image like alpine or busybox.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 48 to +51
- name: work
emptyDir: {}
hostPath:
path: /raid/actions-runner
type: DirectoryOrCreate

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

⚠️ Disk Space Exhaustion Risk on Host NVMe

Since these runner pods are ephemeral, using hostPath with subPathExpr: $(POD_NAME)/... creates a new directory on the host's NVMe (/raid/actions-runner/<pod-name>) for every single runner pod. Kubernetes does not automatically clean up hostPath directories when a pod is deleted.

Over time, this will accumulate orphaned directories (containing heavy workspaces, caches, and docker layers) and eventually exhaust the NVMe disk space, leading to node disk pressure and job evictions.

Recommended Solutions:

  • Option A (Self-contained Pod Cleanup - Recommended): Mount the parent runner-nvme volume into the dind container and use a preStop lifecycle hook to delete /runner-nvme/${POD_NAME}. Since dind runs as root, it can clean up all files (including those created by Docker).

    # In the dind container definition:
    lifecycle:
      preStop:
        exec:
          command: ["sh", "-c", "rm -rf /runner-nvme/${POD_NAME}"]
  • Option B (Host-level Cleanup): Implement a cronjob or systemd timer on the host nodes to periodically prune directories in /raid/actions-runner/ that do not correspond to active pods or are older than a certain threshold (e.g., 24 hours).

Comment on lines 48 to +51
- name: work
emptyDir: {}
hostPath:
path: /raid/actions-runner
type: DirectoryOrCreate

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

⚠️ Disk Space Exhaustion Risk on Host NVMe

Since these runner pods are ephemeral, using hostPath with subPathExpr: $(POD_NAME)/... creates a new directory on the host's NVMe (/raid/actions-runner/<pod-name>) for every single runner pod. Kubernetes does not automatically clean up hostPath directories when a pod is deleted.

Over time, this will accumulate orphaned directories (containing heavy workspaces, caches, and docker layers) and eventually exhaust the NVMe disk space, leading to node disk pressure and job evictions.

Recommended Solutions:

  • Option A (Self-contained Pod Cleanup - Recommended): Mount the parent runner-nvme volume into the dind container and use a preStop lifecycle hook to delete /runner-nvme/${POD_NAME}. Since dind runs as root, it can clean up all files (including those created by Docker).

    # In the dind container definition:
    lifecycle:
      preStop:
        exec:
          command: ["sh", "-c", "rm -rf /runner-nvme/${POD_NAME}"]
  • Option B (Host-level Cleanup): Implement a cronjob or systemd timer on the host nodes to periodically prune directories in /raid/actions-runner/ that do not correspond to active pods or are older than a certain threshold (e.g., 24 hours).

Comment on lines 47 to +50
- name: work
emptyDir: {}
hostPath:
path: /raid/actions-runner
type: DirectoryOrCreate

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

⚠️ Disk Space Exhaustion Risk on Host NVMe

Since these runner pods are ephemeral, using hostPath with subPathExpr: $(POD_NAME)/... creates a new directory on the host's NVMe (/raid/actions-runner/<pod-name>) for every single runner pod. Kubernetes does not automatically clean up hostPath directories when a pod is deleted.

Over time, this will accumulate orphaned directories (containing heavy workspaces, caches, and docker layers) and eventually exhaust the NVMe disk space, leading to node disk pressure and job evictions.

Recommended Solutions:

  • Option A (Self-contained Pod Cleanup - Recommended): Mount the parent runner-nvme volume into the dind container and use a preStop lifecycle hook to delete /runner-nvme/${POD_NAME}. Since dind runs as root, it can clean up all files (including those created by Docker).

    # In the dind container definition:
    lifecycle:
      preStop:
        exec:
          command: ["sh", "-c", "rm -rf /runner-nvme/${POD_NAME}"]
  • Option B (Host-level Cleanup): Implement a cronjob or systemd timer on the host nodes to periodically prune directories in /raid/actions-runner/ that do not correspond to active pods or are older than a certain threshold (e.g., 24 hours).


initContainers:
- name: prepare-runner-nvme
image: fra.ocir.io/idqj093njucb/docker:dind

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

⚡ Use a Lightweight Image for the Init Container

The prepare-runner-nvme init container uses fra.ocir.io/idqj093njucb/docker:dind just to run a simple shell script (mkdir, chown, chmod). This image is very large and increases pod startup latency due to image pull overhead.

Using a lightweight image like alpine or busybox (~5MB) will significantly speed up pod initialization.

        image: alpine


initContainers:
- name: prepare-runner-nvme
image: fra.ocir.io/idqj093njucb/docker:dind

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

⚡ Use a Lightweight Image for the Init Container

The prepare-runner-nvme init container uses fra.ocir.io/idqj093njucb/docker:dind just to run a simple shell script (mkdir, chown, chmod). This image is very large and increases pod startup latency due to image pull overhead.

Using a lightweight image like alpine or busybox (~5MB) will significantly speed up pod initialization.

        image: alpine


initContainers:
- name: prepare-runner-nvme
image: fra.ocir.io/idqj093njucb/docker:dind

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

⚡ Use a Lightweight Image for the Init Container

The prepare-runner-nvme init container uses fra.ocir.io/idqj093njucb/docker:dind just to run a simple shell script (mkdir, chown, chmod). This image is very large and increases pod startup latency due to image pull overhead.

Using a lightweight image like alpine or busybox (~5MB) will significantly speed up pod initialization.

        image: alpine

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed all three H100 runner value files. The changes are consistent and correct: hostPath volumes with per-pod subPathExpr isolation, proper init container sequencing and permissions, and POD_NAME wired to all containers that need it. LGTM.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml`:
- Around line 99-110: The per-POD subPath directories under /raid/actions-runner
are never pruned; update the initContainer prepare-runner-nvme (or add a cluster
CronJob) to remove stale directories under /raid/actions-runner while preserving
the current $(POD_NAME) directory: implement a safe retention policy (e.g.,
delete dirs older than N days or keep last M) using a targeted find/remove
operation that excludes the current $(POD_NAME) and verifies
ownership/permissions before deletion; ensure this cleanup runs with the same
volume mounts and sufficient privileges as prepare-runner-nvme and
document/parameterize the retention window.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5343b708-bf24-4701-b6f0-bd2d4d3fa82d

📥 Commits

Reviewing files that changed from the base of the PR and between f6db034 and c66ca66.

📒 Files selected for processing (3)
  • scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml
  • scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml
  • scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml

Comment thread scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml
Signed-off-by: key4ng <rukeyang@gmail.com>
@key4ng
key4ng force-pushed the fix/h100-runner-nvme-workspaces-pr branch from c66ca66 to 58df753 Compare June 10, 2026 05:49
command:
- sh
- -c
- mkdir -p /runner-nvme/${POD_NAME}/_work /runner-nvme/${POD_NAME}/.cache /runner-nvme/${POD_NAME}/tmp /runner-nvme/${POD_NAME}/docker /models/.locks /models/hub /models/hub/.locks && chown -R 1001:1001 /runner-nvme/${POD_NAME} && chown 1001:1001 /models/.locks /models/hub /models/hub/.locks && chmod 1777 /runner-nvme/${POD_NAME}/tmp /models/.locks /models/hub/.locks

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Nit: The preStop hook correctly uses ${POD_NAME:?} to bail out if the variable is empty, but this init container command uses bare ${POD_NAME} throughout. If POD_NAME were ever unset, chown -R 1001:1001 /runner-nvme/ would recursively chown the entire NVMe runner directory (all pods' data), and the orphaned directories created under /runner-nvme/ would never be cleaned up by any pod's preStop.

metadata.name is always populated by Kubernetes so this is unlikely in practice, but worth guarding consistently — same pattern applies in the 2-gpu and 4-gpu files.

Suggested change
- mkdir -p /runner-nvme/${POD_NAME}/_work /runner-nvme/${POD_NAME}/.cache /runner-nvme/${POD_NAME}/tmp /runner-nvme/${POD_NAME}/docker /models/.locks /models/hub /models/hub/.locks && chown -R 1001:1001 /runner-nvme/${POD_NAME} && chown 1001:1001 /models/.locks /models/hub /models/hub/.locks && chmod 1777 /runner-nvme/${POD_NAME}/tmp /models/.locks /models/hub/.locks
- mkdir -p /runner-nvme/${POD_NAME:?}/_work /runner-nvme/${POD_NAME:?}/.cache /runner-nvme/${POD_NAME:?}/tmp /runner-nvme/${POD_NAME:?}/docker /models/.locks /models/hub /models/hub/.locks && chown -R 1001:1001 /runner-nvme/${POD_NAME:?} && chown 1001:1001 /models/.locks /models/hub /models/hub/.locks && chmod 1777 /runner-nvme/${POD_NAME:?}/tmp /models/.locks /models/hub/.locks

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml (1)

156-173: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The cleanup mount breaks pod isolation across all H100 runner variants.

Each dind sidecar mounts the shared /raid/actions-runner root at /runner-nvme so it can delete ${POD_NAME} on shutdown. Because workflows control that daemon through Docker, they can also bind-mount /runner-nvme and access sibling runners’ workspaces, caches, and Docker state on the same node. Scope that mount with subPathExpr: $(POD_NAME) and have preStop delete the mounted directory contents instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml` around lines 156
- 173, The current lifecycle preStop exec removes /runner-nvme/${POD_NAME} while
the volumeMount mounts the entire shared root at mountPath /runner-nvme (name:
runner-nvme), which breaks pod isolation; change the volumeMount to scope the
mount with subPathExpr: $(POD_NAME) so each pod only gets its own subdirectory,
and update the preStop (lifecycle.preStop.exec.command) to remove only the
contents of the mounted directory (e.g., delete files under /runner-nvme) rather
than attempting to remove sibling subdirectories; keep references to POD_NAME
for subPathExpr and ensure the startupProbe and other fields remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml`:
- Around line 156-173: The current lifecycle preStop exec removes
/runner-nvme/${POD_NAME} while the volumeMount mounts the entire shared root at
mountPath /runner-nvme (name: runner-nvme), which breaks pod isolation; change
the volumeMount to scope the mount with subPathExpr: $(POD_NAME) so each pod
only gets its own subdirectory, and update the preStop
(lifecycle.preStop.exec.command) to remove only the contents of the mounted
directory (e.g., delete files under /runner-nvme) rather than attempting to
remove sibling subdirectories; keep references to POD_NAME for subPathExpr and
ensure the startupProbe and other fields remain unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 559784b5-f93d-47bc-b415-e855938f8a09

📥 Commits

Reviewing files that changed from the base of the PR and between c66ca66 and 58df753.

📒 Files selected for processing (3)
  • scripts/k8s-runner-resources/runner-values-1-gpu-h100.yaml
  • scripts/k8s-runner-resources/runner-values-2-gpu-h100.yaml
  • scripts/k8s-runner-resources/runner-values-4-gpu-h100.yaml

Signed-off-by: key4ng <rukeyang@gmail.com>
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jun 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e61d96643

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 171 to +173
volumeMounts:
- mountPath: /runner-nvme
name: runner-nvme

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not expose the NVMe parent to job-controlled Docker

On H100 runners, workflow steps talk to this dind daemon via DOCKER_HOST, so any job that can run Docker can now bind-mount /runner-nvme from the daemon container (for example with -v /runner-nvme:/host) and read or delete sibling pods' workspaces, caches, and Docker data on the same node. That bypasses the per-pod subPathExpr isolation this change is trying to add; the same parent mount is repeated in the 2- and 4-GPU H100 values.

Useful? React with 👍 / 👎.

Comment on lines +49 to +51
hostPath:
path: /raid/actions-runner
type: DirectoryOrCreate

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when the NVMe mount is missing

If an H100 node is missing the /raid NVMe mount or it is not mounted yet, DirectoryOrCreate lets kubelet create /raid/actions-runner on whatever filesystem backs that path, which can silently put workspaces, caches, and Docker layers back on the boot disk instead of failing fast. That reintroduces the eviction/root-disk exhaustion scenario this change is meant to avoid; the same DirectoryOrCreate hostPath is repeated in the other H100 values.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/k8s-runner-resources/README.md`:
- Line 126: The docs incorrectly call the dind container an "init container";
update the sentence to say the H100 values mount the parent NVMe path into the
dind sidecar (not an init container) and clarify that the actual init container
is prepare-runner-nvme; keep the mention of the preStop hook that removes
/runner-nvme/${POD_NAME:?} and the hostPath behavior, but replace "dind
sidecar-style init container" with something like "dind sidecar (the init
container is prepare-runner-nvme)" to accurately reference the containers and
hooks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 57571d8f-1f33-4d02-8839-061b2c3d0897

📥 Commits

Reviewing files that changed from the base of the PR and between 58df753 and 7e61d96.

📒 Files selected for processing (1)
  • scripts/k8s-runner-resources/README.md


The H100 runner scale-set values mount `/raid/actions-runner` from the host into each runner pod. Workspace, cache, temp, and Docker storage paths use `subPathExpr: $(POD_NAME)/...` so concurrent pods on the same node do not share mutable state.

Because Kubernetes does not garbage collect `hostPath` contents when a pod is deleted, the H100 values also mount the parent NVMe path into the dind sidecar-style init container and use a `preStop` hook to remove `/runner-nvme/${POD_NAME:?}` during normal pod termination. This cleanup is best-effort; force deletion or node failure can still leave orphaned directories. Add host-level pruning if the cluster needs stronger cleanup guarantees.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Incorrect container terminology.

The documentation refers to "the dind sidecar-style init container," but the dind container is a regular sidecar container (with a preStop hook), not an init container. The actual init container is prepare-runner-nvme.

📝 Suggested correction
-Because Kubernetes does not garbage collect `hostPath` contents when a pod is deleted, the H100 values also mount the parent NVMe path into the dind sidecar-style init container and use a `preStop` hook to remove `/runner-nvme/${POD_NAME:?}` during normal pod termination. This cleanup is best-effort; force deletion or node failure can still leave orphaned directories. Add host-level pruning if the cluster needs stronger cleanup guarantees.
+Because Kubernetes does not garbage collect `hostPath` contents when a pod is deleted, the H100 values also mount the parent NVMe path into the dind sidecar container and use a `preStop` hook to remove `/runner-nvme/${POD_NAME:?}` during normal pod termination. This cleanup is best-effort; force deletion or node failure can still leave orphaned directories. Add host-level pruning if the cluster needs stronger cleanup guarantees.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Because Kubernetes does not garbage collect `hostPath` contents when a pod is deleted, the H100 values also mount the parent NVMe path into the dind sidecar-style init container and use a `preStop` hook to remove `/runner-nvme/${POD_NAME:?}` during normal pod termination. This cleanup is best-effort; force deletion or node failure can still leave orphaned directories. Add host-level pruning if the cluster needs stronger cleanup guarantees.
Because Kubernetes does not garbage collect `hostPath` contents when a pod is deleted, the H100 values also mount the parent NVMe path into the dind sidecar container and use a `preStop` hook to remove `/runner-nvme/${POD_NAME:?}` during normal pod termination. This cleanup is best-effort; force deletion or node failure can still leave orphaned directories. Add host-level pruning if the cluster needs stronger cleanup guarantees.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/k8s-runner-resources/README.md` at line 126, The docs incorrectly
call the dind container an "init container"; update the sentence to say the H100
values mount the parent NVMe path into the dind sidecar (not an init container)
and clarify that the actual init container is prepare-runner-nvme; keep the
mention of the preStop hook that removes /runner-nvme/${POD_NAME:?} and the
hostPath behavior, but replace "dind sidecar-style init container" with
something like "dind sidecar (the init container is prepare-runner-nvme)" to
accurately reference the containers and hooks.

@slin1237
slin1237 merged commit 63b532a into main Jun 10, 2026
40 checks passed
@slin1237
slin1237 deleted the fix/h100-runner-nvme-workspaces-pr branch June 10, 2026 18:47
key4ng added a commit that referenced this pull request Jun 12, 2026
This reverts commit 63b532a.

Signed-off-by: Keyang Ru <rukeyang@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants