Configurable Container Runtime (Docker/Podman) - #27
Conversation
Introduces containerRuntime: docker|podman toggle across the chart stack.
Switching runtimes requires only a values change + VM recreate — no golden
image rebuild needed when both images are pre-built.
Key changes:
- openshell-saw values: containerRuntime (default: docker), dataSource
auto-derived from runtime via new openshell-sandbox.dataSourceName helper
- cloud-init: OPENSHELL_DRIVERS set from containerRuntime value
- configmap-scripts: RUNTIME variable injected into all setup scripts;
registry auth and docker login wrapped in docker-only conditional;
binary extraction (pull/create/cp/rm) and dashboard systemd units use
${RUNTIME} throughout; NemoClaw+Podman guard at setup start
- image-builder-charts: $imageName derived from containerRuntime
(openshell-gateway-docker vs openshell-gateway); virt-customize branches
on runtime for Docker CE vs Podman; user-setup.sh enables user-level
podman.socket after the user bus is ready; OPENSHELL_PODMAN_SOCKET and
OPENSHELL_GRPC_ENDPOINT derived per runtime
- Makefile-quickstart: CONTAINER_RUNTIME and IMAGE_NAME variables;
build-openshell-gateway and openshell-saw-create forward runtime;
configure-gateway is now idempotent (remove-before-add)
- e2e-test.sh, test-bootc-e2e.sh: runtime-aware binary version check
- docs/container-runtime.md: new doc covering both runtime paths,
build/deploy commands, and known limitations
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…gured setup-dashboard.sh previously hard-exited (exit 1) when OIDC_ISSUER was unset, causing the setup Job to fail and retry even when dashboard.enabled is true but Keycloak is not deployed. Now exits cleanly with an explanatory message, matching the pattern of other optional setup steps. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Documents the mTLS cert setup, port-forward, and ssh-proxy command needed to reach the openclaw TUI from a local workstation. Notes the virtctl dependency and the follow-up improvement (publish certs as a k8s Secret to remove that dependency). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
podman on macOS runs inside a VM — TCP connections to the OpenShift external registry route are dropped mid-upload for large layers (>30 MB), making `make copy-images` unreliable. On macOS, `copy-images` now detects `uname -s == Darwin` and delegates to scripts/mirror-images-incluster.sh, which runs skopeo inside the cluster against the internal registry service (bypassing the external route entirely). On Linux the original oc-image-mirror path is unchanged. New files: - scripts/mirror-images-incluster.sh — orchestrates per-image Jobs - scripts/mirror-images-rbac.yaml — ServiceAccount + RoleBinding (static) - scripts/mirror-images-job.yaml — Job template (envsubst-rendered per image) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
sauagarwa
left a comment
There was a problem hiding this comment.
Good PR overall — clean single-toggle design, solid guard rails. A few things to address:
1. In-cluster mirror Job: use oc image mirror instead of skopeo
The Job already runs inside the cluster, so oc image mirror can push directly to image-registry.openshift-image-registry.svc:5000 — same as skopeo but without introducing a new tool. This lets you:
- Use
registry.redhat.io/openshift4/ose-cliinstead ofregistry.redhat.io/ubi8/skopeo - Drop the
anyuidSCC grant (oc image mirrordoesn't need root) - Keep tooling consistent with the Linux path
Applies to: scripts/mirror-images-job.yaml, scripts/mirror-images-incluster.sh, scripts/mirror-images-rbac.yaml
2. Podman socket wait loop needs a warning on timeout
In buildconfig.yaml, the Podman socket wait loop silently continues if the socket never appears after 15s. If the gateway then can't reach Podman, the failure surfaces later with no clue about the root cause. Add a warning:
for _ in $(seq 1 15); do
if [[ -S "/run/user/${USER_UID}/podman/podman.sock" ]]; then break; fi
sleep 1
done
if [[ ! -S "/run/user/${USER_UID}/podman/podman.sock" ]]; then
echo "WARNING: Podman socket not found after 15s — gateway may fail to start" >&2
fi3. models.mode = 'replace' is unrelated to the runtime toggle
The fix in configmap-scripts.yaml (changing the invalid custom to replace) is correct but unrelated to container runtime configurability. Consider splitting it into a separate commit for cleaner bisect history.
Jira: https://redhat.atlassian.net/browse/APPENG-6041
Summary
Makes the container runtime inside the gateway VM configurable via a single Helm value (
containerRuntime: docker|podman). Ships two pre-built golden images — a Docker variant for NemoClaw and a Podman variant for openclaw/opencode — and routes all runtime-specific behavior through the toggle. Switching runtimes requires only a values change + VM recreate; no golden image rebuild is needed.What changed
charts/openshell-sawvalues.yaml— newcontainerRuntime: dockerfield (default);source.dataSourcecleared so it auto-derives from the runtimetemplates/_helpers.tpl— newopenshell-sandbox.dataSourceNamehelper: resolvesopenshell-gateway-dockerfor docker,openshell-gatewayfor podman, with explicit override supporttemplates/virtualmachine.yaml— DataSource name now uses the helpertemplates/cloudinit-sandbox.yaml—OPENSHELL_DRIVERSset fromcontainerRuntimeinstead of hardcodeddockertemplates/configmap-scripts.yaml— multiple changes across all setup scripts:RUNTIMEvariable injected at the top ofrun-setup.sh,setup-nemoclaw.sh,setup-dashboard.sh,setup-workspaces.shdocker pull/create/cp/rm/run/stop/logsreplaced with${RUNTIME}docker login, insecure-registries daemon config) wrapped in a Docker-only conditional; Podman path prints a clear skip messageBUILD_NSandNEMOCLAW_CLI_IMAGEgated so they don't cause unbound-variable errors on the Podman pathcontainerRuntime=podmanandonboardCli=nemoclawsetup-dashboard.shexits gracefully (not with exit 1) whenoidc.issuerUrlis not configured, preventing spurious Job retries in standalone deployments without Keycloakmodels.modein the openclaw config set toreplace(only configured providers shown in TUI) instead of the invalidcustomimage-builder-charts/helm/openshell-gateway-imagevalues.yaml— newcontainerRuntime: dockerfieldtemplates/buildconfig.yaml— branches oncontainerRuntime:docker.service, derives GRPC endpoint fromdocker network inspect bridge(172.17.0.1)podman.socket(after the user systemd bus is ready), setsOPENSHELL_PODMAN_SOCKETin gateway.env, derives GRPC endpoint frompodman network inspect podman(10.88.0.1)$imageNamederived from runtime:openshell-gateway-docker(Docker) oropenshell-gateway(Podman)templates/golden-image.yamlandtemplates/imagestream.yaml— use$imageNamefor all resource namesMakefile and scripts
Makefile-quickstart—CONTAINER_RUNTIMEandIMAGE_NAMEvariables;build-openshell-gatewayusesIMAGE_NAMEthroughout;openshell-saw-createforwardsCONTAINER_RUNTIMEandGOVERNANCE_ENABLED;configure-gatewayis now idempotent (removes stale entry before re-adding)scripts/openshell-saw-create.sh— acceptsCONTAINER_RUNTIMEandGOVERNANCE_ENABLEDenv vars, passes both to helmscripts/e2e-test.sh(line 304) andtests/test-bootc-e2e.sh(line 346) — runtime version check uses the configured runtime instead of the stalepodman --versionmacOS copy-images fix
make copy-imagesfails on macOS becausepodmanruns inside a VM and large-layer TCP uploads to the OpenShift external registry route are dropped mid-transfer. Onuname -s == Darwin, the target now delegates to an in-cluster skopeo Job that pushes directly toimage-registry.openshift-image-registry.svc:5000, bypassing the external route entirely.New files:
scripts/mirror-images-incluster.sh,scripts/mirror-images-rbac.yaml,scripts/mirror-images-job.yamlDocs
docs/container-runtime.md— new doc covering: runtime comparison table, golden image build commands, deploy commands, TUI connection steps (mTLS cert copy, port-forward, ssh-proxy), and known limitations (NemoClaw incompatibility, inference.local, rootless Podman caveats)E2E validation (Docker path, clean first-time install)
Tested against
cluster-7brvw.dyn.redhatworkshops.io:make build-openshell-gateway CONTAINER_RUNTIME=dockeropenshell-gateway-dockerImageStream + DataSource createdSucceededopenshell-gateway-dockerdocker loginto internal registrydocker pull/create/cp/rmbinary extractionnemoclaw-sandbox:latestopenclaw gateway readyrun-create OK/Setup completeopenclawresponded to promptsPodman path validation:
✗ Docker is not reachable— correct expected failurepodman pull/create/cp/rm— confirmed in logsOPENSHELL_DRIVERS=podmanin cloud-init — confirmedopenshell-gateway— confirmedNotes for reviewers
inference.localrouting (nemoclaw onboardstep 4) fails with externally-supervised gateways running 0.0.99+. The setup Job's fallback creates the inference provider and sandbox viaopenshell provider create+openshell sandbox create, which is sufficient for TUI use. This is a known upstream limitation unrelated to this PR.nemoclaw-sandboximage: Must be available in the internal registry before the setup Job runs. On first deploy, usemake copy-images(Linux) or it runs automatically on macOS via the new in-cluster Job path.127.0.0.1. TUI access requires copying the client cert from the VM (virtctl scp) and port-forwarding the gateway service. Steps documented indocs/container-runtime.md. A follow-up improvement would be publishing the client cert as a k8s Secret from the setup Job to eliminate thevirtctldependency.