You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a6c775e
Browse filesBrowse the repository at this point in the historyBrowse files
fix(bootstrap): persist sandbox state across gateway stop/start cycles
Sandbox state was lost whenever the gateway was stopped and restarted.
k3s used the Docker container ID as its node name, which changes on
container recreation (e.g. after an image upgrade). This caused
clean_stale_nodes() to delete all PVCs with node affinity for the old
node — including the server's own SQLite database PVC.
Fix with a three-layer approach to ensure a deterministic k3s node name:
1. Set the Docker container hostname to a deterministic name derived
from the gateway name (openshell-{name}). k3s uses the hostname
as its default node name, and it persists across container
stop/start cycles.
2. Pass OPENSHELL_NODE_NAME env var and --node-name flag to k3s via
the cluster entrypoint as a belt-and-suspenders measure.
3. Update clean_stale_nodes() to prefer the deterministic name, with
a fallback to the container hostname for backward compatibility
with older cluster images that don't have the entrypoint change.
Fixes#738
Copy file name to clipboardExpand all lines: architecture/gateway-single-node.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -185,7 +185,7 @@ For the target daemon (local or remote):
185
185
186
186
After the container starts:
187
187
188
-
1.**Clean stale nodes**: `clean_stale_nodes()` finds `NotReady`nodes via `kubectl get nodes` and deletes them. This is needed when a container is recreated but reuses the persistent volume -- k3s registers a new node (using the container ID as hostname) while old node entries persist in etcd. Non-fatal on error; returns the count of removed nodes.
188
+
1.**Clean stale nodes**: `clean_stale_nodes()` finds nodes whose name does not match the deterministic k3s `--node-name` and deletes them. That node name is derived from the gateway name but normalized to a Kubernetes-safe lowercase form so existing gateway names that contain `_`, `.`, or uppercase characters still produce a valid node identity. This cleanup is needed when a container is recreated but reuses the persistent volume -- old node entries can persist in etcd. Non-fatal on error; returns the count of removed nodes.
189
189
2.**Push local images** (optional, local deploy only): If `OPENSHELL_PUSH_IMAGES` is set, the comma-separated image refs are exported from the local Docker daemon as a single tar, uploaded into the container via `docker put_archive`, and imported into containerd via `ctr images import` in the `k8s.io` namespace. After import, `kubectl rollout restart deployment/openshell openshell` is run, followed by `kubectl rollout status --timeout=180s` to wait for completion. See `crates/openshell-bootstrap/src/push.rs`.
190
190
3.**Wait for gateway health**: `wait_for_gateway_ready()` polls the Docker HEALTHCHECK status up to 180 times, 2 seconds apart (6 min total). A background task streams container logs during this wait. Failure modes:
191
191
- Container exits during polling: error includes recent log lines.
-**Create**: Translates a `Sandbox` proto into a Kubernetes `DynamicObject` with labels (`openshell.ai/sandbox-id`, `openshell.ai/managed-by: openshell`) and a spec that includes the pod template, environment variables, and gateway-required env vars (`OPENSHELL_SANDBOX_ID`, `OPENSHELL_ENDPOINT`, `OPENSHELL_SSH_LISTEN_ADDR`, etc.).
504
+
-**Create**: Translates a `Sandbox` proto into a Kubernetes `DynamicObject` with labels (`openshell.ai/sandbox-id`, `openshell.ai/managed-by: openshell`) and a spec that includes the pod template, environment variables, and gateway-required env vars (`OPENSHELL_SANDBOX_ID`, `OPENSHELL_ENDPOINT`, `OPENSHELL_SSH_LISTEN_ADDR`, etc.). When callers do not provide custom `volumeClaimTemplates`, the server injects a default `workspace` PVC and mounts it at `/sandbox` so the default sandbox home/workdir survives pod rescheduling.
505
505
-**Delete**: Calls the Kubernetes API to delete the CRD by name. Returns `false` if already gone (404).
506
506
-**Pod IP resolution**: `agent_pod_ip()` fetches the agent pod and reads `status.podIP`.
0 commit comments