Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled

Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
2026-07-05 09:36:54 +00:00
parent 3216769225
commit bedb527145
21108 changed files with 6010766 additions and 0 deletions

209
scripts/k8s/create-kind.sh Executable file
View File

@@ -0,0 +1,209 @@
#!/usr/bin/env bash
# ============================================================================
# KIND CLUSTER BOOTSTRAP SCRIPT
# ============================================================================
#
# Usage:
# ./scripts/k8s/create-kind.sh # Create with auto-detected engine
# ./scripts/k8s/create-kind.sh --name mycluster
# ./scripts/k8s/create-kind.sh --delete
#
# After creation, deploy with:
# export <AI_PROVIDER>_API_KEY="..." && ./scripts/k8s/deploy.sh
# ============================================================================
set -euo pipefail
# Defaults
CLUSTER_NAME="openclaw"
CONTAINER_CMD=""
DELETE=false
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
NC='\033[0m'
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
fail() { echo -e "${RED}[ERROR]${NC} $1" >&2; exit 1; }
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Options:
--name NAME Cluster name (default: openclaw)
--delete Delete the cluster instead of creating it
-h, --help Show this help message
Examples:
$(basename "$0") # Create cluster (auto-detect engine)
$(basename "$0") --delete # Delete the cluster
$(basename "$0") --name dev --delete # Delete a cluster named "dev"
EOF
exit 0
}
# ---------------------------------------------------------------------------
# Argument parsing
# ---------------------------------------------------------------------------
while [[ $# -gt 0 ]]; do
case "$1" in
--name)
[[ -z "${2:-}" ]] && fail "--name requires a value"
CLUSTER_NAME="$2"; shift 2 ;;
--delete)
DELETE=true; shift ;;
-h|--help)
usage ;;
*)
fail "Unknown option: $1 (see --help)" ;;
esac
done
# ---------------------------------------------------------------------------
# Container engine detection
# ---------------------------------------------------------------------------
provider_installed() {
command -v "$1" &>/dev/null
}
provider_responsive() {
case "$1" in
docker)
docker info &>/dev/null
;;
podman)
podman info &>/dev/null
;;
*)
return 1
;;
esac
}
detect_provider() {
local candidate
for candidate in podman docker; do
if provider_installed "$candidate" && provider_responsive "$candidate"; then
echo "$candidate"
return 0
fi
done
for candidate in podman docker; do
if provider_installed "$candidate"; then
case "$candidate" in
podman)
fail "Podman is installed but not responding, and no responsive Docker daemon was found. Ensure the podman machine is running (podman machine start) or start Docker."
;;
docker)
fail "Docker is installed but not running, and no responsive Podman machine was found. Start Docker or start Podman."
;;
esac
fi
done
fail "Neither podman nor docker found. Install one to use Kind."
}
CONTAINER_CMD=$(detect_provider)
info "Auto-detected container engine: $CONTAINER_CMD"
# ---------------------------------------------------------------------------
# Prerequisites
# ---------------------------------------------------------------------------
if ! command -v kind &>/dev/null; then
fail "kind is not installed. Install it from https://kind.sigs.k8s.io/"
fi
if ! command -v kubectl &>/dev/null; then
fail "kubectl is not installed. Install it before creating or managing a Kind cluster."
fi
# Verify the container engine is responsive
if ! provider_responsive "$CONTAINER_CMD"; then
if [[ "$CONTAINER_CMD" == "docker" ]]; then
fail "Docker daemon is not running. Start it and try again."
elif [[ "$CONTAINER_CMD" == "podman" ]]; then
fail "Podman is not responding. Ensure the podman machine is running (podman machine start)."
fi
fi
# ---------------------------------------------------------------------------
# Delete mode
# ---------------------------------------------------------------------------
if $DELETE; then
info "Deleting Kind cluster '$CLUSTER_NAME'..."
if KIND_EXPERIMENTAL_PROVIDER="$CONTAINER_CMD" kind get clusters 2>/dev/null | grep -qx "$CLUSTER_NAME"; then
KIND_EXPERIMENTAL_PROVIDER="$CONTAINER_CMD" kind delete cluster --name "$CLUSTER_NAME"
success "Cluster '$CLUSTER_NAME' deleted."
else
warn "Cluster '$CLUSTER_NAME' does not exist."
fi
exit 0
fi
# ---------------------------------------------------------------------------
# Check if cluster already exists
# ---------------------------------------------------------------------------
if KIND_EXPERIMENTAL_PROVIDER="$CONTAINER_CMD" kind get clusters 2>/dev/null | grep -qx "$CLUSTER_NAME"; then
warn "Cluster '$CLUSTER_NAME' already exists."
info "To recreate it, run: $0 --name \"$CLUSTER_NAME\" --delete && $0 --name \"$CLUSTER_NAME\""
info "Switching kubectl context to kind-$CLUSTER_NAME..."
kubectl config use-context "kind-$CLUSTER_NAME" &>/dev/null && success "Context set." || warn "Could not switch context."
exit 0
fi
# ---------------------------------------------------------------------------
# Create cluster
# ---------------------------------------------------------------------------
info "Creating Kind cluster '$CLUSTER_NAME' (provider: $CONTAINER_CMD)..."
KIND_EXPERIMENTAL_PROVIDER="$CONTAINER_CMD" kind create cluster \
--name "$CLUSTER_NAME" \
--config - <<'KINDCFG'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
labels:
openclaw.dev/role: control-plane
# Uncomment to expose services on host ports:
# extraPortMappings:
# - containerPort: 30080
# hostPort: 8080
# protocol: TCP
# - containerPort: 30443
# hostPort: 8443
# protocol: TCP
KINDCFG
success "Kind cluster '$CLUSTER_NAME' created."
# ---------------------------------------------------------------------------
# Wait for readiness
# ---------------------------------------------------------------------------
info "Waiting for cluster to be ready..."
kubectl --context "kind-$CLUSTER_NAME" wait --for=condition=Ready nodes --all --timeout=120s >/dev/null
success "All nodes are Ready."
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
echo ""
echo "---------------------------------------------------------------"
echo " Kind cluster '$CLUSTER_NAME' is ready"
echo "---------------------------------------------------------------"
echo ""
echo " kubectl cluster-info --context kind-$CLUSTER_NAME"
echo ""
echo ""
echo " export <AI_PROVIDER>_API_KEY=\"...\" && ./scripts/k8s/deploy.sh"
echo ""

