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
Kubernetes sandbox pods can be evicted or terminated for several infrastructure reasons, including:
Planned node maintenance and drains.
Cluster autoscaling.
Node upgrades or graceful shutdown.
Resource-pressure eviction.
Scheduler preemption.
Node failure or loss.
When this happens, OpenShell must determine:
Whether to protect the pod from a planned eviction.
Whether there is time to checkpoint state.
Whether a replacement pod was created.
Whether the replacement can run on another node.
Which sandbox state survived.
How to communicate disruption and recovery to users.
OpenShell currently reduces these situations to broad lifecycle phases such as Provisioning. It does not explain that the sandbox was evicted, identify the affected pod instance or node, show why recovery is blocked, or indicate whether durable state was restored.
Node-Drain Experiment
To investigate this behavior, we deployed OpenShell into a two-worker kind cluster and created a sandbox through the OpenShell CLI. The gateway ran on one worker and the sandbox ran on the other.
We then drained the worker hosting the sandbox.
The experiment showed:
A normal drain refused to evict the sandbox because the pod used an emptyDir.
Drain succeeded after adding --delete-emptydir-data.
The OpenShell sandbox record and Agent Sandbox CR were preserved.
Agent Sandbox created a replacement pod with the same name and a new UID.
The replacement could not move to the second worker because kind's local-path PV was bound to the original node.
OpenShell displayed only Provisioning while recovery was blocked.
After the original node was uncordoned, the replacement became Ready using the same PVC.
Files under /sandbox survived.
Files under /tmp, running processes, exec sessions, and connections did not survive.
This experiment demonstrates one planned infrastructure disruption. The solution should also address unplanned disruptions, recognizing that checkpointing is only possible when OpenShell receives advance notice.
Update the API, CLI, JSON/YAML output, TUI, logs, and metrics to distinguish initial provisioning from recovery.
2. Protect planned evictions
Support an optional per-sandbox PodDisruptionBudget.
Testing confirmed that the following behavior blocks voluntary eviction:
minAvailable: 1
Because a sandbox is a singleton, the replacement cannot be created until the original pod is deleted. The PDB must therefore be explicitly relaxed after checkpointing or by an operator.
A PDB protects against voluntary Eviction API operations. It cannot prevent direct pod deletion, sudden node failure, or drains that bypass eviction.
The checkpoint deadline should be shorter than the Kubernetes termination grace period, leaving time for process shutdown and supervisor cleanup.
Potential checkpoint failure policies include:
Block: retain eviction protection and require operator intervention.
Proceed: allow eviction even if checkpointing fails.
ProceedAfterTimeout: block initially and proceed when the deadline expires.
Application-level checkpointing should be the initial scope. It can preserve:
Files under /sandbox.
Git working state.
Agent task metadata.
Application-specific checkpoints.
Information needed to restart interrupted work.
Transparent restoration of process memory, sockets, exec sessions, and SSH sessions is out of scope.
A Kubernetes preStop hook or SIGTERM handler could provide a simpler best-effort checkpoint. However, eviction has already been accepted at that point and cannot be cancelled if checkpointing fails. See Kubernetes lifecycle hooks.
For unplanned disruption, OpenShell should recover whatever is available from persistent storage and explicitly report that no checkpoint occurred.
4. Document storage durability requirements
Document that:
OpenShell's default /sandbox PVC survives replacement of the pod while the Sandbox CR remains.
Cross-node recovery requires a portable CSI-backed StorageClass.
kind's default local-path storage remains tied to its original node.
emptyDir, /tmp, container-layer changes, and process state do not survive.
Externally managed PVCs can make data ownership independent of the Sandbox CR.
Retain reclaim policies can protect storage after PVC or sandbox deletion.
CSI VolumeSnapshots can provide additional recovery points.
--delete-emptydir-data is required for the current sandbox pod layout during drain.
Alternatives Considered
PodDisruptionBudget only
A PDB successfully blocks voluntary eviction, but it does not checkpoint state or provide availability. Because the sandbox is a singleton, the replacement cannot be created until the original pod is deleted.
Longer termination grace period only
This gives the supervisor more time to shut down, but eviction has already started. It cannot block deletion when checkpointing fails.
Pod finalizers
Finalizers can leave pod objects stuck in Terminating, but they do not keep the workload usable if its node is unavailable. They are not suitable as an eviction-protection mechanism.
Portable storage only
Portable storage allows the replacement to move to another node and preserves /sandbox, but it does not preserve processes, connections, or active sessions.
Full process checkpoint and restore
CRIU or runtime-level checkpointing could theoretically preserve process memory. Compatibility across kernels, container runtimes, namespaces, sockets, mounts, and security configurations makes this unsuitable for the initial design.
Agent Investigation
Environment
OpenShell revision: 8c7dd148
Built images: v0.0.90-67-g8c7dd148
Agent Sandbox controller: v0.5.0
Kubernetes: v1.31.0
Cluster: kind with two worker nodes
StorageClass: standard
Provisioner: rancher.io/local-path
Observed identities
Resource
Before drain
After drain
OpenShell sandbox ID
2e3ae382-2272-4229-90bc-c5a8bd60c017
Unchanged
Agent Sandbox CR UID
e81b7fb9-669b-4ae0-a56b-e4b39027174c
Unchanged
Pod UID
45d3c0d0-3910-461f-a4c8-72fff452417b
0d2b3a54-0936-485b-b027-afbb64897347
PVC UID
5ba67215-0d8f-462f-b3ed-d0440ed33bea
Unchanged
OpenShell phase
Ready
Provisioning, then Ready
State validation
/sandbox/pvc-marker: survived.
/tmp/ephemeral-marker: lost.
The replacement remained Pending until the original node was uncordoned.
OpenShell exposed only Provisioning while Kubernetes showed a Pending replacement.
PDB validation
minAvailable: 1
expectedPods: 1
desiredHealthy: 1
disruptionsAllowed: 0
Drain timed out after repeated PDB violations.
The pod UID remained unchanged.
Relevant implementation findings
The Kubernetes driver creates an Agent Sandbox CR and default workspace PVC.
It watches Sandbox CRs and events but does not retain pod UID or node identity.
CLI and TUI primarily expose the normalized phase.
Kubernetes driver configuration does not expose lifecycle hooks or termination grace periods.
The supervisor handles SIGTERM by forwarding it to the entrypoint and waiting for it to exit.
There is currently no checkpoint protocol or checkpoint acknowledgement.
Acceptance Criteria
OpenShell distinguishes initial provisioning from disruption recovery.
Sandbox status exposes node and runtime-instance identity.
Eviction, replacement, scheduling failure, and recovery are visible through the API, CLI, TUI, logs, and metrics.
Problem Statement
Kubernetes sandbox pods can be evicted or terminated for several infrastructure reasons, including:
When this happens, OpenShell must determine:
OpenShell currently reduces these situations to broad lifecycle phases such as
Provisioning. It does not explain that the sandbox was evicted, identify the affected pod instance or node, show why recovery is blocked, or indicate whether durable state was restored.Node-Drain Experiment
To investigate this behavior, we deployed OpenShell into a two-worker kind cluster and created a sandbox through the OpenShell CLI. The gateway ran on one worker and the sandbox ran on the other.
We then drained the worker hosting the sandbox.
The experiment showed:
emptyDir.--delete-emptydir-data.local-pathPV was bound to the original node.Provisioningwhile recovery was blocked./sandboxsurvived./tmp, running processes, exec sessions, and connections did not survive.This experiment demonstrates one planned infrastructure disruption. The solution should also address unplanned disruptions, recognizing that checkpointing is only possible when OpenShell receives advance notice.
Proposed Design
1. Surface disruption and recovery
Add durable sandbox conditions such as:
Expose:
Update the API, CLI, JSON/YAML output, TUI, logs, and metrics to distinguish initial provisioning from recovery.
2. Protect planned evictions
Support an optional per-sandbox PodDisruptionBudget.
Testing confirmed that the following behavior blocks voluntary eviction:
Because a sandbox is a singleton, the replacement cannot be created until the original pod is deleted. The PDB must therefore be explicitly relaxed after checkpointing or by an operator.
A PDB protects against voluntary Eviction API operations. It cannot prevent direct pod deletion, sudden node failure, or drains that bypass eviction.
3. Checkpoint before planned eviction
For planned maintenance:
Checkpointing./sandbox.Example configuration concepts:
The checkpoint deadline should be shorter than the Kubernetes termination grace period, leaving time for process shutdown and supervisor cleanup.
Potential checkpoint failure policies include:
Block: retain eviction protection and require operator intervention.Proceed: allow eviction even if checkpointing fails.ProceedAfterTimeout: block initially and proceed when the deadline expires.Application-level checkpointing should be the initial scope. It can preserve:
/sandbox.Transparent restoration of process memory, sockets, exec sessions, and SSH sessions is out of scope.
A Kubernetes
preStophook or SIGTERM handler could provide a simpler best-effort checkpoint. However, eviction has already been accepted at that point and cannot be cancelled if checkpointing fails. See Kubernetes lifecycle hooks.For unplanned disruption, OpenShell should recover whatever is available from persistent storage and explicitly report that no checkpoint occurred.
4. Document storage durability requirements
Document that:
/sandboxPVC survives replacement of the pod while the Sandbox CR remains.local-pathstorage remains tied to its original node.emptyDir,/tmp, container-layer changes, and process state do not survive.Retainreclaim policies can protect storage after PVC or sandbox deletion.--delete-emptydir-datais required for the current sandbox pod layout during drain.Alternatives Considered
PodDisruptionBudget only
A PDB successfully blocks voluntary eviction, but it does not checkpoint state or provide availability. Because the sandbox is a singleton, the replacement cannot be created until the original pod is deleted.
Longer termination grace period only
This gives the supervisor more time to shut down, but eviction has already started. It cannot block deletion when checkpointing fails.
Pod finalizers
Finalizers can leave pod objects stuck in
Terminating, but they do not keep the workload usable if its node is unavailable. They are not suitable as an eviction-protection mechanism.Portable storage only
Portable storage allows the replacement to move to another node and preserves
/sandbox, but it does not preserve processes, connections, or active sessions.Full process checkpoint and restore
CRIU or runtime-level checkpointing could theoretically preserve process memory. Compatibility across kernels, container runtimes, namespaces, sockets, mounts, and security configurations makes this unsuitable for the initial design.
Agent Investigation
Environment
8c7dd148v0.0.90-67-g8c7dd148v0.5.0v1.31.0standardrancher.io/local-pathObserved identities
2e3ae382-2272-4229-90bc-c5a8bd60c017e81b7fb9-669b-4ae0-a56b-e4b39027174c45d3c0d0-3910-461f-a4c8-72fff452417b0d2b3a54-0936-485b-b027-afbb648973475ba67215-0d8f-462f-b3ed-d0440ed33beaReadyProvisioning, thenReadyState validation
/sandbox/pvc-marker: survived./tmp/ephemeral-marker: lost.Provisioningwhile Kubernetes showed a Pending replacement.PDB validation
minAvailable: 1expectedPods: 1desiredHealthy: 1disruptionsAllowed: 0Relevant implementation findings
Acceptance Criteria