Skip to main content

Running OpenClaw Sandbox

This example demonstrates how to deploy OpenClaw via OpenKruise Agents and initialize OpenClaw instances from a pre-warmed pool using the E2B SDK.

0. Basic Concepts​

OpenClaw​

OpenClaw is an open-source AI programming assistant gateway that provides unified LLM access, tool invocation, and code execution capabilities. By deploying OpenClaw through OpenKruise Agents, you can provide each user with an independent, data-persistent sandbox environment.

Data Persistence​

Unlike regular code execution sandboxes, OpenClaw needs to persist user configuration files and working data. This example uses volumeClaimTemplates to automatically create independent cloud disks for each Sandbox, ensuring data is not lost when a Sandbox is recreated.


1. Prerequisites​

1.1 Configuring Dynamic Storage​

OpenClaw requires persistent storage to save user configurations and data. First, create a StorageClass:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: openclaw-disk-sc
provisioner: ****
parameters:
type: *****
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true

Key Configuration Parameters:

ParameterDescription
provisionerCloud disk provider
volumeBindingMode: WaitForFirstConsumerDelayed binding - schedules Pod first, then creates disk based on availability zone
reclaimPolicy: RetainRetains PV and data when PVC is deleted; manual cleanup required

2. Deploying OpenClaw Pre-warmed Pool​

2.1 Deploying via SandboxSet​

Create a SandboxSet to deploy the OpenClaw pre-warmed pool:

apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
name: openclaw-sbs
namespace: default
spec:
replicas: 3
runtimes:
- name: agent-runtime
template:
metadata:
labels:
app: openclaw
spec:
automountServiceAccountToken: false
enableServiceLinks: false
hostNetwork: false
hostPID: false
hostIPC: false
shareProcessNamespace: false
hostname: openclaw
initContainers:
# Inject tini process manager
- name: tini-copy
image: krallin/ubuntu-tini:latest
command: ["sh", "-c"]
args:
- |
cp /usr/bin/tini /mnt/tini/tini
chmod +x /mnt/tini/tini
volumeMounts:
- name: tini-volume
mountPath: /mnt/tini
containers:
- name: gateway
image: ghcr.io/openclaw/openclaw:2026.3.28
securityContext:
readOnlyRootFilesystem: false
runAsUser: 1000
runAsGroup: 1000
command: ["/mnt/tini/tini", "--"]
args:
- bash
- -c
- |
exec node openclaw.mjs gateway run --allow-unconfigured
ports:
- name: gateway
containerPort: 18789
protocol: TCP
env:
- name: OPENCLAW_CONFIG_DIR
value: /home/node/.openclaw
- name: KUBERNETES_SERVICE_PORT_HTTPS
value: ""
- name: KUBERNETES_SERVICE_PORT
value: ""
- name: KUBERNETES_PORT_443_TCP
value: ""
- name: KUBERNETES_PORT_443_TCP_PROTO
value: ""
- name: KUBERNETES_PORT_443_TCP_ADDR
value: ""
- name: KUBERNETES_SERVICE_HOST
value: ""
- name: KUBERNETES_PORT
value: ""
- name: KUBERNETES_PORT_443_TCP_PORT
value: ""
volumeMounts:
- name: tini-volume
mountPath: /mnt/tini
- name: openclaw-dir
mountPath: /home/node/.openclaw
resources:
requests:
cpu: 2
memory: 4Gi
limits:
cpu: 2
memory: 4Gi
startupProbe:
exec:
command:
- node
- -e
- "require('http').get('http://127.0.0.1:18789/healthz', r => process.exit(r.statusCode < 400 ? 0 : 1)).on('error', () => process.exit(1))"
initialDelaySeconds: 2
periodSeconds: 2
failureThreshold: 150
volumes:
- name: tini-volume
emptyDir: { }
# Automatically create PVC for each Sandbox
volumeClaimTemplates:
- metadata:
name: openclaw-dir
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "openclaw-disk-sc"
resources:
requests:
storage: 20Gi

2.2 Verifying Deployment​

# Deploy SandboxSet
kubectl apply -f storageclass.yaml
kubectl apply -f sandboxset.yaml

# Check pre-warmed pool status
kubectl get sbs openclaw-sbs

# Expected output
NAME REPLICAS AVAILABLE UPDATEREVISION AGE
openclaw-sbs 3 3 xxxxxxxx 92s

