From 9a15e4ce52df6fe0615584610004346081e1b46e Mon Sep 17 00:00:00 2001 From: Andrew Stoltz Date: Sun, 17 May 2026 21:24:30 -0500 Subject: [PATCH] feat(github-runner): pod-env DOTNET_INSTALL_DIR + initContainer for non-root runner Sprint 30 Cl-1 acceptance fix. Sets DOTNET_INSTALL_DIR + NUGET_PACKAGES + 4 sibling env vars on both Deployments so non-root runner (UID 1001) can write to /home/runner/.dotnet + /home/runner/.nuget without the per-workflow patch that ~25 flipped Linux repos currently carry. initContainer pre-creates + chowns the dirs to runner:runner so the runtime mkdir-or-write succeeds on first restore. emptyDir mounted at /home/runner; the .nuget/packages PVC (Common runner) wins at its nested mount path so the persistent NuGet cache survives ephemeral pod restarts. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/github-runner/github-runner.yaml | 92 +++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/apps/github-runner/github-runner.yaml b/apps/github-runner/github-runner.yaml index 6e7d31c..90ca5e1 100644 --- a/apps/github-runner/github-runner.yaml +++ b/apps/github-runner/github-runner.yaml @@ -141,6 +141,32 @@ spec: runAsUser: 1001 runAsGroup: 1001 fsGroup: 1001 + # Sprint 30 Cl-1 pod-env fix (2026-05-21): pre-create + chown + # /home/runner/.dotnet + /home/runner/.nuget so the non-root runner + # (UID 1001) can host setup-dotnet@v4 + dotnet restore writes without + # the per-workflow DOTNET_INSTALL_DIR patch ~25 flipped Linux repos + # have been carrying. Runs as root so chown succeeds; the main + # container then runs as 1001 against an emptyDir mounted at + # /home/runner. The PVC mount at /home/runner/.nuget/packages + # (Common runner) still wins at its nested path because Kubernetes + # honors the deeper mount. + initContainers: + - name: setup-runner-home + image: busybox:1.36 + command: + - sh + - -c + - | + set -e + mkdir -p /home/runner/.dotnet /home/runner/.nuget/packages /home/runner/.nuget/NuGet + chown -R 1001:1001 /home/runner/.dotnet /home/runner/.nuget + chmod -R 755 /home/runner/.dotnet /home/runner/.nuget + securityContext: + runAsUser: 0 + runAsNonRoot: false + volumeMounts: + - name: runner-home + mountPath: /home/runner containers: - name: runner image: myoung34/github-runner:latest @@ -181,6 +207,22 @@ spec: # setup steps (cache prewarm + apt updates — both already baked). - name: RUN_AS_ROOT value: "false" + # Sprint 30 Cl-1 pod-env fix (2026-05-21): retire the per-workflow + # DOTNET_INSTALL_DIR patch by setting it (+ siblings) here so ALL + # flipped Linux repos pick it up automatically. setup-dotnet@v4 + # default writes to /usr/share/dotnet (root-only) or HOME-relative + # ~/.dotnet without HOME guard; pin both explicitly to the chowned + # emptyDir at /home/runner. + - name: DOTNET_INSTALL_DIR + value: "/home/runner/.dotnet" + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: "1" + - name: NUGET_PACKAGES + value: "/home/runner/.nuget/packages" + - name: DOTNET_NOLOGO + value: "1" + - name: DOTNET_GENERATE_ASPNET_CERTIFICATE + value: "false" resources: requests: cpu: "500m" @@ -189,6 +231,14 @@ spec: cpu: "2000m" memory: "4Gi" volumeMounts: + # /home/runner emptyDir — owned by the non-root runner thanks + # to the setup-runner-home initContainer chown. Hosts .dotnet + # (setup-dotnet@v4 target) and provides a writable HOME without + # forcing a PVC. The PVC mount below at .nuget/packages wins + # at that nested path (deeper mount overrides), so the Common + # NuGet cache continues to persist across ephemeral pod restarts. + - name: runner-home + mountPath: /home/runner - name: nuget-cache mountPath: /home/runner/.nuget/packages - name: tmp @@ -204,6 +254,8 @@ spec: periodSeconds: 30 failureThreshold: 3 volumes: + - name: runner-home + emptyDir: {} - name: nuget-cache persistentVolumeClaim: claimName: github-runner-nuget-cache @@ -255,6 +307,27 @@ spec: runAsUser: 1001 runAsGroup: 1001 fsGroup: 1001 + # Sprint 30 Cl-1 pod-env fix (2026-05-21): see github-runner Deployment + # above for full rationale. Mirrored on the Shared.Pos runner so the + # per-workflow DOTNET_INSTALL_DIR patch can be retired fleet-wide + # rather than re-applied per repo as flipped lanes land. + initContainers: + - name: setup-runner-home + image: busybox:1.36 + command: + - sh + - -c + - | + set -e + mkdir -p /home/runner/.dotnet /home/runner/.nuget/packages /home/runner/.nuget/NuGet + chown -R 1001:1001 /home/runner/.dotnet /home/runner/.nuget + chmod -R 755 /home/runner/.dotnet /home/runner/.nuget + securityContext: + runAsUser: 0 + runAsNonRoot: false + volumeMounts: + - name: runner-home + mountPath: /home/runner containers: - name: runner image: myoung34/github-runner:latest @@ -277,6 +350,17 @@ spec: key: credential - name: RUN_AS_ROOT value: "false" + # Sprint 30 Cl-1 pod-env fix (2026-05-21): retire per-workflow patch. + - name: DOTNET_INSTALL_DIR + value: "/home/runner/.dotnet" + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: "1" + - name: NUGET_PACKAGES + value: "/home/runner/.nuget/packages" + - name: DOTNET_NOLOGO + value: "1" + - name: DOTNET_GENERATE_ASPNET_CERTIFICATE + value: "false" resources: requests: cpu: "500m" @@ -285,6 +369,12 @@ spec: cpu: "2000m" memory: "4Gi" volumeMounts: + # Shared.Pos runner uses emptyDir for nuget cache (no node pin + # via RWO PVC). /home/runner emptyDir hosts .dotnet via the + # setup-runner-home initContainer chown; the .nuget/packages + # emptyDir mount still wins at its nested path. + - name: runner-home + mountPath: /home/runner - name: nuget-cache mountPath: /home/runner/.nuget/packages - name: tmp @@ -299,6 +389,8 @@ spec: periodSeconds: 30 failureThreshold: 3 volumes: + - name: runner-home + emptyDir: {} - name: nuget-cache emptyDir: {} - name: tmp