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
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:
209
scripts/k8s/create-kind.sh
Executable file
209
scripts/k8s/create-kind.sh
Executable 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
231
scripts/k8s/deploy.sh
Executable 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"
|
||||
40
scripts/k8s/manifests/configmap.yaml
Normal file
40
scripts/k8s/manifests/configmap.yaml
Normal 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.
|
||||
146
scripts/k8s/manifests/deployment.yaml
Normal file
146
scripts/k8s/manifests/deployment.yaml
Normal 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: {}
|
||||
7
scripts/k8s/manifests/kustomization.yaml
Normal file
7
scripts/k8s/manifests/kustomization.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- pvc.yaml
|
||||
- configmap.yaml
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
12
scripts/k8s/manifests/pvc.yaml
Normal file
12
scripts/k8s/manifests/pvc.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: openclaw-home-pvc
|
||||
labels:
|
||||
app: openclaw
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
15
scripts/k8s/manifests/service.yaml
Normal file
15
scripts/k8s/manifests/service.yaml
Normal 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
|
||||
Reference in New Issue
Block a user