231
scripts/k8s/deploy.sh Executable file
View File

@@ -0,0 +1,231 @@
#!/usr/bin/env bash
# Deploy OpenClaw to Kubernetes.
#
# Secrets are generated in a temp directory and applied server-side.
# No secret material is ever written to the repo checkout.
#
# Usage:
# ./scripts/k8s/deploy.sh # Deploy (requires API key in env or secret already in cluster)
# ./scripts/k8s/deploy.sh --create-secret # Create or update the K8s Secret from env vars
# ./scripts/k8s/deploy.sh --show-token # Print the gateway token after deploy
# ./scripts/k8s/deploy.sh --delete # Tear down
#
# Environment:
# OPENCLAW_NAMESPACE Kubernetes namespace (default: openclaw)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MANIFESTS="$SCRIPT_DIR/manifests"
NS="${OPENCLAW_NAMESPACE:-openclaw}"
# Check prerequisites
for cmd in kubectl openssl; do
command -v "$cmd" &>/dev/null || { echo "Missing: $cmd" >&2; exit 1; }
done
kubectl cluster-info &>/dev/null || { echo "Cannot connect to cluster. Check kubeconfig." >&2; exit 1; }
# ---------------------------------------------------------------------------
# -h / --help
# ---------------------------------------------------------------------------
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
cat <<'HELP'
Usage: ./scripts/k8s/deploy.sh [OPTION]
(no args) Deploy OpenClaw (creates secret from env if needed)
--create-secret Create or update the K8s Secret from env vars without deploying
--show-token Print the gateway token after deploy or secret creation
--delete Delete the namespace and all resources
-h, --help Show this help
Environment:
Export at least one provider API key:
ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY
OPENCLAW_NAMESPACE Kubernetes namespace (default: openclaw)
HELP
exit 0
fi
SHOW_TOKEN=false
MODE="deploy"
while [[ $# -gt 0 ]]; do
case "$1" in
--create-secret)
MODE="create-secret"
;;
--delete)
MODE="delete"
;;
--show-token)
SHOW_TOKEN=true
;;
*)
echo "Unknown option: $1" >&2
echo "Run ./scripts/k8s/deploy.sh --help for usage." >&2
exit 1
;;
esac
shift
done
# ---------------------------------------------------------------------------
# --delete
# ---------------------------------------------------------------------------
if [[ "$MODE" == "delete" ]]; then
echo "Deleting namespace '$NS' and all resources..."
kubectl delete namespace "$NS" --ignore-not-found
echo "Done."
exit 0
fi
# ---------------------------------------------------------------------------
# Create and apply Secret to the cluster
# ---------------------------------------------------------------------------
_apply_secret() {
local TMP_DIR
local EXISTING_SECRET=false
local EXISTING_TOKEN=""
local ANTHROPIC_VALUE=""
local OPENAI_VALUE=""
local GEMINI_VALUE=""
local OPENROUTER_VALUE=""
local TOKEN
local SECRET_MANIFEST
TMP_DIR="$(mktemp -d)"
chmod 700 "$TMP_DIR"
trap 'rm -rf "$TMP_DIR"' EXIT
if kubectl get secret openclaw-secrets -n "$NS" &>/dev/null; then
EXISTING_SECRET=true
EXISTING_TOKEN="$(kubectl get secret openclaw-secrets -n "$NS" -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d)"
ANTHROPIC_VALUE="$(kubectl get secret openclaw-secrets -n "$NS" -o jsonpath='{.data.ANTHROPIC_API_KEY}' 2>/dev/null | base64 -d)"
OPENAI_VALUE="$(kubectl get secret openclaw-secrets -n "$NS" -o jsonpath='{.data.OPENAI_API_KEY}' 2>/dev/null | base64 -d)"
GEMINI_VALUE="$(kubectl get secret openclaw-secrets -n "$NS" -o jsonpath='{.data.GEMINI_API_KEY}' 2>/dev/null | base64 -d)"
OPENROUTER_VALUE="$(kubectl get secret openclaw-secrets -n "$NS" -o jsonpath='{.data.OPENROUTER_API_KEY}' 2>/dev/null | base64 -d)"
fi
TOKEN="${EXISTING_TOKEN:-$(openssl rand -hex 32)}"
ANTHROPIC_VALUE="${ANTHROPIC_API_KEY:-$ANTHROPIC_VALUE}"
OPENAI_VALUE="${OPENAI_API_KEY:-$OPENAI_VALUE}"
GEMINI_VALUE="${GEMINI_API_KEY:-$GEMINI_VALUE}"
OPENROUTER_VALUE="${OPENROUTER_API_KEY:-$OPENROUTER_VALUE}"
SECRET_MANIFEST="$TMP_DIR/secrets.yaml"
# Write secret material to temp files so kubectl handles encoding safely.
printf '%s' "$TOKEN" > "$TMP_DIR/OPENCLAW_GATEWAY_TOKEN"
printf '%s' "$ANTHROPIC_VALUE" > "$TMP_DIR/ANTHROPIC_API_KEY"
printf '%s' "$OPENAI_VALUE" > "$TMP_DIR/OPENAI_API_KEY"
printf '%s' "$GEMINI_VALUE" > "$TMP_DIR/GEMINI_API_KEY"
printf '%s' "$OPENROUTER_VALUE" > "$TMP_DIR/OPENROUTER_API_KEY"
chmod 600 \
"$TMP_DIR/OPENCLAW_GATEWAY_TOKEN" \
"$TMP_DIR/ANTHROPIC_API_KEY" \
"$TMP_DIR/OPENAI_API_KEY" \
"$TMP_DIR/GEMINI_API_KEY" \
"$TMP_DIR/OPENROUTER_API_KEY"
kubectl create secret generic openclaw-secrets \
-n "$NS" \
--from-file=OPENCLAW_GATEWAY_TOKEN="$TMP_DIR/OPENCLAW_GATEWAY_TOKEN" \
--from-file=ANTHROPIC_API_KEY="$TMP_DIR/ANTHROPIC_API_KEY" \
--from-file=OPENAI_API_KEY="$TMP_DIR/OPENAI_API_KEY" \
--from-file=GEMINI_API_KEY="$TMP_DIR/GEMINI_API_KEY" \
--from-file=OPENROUTER_API_KEY="$TMP_DIR/OPENROUTER_API_KEY" \
--dry-run=client \
-o yaml > "$SECRET_MANIFEST"
chmod 600 "$SECRET_MANIFEST"
kubectl create namespace "$NS" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
kubectl apply --server-side --field-manager=openclaw -f "$SECRET_MANIFEST" >/dev/null
# Clean up any annotation left by older client-side apply runs.
kubectl annotate secret openclaw-secrets -n "$NS" kubectl.kubernetes.io/last-applied-configuration- >/dev/null 2>&1 || true
rm -rf "$TMP_DIR"
trap - EXIT
if $EXISTING_SECRET; then
echo "Secret updated in namespace '$NS'. Existing gateway token preserved."
else
echo "Secret created in namespace '$NS'."
fi
if $SHOW_TOKEN; then
echo "Gateway token: $TOKEN"
else
echo "Gateway token stored in Secret only."
echo "Retrieve it with:"
echo " kubectl get secret openclaw-secrets -n $NS -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d && echo"
fi
}
# ---------------------------------------------------------------------------
# --create-secret
# ---------------------------------------------------------------------------
if [[ "$MODE" == "create-secret" ]]; then
HAS_KEY=false
for key in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENROUTER_API_KEY; do
if [[ -n "${!key:-}" ]]; then
HAS_KEY=true
echo " Found $key in environment"
fi
done
if ! $HAS_KEY; then
echo "No API keys found in environment. Export at least one and re-run:"
echo " export <PROVIDER>_API_KEY=\"...\" (ANTHROPIC, GEMINI, OPENAI, or OPENROUTER)"
echo " ./scripts/k8s/deploy.sh --create-secret"
exit 1
fi
_apply_secret
echo ""
echo "Now run:"
echo " ./scripts/k8s/deploy.sh"
exit 0
fi
# ---------------------------------------------------------------------------
# Check that the secret exists in the cluster
# ---------------------------------------------------------------------------
if ! kubectl get secret openclaw-secrets -n "$NS" &>/dev/null; then
HAS_KEY=false
for key in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENROUTER_API_KEY; do
[[ -n "${!key:-}" ]] && HAS_KEY=true
done
if $HAS_KEY; then
echo "Creating secret from environment..."
_apply_secret
echo ""
else
echo "No secret found and no API keys in environment."
echo ""
echo "Export at least one provider API key and re-run:"
echo " export <PROVIDER>_API_KEY=\"...\" (ANTHROPIC, GEMINI, OPENAI, or OPENROUTER)"
echo " ./scripts/k8s/deploy.sh"
exit 1
fi
fi
# ---------------------------------------------------------------------------
# Deploy
# ---------------------------------------------------------------------------
echo "Deploying to namespace '$NS'..."
kubectl create namespace "$NS" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
kubectl apply -k "$MANIFESTS" -n "$NS"
kubectl rollout restart deployment/openclaw -n "$NS" 2>/dev/null || true
echo ""
echo "Waiting for rollout..."
kubectl rollout status deployment/openclaw -n "$NS" --timeout=300s
echo ""
echo "Done. Access the gateway:"
echo " kubectl port-forward svc/openclaw 18789:18789 -n $NS"
echo " open http://localhost:18789"
echo ""
if $SHOW_TOKEN; then
echo "Gateway token (paste into Control UI):"
echo " $(kubectl get secret openclaw-secrets -n "$NS" -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d)"
echo ""
fi
echo "Retrieve the gateway token with:"
echo " kubectl get secret openclaw-secrets -n $NS -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d && echo"