# List available Sandboxes
kubectl get sbx -l agents.kruise.io/sandbox-pool=openclaw-sbs \
-l agents.kruise.io/sandbox-claimed=false

3. Requesting OpenClaw from Pre-warmed Pool via E2B SDK​

You can connect the native E2B Python SDK and JavaScript SDK to sandbox-manager through the following environment variables. In this section, we will use the Python SDK as an example.

3.1 Environment Setup​

# Install E2B SDK
pip install e2b-code-interpreter

# Configure environment variables
export E2B_DOMAIN=your.domain
export E2B_API_KEY=your-token
# If using self-signed certificates
export SSL_CERT_FILE=/path/to/ca-fullchain.pem

3.2 Creating a Sandbox and Configuring OpenClaw​

Create a configuration template openclaw-template.json:

{
"agents": {
"defaults": {
"model": {
"primary": "bailian/qwen3.5-plus"
},
"workspace": "/root/.openclaw/workspace"
}
},
"models": {
"mode": "merge",
"providers": {
"bailian": {
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"apiKey": "${DASHSCOPE_API_KEY}",
"api": "openai-completions",
"models": [
{
"id": "qwen3.5-plus",
"name": "qwen",
"input": ["text"],
"contextWindow": 1000000,
"maxTokens": 65536
}
]
}
}
},
"commands": {
"native": "auto",
"nativeSkills": "auto",
"restart": true,
"ownerDisplay": "raw"
},
"gateway": {
"port": 18789,
"bind": "lan",
"controlUi": {
"allowedOrigins": ["*"],
"dangerouslyAllowHostHeaderOriginFallback": true,
"allowInsecureAuth": true,
"dangerouslyDisableDeviceAuth": true
},
"auth": {
"mode": "token",
"token": "${GATEWAY_TOKEN}"
}
}
}

Python script create_sandbox.py:

import os
from string import Template
from e2b_code_interpreter import Sandbox

# Create Sandbox from pre-warmed pool (never-timeout keeps it running)
sbx = Sandbox.create(
template="openclaw-sbs",
metadata={"e2b.agents.kruise.io/never-timeout": "true"}
)
print(f"Sandbox ID: {sbx.sandbox_id}")

# Read environment variables
GATEWAY_TOKEN = os.environ.get("GATEWAY_TOKEN", "your-token")
DASHSCOPE_API_KEY = os.environ.get("DASHSCOPE_API_KEY", "sk-****")

# Render configuration template
with open("openclaw-template.json", "r") as f:
template_content = f.read()

rendered = Template(template_content).safe_substitute(
GATEWAY_TOKEN=GATEWAY_TOKEN,
DASHSCOPE_API_KEY=DASHSCOPE_API_KEY,
)

# Write configuration and trigger restart (using node user)
sbx.files.write("/home/node/.openclaw/openclaw.json", rendered, user="node")
print("Configuration written. OpenClaw will automatically restart to load the new configuration.")

Execute:

python create_sandbox.py

3.3 Retrieving Sandbox Information​

print(f"Sandbox ID: {sbx.sandbox_id}")
# Format: {Namespace}--{Sandbox Name}
# Example: default--openclaw-sbs-4p4h7

View details via kubectl:

kubectl describe sandbox openclaw-sbs-4p4h7 -n default

# View Pod IP
# Status:
# Pod Info:
# Pod IP: 10.10.24.10

4. Accessing OpenClaw UI​

4.1 Via E2B Native Interface​

URL format:

https://{port}-{sandbox-id}.{domain}/#token={token}

Example:

https://18789-default--openclaw-sbs-4p4h7.your.domain/#token=abc

4.2 Via kubectl port-forward (Quick Testing)​

kubectl port-forward openclaw-sbs-4p4h7 18789:18789 -n default

Then access in your local browser:

http://127.0.0.1:18789/#token=abc

5. Best Practices​

  1. Data Persistence: Use Retain reclaim policy to prevent accidental data deletion
  2. Access Control: Tighten allowedOrigins and authentication settings in production environments
  3. Resource Allocation: Adjust CPU/memory quotas based on actual workload requirements
  4. Image Versioning: Select OpenClaw image versions based on business needs; back up data before updating images
  5. Network Isolation: For production use, isolate OpenClaw from other workloads using vSwitch & NetworkPolicy