Repository navigation
🐛 Fix pvc-migration hook runAsNonRoot failure on non-OpenShift clusters - #22947
Conversation
…rs (#22946) The pre-upgrade pvc-migration hook has been failing every scheduled Console Live Promote run with: Error: container has runAsNonRoot and image will run as root (container: migrate-pvcs) alpine/k8s has no USER directive, so it runs as root. After #22929 removed the explicit runAsUser (to satisfy OpenShift's restricted-v2 SCC, #22925), the hook was left with runAsNonRoot: true and no numeric UID. On OpenShift the SCC injects an in-range UID, so it works there — but on the plain-Kubernetes console-live cluster (OKE) nothing injects a UID, the container's effective user stays root, and the kubelet refuses to start it. The failed hook then cascades into 'pre-upgrade hooks failed' and an immutable-PVC rollback failure. Fix: mirror the chart's existing securityContext.runAsUser pattern for the app container — default migration.runAsUser/runAsGroup to the numeric non-root UID 65532 in values.yaml (rendered conditionally in the hook template), and null them on OpenShift via values-openshift.yaml and the build-deploy.yml OpenShift helm invocation, where the SCC injects its own UID. The UID need not exist in /etc/passwd, and the hook already sets HOME=/tmp so kubectl cache writes work for any UID. Verified with helm template: default values render runAsUser/runAsGroup 65532; the OpenShift overlay renders neither field. Fixes #22946 Refs #22907 #22919 Signed-off-by: Andrew Anderson <andy@clubanderson.com>
✅ Deploy Preview for kubestellarconsole canceled.
|
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
👋 Hey @clubanderson — thanks for opening this PR!
This is an automated message. |
|
🐝 Hi @clubanderson! I'm Trusted users — org members and contributors with write access — can mention Automation may take a moment to start, and follow-up happens through workflow activity rather than chat replies. |
There was a problem hiding this comment.
Pull request overview
This PR fixes the Helm chart’s pre-upgrade pvc-migration hook failing runAsNonRoot admission on non-OpenShift clusters by introducing explicit non-root runAsUser/runAsGroup defaults for the migration container, while keeping OpenShift behavior unchanged by nulling those fields in the OpenShift overlay and deploy workflow.
Changes:
- Add
migration.runAsUser/migration.runAsGroupdefaults (65532) in the chart’svalues.yamlfor plain Kubernetes clusters. - Update the pvc-migration hook template to conditionally render
runAsUser/runAsGroup, and update the OpenShift overlay to null them so SCC can inject an in-range UID. - Update OpenShift deploy workflow and Helm README instructions to also null the migration UID/GID fields.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| deploy/helm/kubestellar-console/values.yaml | Adds default non-root UID/GID for the pvc-migration hook container. |
| deploy/helm/kubestellar-console/values-openshift.yaml | Nulls migration UID/GID so OpenShift SCC can inject an allowed UID. |
| deploy/helm/kubestellar-console/templates/pre-upgrade-pvc-migration.yaml | Conditionally renders migration container runAsUser/runAsGroup alongside runAsNonRoot: true. |
| deploy/helm/kubestellar-console/README.md | Documents nulling migration UID/GID when deploying to OpenShift without the overlay file. |
| .github/workflows/build-deploy.yml | Ensures OpenShift deploy job also nulls migration UID/GID via Helm --set. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| runAsNonRoot: true | ||
| {{- if .Values.migration.runAsUser }} | ||
| runAsUser: {{ .Values.migration.runAsUser }} | ||
| {{- end }} | ||
| {{- if .Values.migration.runAsGroup }} | ||
| runAsGroup: {{ .Values.migration.runAsGroup }} | ||
| {{- end }} | ||
| allowPrivilegeEscalation: false |
|
Thank you for your contribution! Your PR has been merged. Check out what's new:
Stay connected: Slack #kubestellar-dev | Multi-Cluster Survey |
|
Post-merge build verification passed ✅ Both Go and frontend builds compiled successfully against merge commit |
…#22958) Console Live Promote failed every scheduled run with: serviceaccount "kc-live-kubestellar-console" not found (run 33346472599). The pvc-migration hook itself now completes fine (#22947); the missing SA is the *main* release ServiceAccount that the Deployment's ReplicaSet references. Root cause: both the canary and live releases deploy with serviceAccount.create: false, so no release owns the SA. But the corrupted release state left by the earlier hook-failure/rollback loop (#22946) still records the SA inside the perpetual rollback-target revision's manifest. Helm v4 therefore treats every upgrade as "SA removed from the chart" and prunes it mid-upgrade; pod creation is rejected instantly, the 10m --wait expires, and the atomic rollback then wedges on the immutable PVC volumeName patch. The follow-up 'helm rollback' restores the SA from the old revision, re-arming the same failure for the next scheduled run. Fix (workflow-only, no chart change needed): - live prod values now set serviceAccount.create: true (same name via LIVE_SERVICE_ACCOUNT), so the SA is part of every rendered upgrade and Helm reconciles/adopts it instead of pruning it. Once one upgrade succeeds, the release snapshot also re-owns the PVC, so future rollbacks no longer hit the immutability error. - new idempotent pre-flight step recreates the SA if absent before the canary/live deploys, unwedging the currently-broken cluster without any manual action. The canary release keeps create: false and only references the SA; exactly one release may own it. Fixes #22957 Refs #22946 Signed-off-by: Andy Anderson <andy@clubanderson.com>
Problem
Console Live Promotehas failed every scheduled run since 2026-08-26. The pre-upgradepvc-migrationhook pod is refused at container start on the console-live cluster:The failed hook then cascades into
pre-upgrade hooks failed→ helm rollback →PersistentVolumeClaim ... spec is immutable→UPGRADE FAILED(run 33311744159).Why the previous attempts did not clear it
runAsNonRoot: false+runAsUser: 0on the container. That would have passed the kubelet check, but it was replaced almost immediately by 🐛 Fix pvc-migration hook rejected by OpenShift restricted-v2 SCC #22929 (for Workflow failure: Build and Deploy KC #22925) because OpenShift's restricted-v2 SCC forbidsrunAsUser: 0. 🐛 Fix pvc-migration hook rejected by OpenShift restricted-v2 SCC #22929 reverted torunAsNonRoot: truewith norunAsUser— which works on OpenShift (the SCC injects an in-range UID) but reintroduced the failure on every non-OpenShift cluster:alpine/k8shas noUSERdirective, so with nothing injecting a UID the container's effective user is root and the kubelet refuses to start it. The console-live cluster (OKE,oci-bvstorage) is plain Kubernetes, so every promote since has failed.Fix (differs from both prior attempts)
Mirror the chart's long-standing pattern for the app container (
securityContext.runAsUser: 1001invalues.yaml, nulled on OpenShift):values.yaml: newmigration.runAsUser: 65532/migration.runAsGroup: 65532— explicit numeric non-root UID (distroless "nonroot" convention; the UID need not exist in/etc/passwd, and the hook already setsHOME=/tmpso kubectl cache/config writes work for any UID).templates/pre-upgrade-pvc-migration.yaml: renderrunAsUser/runAsGroupconditionally so nulling them drops the fields;runAsNonRoot: trueis kept (PodSecurityrestrictedstill satisfied).values-openshift.yaml+ the OpenShiftdeploy_helminbuild-deploy.yml+ README: nullmigration.runAsUser/runAsGroupso restricted-v2 keeps injecting its own in-range UID — OpenShift behavior is unchanged from today.Verified with
helm template: default values renderrunAsUser/runAsGroup: 65532on themigrate-pvcscontainer; the OpenShift overlay renders neither field.Fixes #22946
Refs #22907 #22919