View File

@@ -0,0 +1,40 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: openclaw-config
labels:
app: openclaw
data:
openclaw.json: |
{
"gateway": {
"mode": "local",
"bind": "loopback",
"port": 18789,
"auth": {
"mode": "token"
},
"controlUi": {
"enabled": true
}
},
"agents": {
"defaults": {
"workspace": "~/.openclaw/workspace"
},
"list": [
{
"id": "default",
"name": "OpenClaw Assistant",
"workspace": "~/.openclaw/workspace"
}
]
},
"cron": { "enabled": false }
}
AGENTS.md: |
# OpenClaw Assistant
You are a helpful AI assistant running in Kubernetes.
Before proposing or building a custom system, feature, workflow, tool, integration, or automation, do a brief check for open-source projects, maintained libraries, existing OpenClaw plugins, or free platforms that already solve it well enough. Prefer those when adequate. Build custom only when existing options are unsuitable, too expensive, unmaintained, unsafe, non-compliant, or the user explicitly asks for custom. Avoid paid-service recommendations unless the user explicitly approves spend. Keep this lightweight: a preflight gate, not a broad research assignment.

View File

@@ -0,0 +1,146 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: openclaw
labels:
app: openclaw
spec:
replicas: 1
selector:
matchLabels:
app: openclaw
strategy:
type: Recreate
template:
metadata:
labels:
app: openclaw
spec:
automountServiceAccountToken: false
securityContext:
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
initContainers:
- name: init-config
image: busybox:1.37
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- |
cp /config/openclaw.json /home/node/.openclaw/openclaw.json
mkdir -p /home/node/.openclaw/workspace
cp /config/AGENTS.md /home/node/.openclaw/workspace/AGENTS.md
securityContext:
runAsUser: 1000
runAsGroup: 1000
resources:
requests:
memory: 32Mi
cpu: 50m
limits:
memory: 64Mi
cpu: 100m
volumeMounts:
- name: openclaw-home
mountPath: /home/node/.openclaw
- name: config
mountPath: /config
containers:
- name: gateway
image: ghcr.io/openclaw/openclaw:slim
imagePullPolicy: IfNotPresent
command:
- node
- /app/dist/index.js
- gateway
- run
ports:
- name: gateway
containerPort: 18789
protocol: TCP
env:
- name: HOME
value: /home/node
- name: OPENCLAW_CONFIG_DIR
value: /home/node/.openclaw
- name: NODE_ENV
value: production
- name: OPENCLAW_GATEWAY_TOKEN
valueFrom:
secretKeyRef:
name: openclaw-secrets
key: OPENCLAW_GATEWAY_TOKEN
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: openclaw-secrets
key: ANTHROPIC_API_KEY
optional: true
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openclaw-secrets
key: OPENAI_API_KEY
optional: true
- name: GEMINI_API_KEY
valueFrom:
secretKeyRef:
name: openclaw-secrets
key: GEMINI_API_KEY
optional: true
- name: OPENROUTER_API_KEY
valueFrom:
secretKeyRef:
name: openclaw-secrets
key: OPENROUTER_API_KEY
optional: true
resources:
requests:
memory: 512Mi
cpu: 250m
limits:
memory: 2Gi
cpu: "1"
livenessProbe:
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: 60
periodSeconds: 30
timeoutSeconds: 10
readinessProbe:
exec:
command:
- node
- -e
- "require('http').get('http://127.0.0.1:18789/readyz', r => process.exit(r.statusCode < 400 ? 0 : 1)).on('error', () => process.exit(1))"
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 5
volumeMounts:
- name: openclaw-home
mountPath: /home/node/.openclaw
- name: tmp-volume
mountPath: /tmp
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumes:
- name: openclaw-home
persistentVolumeClaim:
claimName: openclaw-home-pvc
- name: config
configMap:
name: openclaw-config
- name: tmp-volume
emptyDir: {}

View File

@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pvc.yaml
- configmap.yaml
- deployment.yaml
- service.yaml

View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: openclaw-home-pvc
labels:
app: openclaw
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: openclaw
labels:
app: openclaw
spec:
type: ClusterIP
selector:
app: openclaw
ports:
- name: gateway
port: 18789
targetPort: 18789
protocol: TCP