#OpenClaw#KubeSphere#Kubernetes#Docker#AIGateway#自托管
技术栈:OpenClaw v2026.3.8 / KubeSphere / Kubernetes / Ubuntu 22.04 / Alpine Linux / GLM (ZhipuAI) API
关键版本:alpine/openclaw:latest(OpenClaw v2026.3.8)/ 宿主机:Ubuntu 22.04,8核36G
核心文件:/home/node/.openclaw/openclaw.json
实际服务端口:18789(非官方常见文档所写的 3000)
系列:OpenClaw 云原生实战(一)
一、引言:痛点与破局(SCQA)
S(情境)在私有化 KubeSphere 集群上部署 OpenClaw 作为 AI 网关,用于调用 GLM 等第三方大模型 API,服务器为 Ubuntu 22.04,8核36G,纯 API 转发场景,不跑本地大模型。
C(冲突)部署过程一路坎坷:镜像选型无从下手;Pod 跑起来了,网页死活打不开;配置文件改错字段,程序直接报 Config invalid;端口填的是 3000,实际服务跑在 18789;好不容易通了,又撞上 origin not allowed 的 CORS 拦截,再通了又来一个 device identity required……每一关都让人头大。
Q(疑问)如何在 KubeSphere 上完整完成 OpenClaw 的部署、网络打通和模型接入,并且少踩那些"文档里没写"的坑?
A(解答)核心解法三件套:用 gateway.bind: "lan" 打开网络监听;用 gateway.controlUi.allowedOrigins 解除 CORS 拦截;用 auth.profiles + models.providers + agents.defaults 三段式结构完成模型接入。所有配置均通过宿主机 HostPath 挂载的 openclaw.json 持久化管理。
二、深度复盘:排错与思考路径
错误方向一:以为端口是 3000
最初按照通用 Web 服务的惯例,在 KubeSphere 中配置了容器端口 3000。结果网页一直打不开。
失败原因:alpine/openclaw 镜像实际网关监听的是 18789,只有通过实际读取容器日志才能发现:
1 2
[gateway] listening on ws://127.0.0.1:18789 (PID 14)[canvas] host mounted at http://127.0.0.1:18789/__openclaw__/canvas/
转折点:日志是最诚实的"说明书",Kubernetes 层没问题,问题出在应用本身的端口上。
错误方向二:以为 HOST=0.0.0.0 环境变量能生效
日志显示服务绑定在 127.0.0.1,于是在 KubeSphere 中注入 HOST=0.0.0.0 环境变量。结果日志仍然是 ws://127.0.0.1:18789——程序根本不认这个变量。
失败原因:OpenClaw 使用自己专属的配置体系,不读取通用的 HOST 环境变量。
错误方向三:在 openclaw.json 里写 "host": "0.0.0.0"
在配置文件的 gateway 块里加了 "host": "0.0.0.0",程序启动时直接报错:
1
Config invalid:gateway: Unrecognized key:"host"失败原因:OpenClaw 配置校验有严格的 JSON Schema,字段名必须精确。host 不是合法字段。
灵光一现的转折点:执行 openclaw gateway --help,看到官方文档:
1 2
--bind <mode> Bind mode ("loopback"|"lan"|"tailnet"|"auto"|"custom").Defaults to config gateway.bind (or loopback).
正确字段名是 bind,且值是枚举类型(lan 而非 IP 地址)。
错误方向四:以为打通 bind 就万事大吉
将 bind 改为 lan 后,服务监听在 0.0.0.0:18789,但浏览器访问时仍然报错:
1 2
origin not allowed (openthe Control UI fromthe gateway host orallow itin gateway.controlUi.allowedOrigins)
根本原因:OpenClaw 自 v2026.2.26 起新增了 CORS 白名单校验(issue #29385)。`bind=lan` 只解决"服务器监听谁",controlUi.allowedOrigins 解决的是"允许哪些浏览器来源连接",二者相互独立。
三、核心实操与代码沉淀
3.1 选择正确的镜像
在 Docker Hub 多个 OpenClaw 相关镜像中,综合更新频率、社区活跃度和体积:
首选: alpine/openclaw:latest— 基于 Alpine Linux,体积小、无冗余依赖,Stars 最多,更新最频繁,最适合 Kubernetes 环境。备选: 1panel/openclaw— 国内 1Panel 团队维护,适合偏好中文社区支持的场景。特殊场景: justlikemaki/openclaw-docker-cn-im— 已预集成微信/钉钉/飞书等国内 IM 接入,如需接入国内即时通讯平台可直接使用。
3.2 第一步:宿主机准备数据目录
1 2 3 4 5
# 创建 OpenClaw 数据目录mkdir -p /data/openclaw-data# 赋予容器写入权限(必须,否则容器内报 Permission denied)chmod -R 777 /data/openclaw-data
3.3 第二步:KubeSphere 工作负载完整 YAML
以下是完整且验证通过的 Deployment + Service 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
kind:DeploymentapiVersion:apps/v1metadata:name:openclaw-corenamespace:openclawspec:replicas:1selector:matchLabels:app:openclaw-coretemplate:metadata:labels:app:openclaw-corespec:volumes:-name:openclaw-datahostPath:# 宿主机物理路径,须与 mkdir 的路径完全一致path:/data/openclaw-datatype:''containers:-name:openclaw-containerimage:'alpine/openclaw:latest'imagePullPolicy:IfNotPresent# 优先使用本地镜像,避免版本漂移ports:-name:http-18789containerPort:18789# 实际端口是 18789,不是 3000protocol:TCPenv:-name:TZvalue:Asia/Shanghai# 时区:东八区-name:HOSTvalue:0.0.0.0# 注:HOST 环境变量对 OpenClaw 本身不生效(网关绑定地址由# openclaw.json 中的 gateway.bind 控制),此处保留无害-name:PATHvalue:>-/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/node/.openclaw/bin:/home/node/.openclaw/node_modules/.bin# 将持久化目录下的 bin 路径加入系统检索路径,# 使 uvx、mcporter 等安装在挂载目录的工具可直接调用resources:requests:cpu:100mmemory:512Milimits:cpu:'1'memory:1GivolumeMounts:-name:openclaw-datamountPath:/home/node/.openclaw# 容器内数据目录restartPolicy:AlwaysdnsPolicy:ClusterFirstsecurityContext: {} # 以默认用户(node)运行,不要加 runAsUser: 0# 若改为 root,需同步将 mountPath 改为 /root/.openclaw---kind:ServiceapiVersion:v1metadata:name:openclaw-svcnamespace:openclawspec:type:NodePortselector:app:openclaw-coreports:-name:http-18789protocol:TCPport:18789targetPort:18789nodePort:<NodePort># K8s 自动分配,或手动指定 30000-32767
⚠️ 关键注意:容器端口必须填
18789,而非3000。有 GPU 资源限制设置的务必清空,否则 Pod 一直Pending。
3.4 第三步:配置 openclaw.json 打通网络访问
OpenClaw 首次启动后会在挂载目录自动生成 openclaw.json,默认 gateway 配置只允许本机访问。在宿主机上直接编辑(修改永久生效,无需进入容器):
1
sudo nano /data/openclaw-data/openclaw.json找到 gateway 块,替换为如下完整结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
"gateway":{"port":18789,"mode":"local","bind":"lan","controlUi":{"enabled":true,"allowedOrigins":["http://<YOUR_NODE_IP>:<NodePort>","http://localhost:18789","http://127.0.0.1:18789"],"allowInsecureAuth":true,"dangerouslyDisableDeviceAuth":true},"auth":{"mode":"token","token":"<YOUR_GATEWAY_TOKEN>"},"tailscale":{"mode":"off","resetOnExit":false}}
四个关键字段说明:
gateway.mode: "local":必须显式声明,缺少此字段网关拒绝外部连接(最容易漏掉)。gateway.bind: "lan":从默认loopback(127.0.0.1)改为lan(0.0.0.0)。枚举值:loopback/lan/tailnet/auto/custom,不能直接填 IP。gateway.controlUi.allowedOrigins:CORS 白名单,必须含http://前缀,末尾不能有/。gateway.controlUi.dangerouslyDisableDeviceAuth: true:HTTP 非安全上下文下必须开启,否则报device identity required。
关于 Token:
auth.token建议写死固定值,否则每次 Pod 重启 OpenClaw 随机生成新 Token,反复出现gateway token mismatch。
1 2
# 修改完成后重启 Podkubectl rollout restart deployment openclaw-core -n openclaw
验证成功标志:
1 2
[gateway] listening on ws://0.0.0.0:18789 (PID 14)[canvas] host mounted at http://0.0.0.0:18789/__openclaw__/canvas/
3.5 第四步:接入第三方大模型(以智谱 GLM 为例)
适用版本:OpenClaw v2026.3.8
三段式结构
OpenClaw 的模型接入由三个相互绑定的节点共同完成:
auth.profiles | providermodels.providers 的 Key 完全一致 | |
models.providers | api: "openai-completions" | |
agents.defaults.model | "供应商ID/模型ID" |
关于 API Key:Key 不写在 openclaw.json 中,通过 Web 控制台 UI 填入后由系统安全存储(openclaw status 输出中显示为 __OPENCLAW_REDACTED__)。如需硬编码,在 models.providers.<name> 下加 "apiKey": "your_key" 字段。
实际运行的配置结构(v2026.3.8 验证)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
{"auth":{"profiles":{"zai:default":{"provider":"zai","mode":"api_key"}}},"models":{"mode":"merge","providers":{"zai":{"baseUrl":"https://open.bigmodel.cn/api/paas/v4","api":"openai-completions","models":[{"id":"glm-5-turbo","name":"GLM-5 Turbo","api":"openai-completions","reasoning":false,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":8192},{"id":"glm-5","name":"GLM-5","api":"openai-completions","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":204800,"maxTokens":131072}]}}},"agents":{"defaults":{"model":{"primary":"zai/glm-5-turbo","fallbacks":[]},"models":{"zai/glm-5-turbo":{"alias":"GLM-Turbo"}},"workspace":"/home/node/.openclaw/workspace","contextPruning":{"mode":"cache-ttl","ttl":"1h"},"compaction":{"mode":"safeguard"},"heartbeat":{"every":"30m"},"maxConcurrent":4,"subagents":{"maxConcurrent":8}}}}
baseUrl说明:智谱 AI 标准 OpenAI 兼容地址为https://open.bigmodel.cn/api/paas/v4。通过内网 API 网关(如 OneAPI/NewAPI)中转时,填写中转服务地址,协议类型保持openai-completions。
reasoning字段:false关闭深度推理,适合工具调用(Function Calling)场景——响应更快且不会污染 JSON 输出;true适合需要多步推理的复杂任务。主模型glm-5-turbo建议设为false。
3.6 完整生产级 openclaw.json 配置模板
以下是基于 OpenClaw v2026.3.8 实际运行验证的完整配置模板,脱敏后可直接对照使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
{"meta":{"lastTouchedVersion":"2026.3.8","lastTouchedAt":"<由系统自动更新>"},"auth":{"profiles":{"zai:default":{"provider":"zai","mode":"api_key"}}},"models":{"mode":"merge","providers":{"zai":{"baseUrl":"https://open.bigmodel.cn/api/paas/v4","api":"openai-completions","models":[{"id":"glm-5-turbo","name":"GLM-5 Turbo","api":"openai-completions","reasoning":false,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":131072,"maxTokens":8192},{"id":"glm-5","name":"GLM-5","api":"openai-completions","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":204800,"maxTokens":131072},{"id":"glm-4.7-flash","name":"GLM-4.7 Flash","api":"openai-completions","reasoning":true,"input":["text"],"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0},"contextWindow":204800,"maxTokens":131072}]}}},"agents":{"defaults":{"model":{"primary":"zai/glm-5-turbo","fallbacks":[]},"models":{"zai/glm-5-turbo":{"alias":"GLM-Turbo"}},"workspace":"/home/node/.openclaw/workspace","contextPruning":{"mode":"cache-ttl","ttl":"1h"},"compaction":{"mode":"safeguard"},"heartbeat":{"every":"30m"},"maxConcurrent":4,"subagents":{"maxConcurrent":8}}},"tools":{"profile":"coding","web":{"search":{"provider":"kimi"}}},"commands":{"native":"auto","nativeSkills":"auto","restart":true,"ownerDisplay":"raw"},"session":{"dmScope":"per-channel-peer"},"gateway":{"port":18789,"mode":"local","bind":"lan","controlUi":{"enabled":true,"allowedOrigins":["http://<YOUR_NODE_IP>:<NodePort>","http://localhost:18789","http://127.0.0.1:18789"],"allowInsecureAuth":true,"dangerouslyDisableDeviceAuth":true},"auth":{"mode":"token","token":"<YOUR_GATEWAY_TOKEN>"},"tailscale":{"mode":"off","resetOnExit":false}}}
四、容器化环境常见坑
4.1 提权为 root 后用户目录错位(配置静默失效)
现象:局域网访问在某次重启后突然变回 listening on ws://127.0.0.1:18789,日志显示 auth token was missing. Generated a new token,配置仿佛被完全重置。
根本原因:为安装插件在 YAML 中加了 runAsUser: 0 将容器用户提权为 root:
1 2
普通用户 node的家目录:/home/node/ → 挂载目录 /home/node/.openclaw(有配置)root 用户的家目录: /root/ → OpenClaw 去找 /root/.openclaw(空!)
解决方案(二选一):
方案 A(推荐):同步修改挂载路径:
1 2 3
volumeMounts:-name:openclaw-datamountPath:/root/.openclaw# 随 runAsUser 同步修改
方案 B:删除 securityContext.runAsUser: 0,恢复 node 用户身份,但需重新安装已装好的插件。
4.2 容器内无编辑器、restart 命令无效
误区 1:在容器终端里执行 openclaw gateway restart
1 2
Gateway service disabled. If you'rein a container,run the gateway in the foreground instead.
Kubernetes 容器里没有 systemd,应回到 KubeSphere 界面删除 Pod 让 Deployment 自动拉起,或执行:
1
kubectl rollout restart deployment openclaw-core -n openclaw误区 2:在容器终端里用 nano/vim 改配置
镜像删除了所有文本编辑器,且容器内改动在 Pod 重启后消失。始终在宿主机上修改:
1
sudo nano /data/openclaw-data/openclaw.json4.3 进入容器终端的一键命令
1 2 3
kubectl exec -it \$(kubectl get pods -n openclaw -l app=openclaw-core -o jsonpath='{.items[0].metadata.name}') \-n openclaw -- /bin/sh
五、避坑速查清单
基础部署层
容器端口填 18789,不是3000(以日志为准)GPU 资源设置留空,否则 Pod 永远 PendingHostPath 多节点集群必须配 nodeSelector,防止 Pod 漂移"AI 失忆"
网络与访问层
gateway.bind值为枚举字符串"lan",不是 IP"0.0.0.0"gateway.mode: "local"不能遗漏controlUi.allowedOrigins每条 URL 必须带http://,末尾不能有/HTTP 环境必须同时设置 allowInsecureAuth: true+dangerouslyDisableDeviceAuth: truegateway.auth.token建议写死固定值,避免重启后token mismatch
配置文件操作层
OpenClaw JSON Schema 校验零容错: bind不是host,plugins.entries不是plugins.allow出现 Config invalid时不要运行openclaw doctor --fix
容器持久化层
修改 runAsUser时必须同步修改mountPath修改配置文件始终在宿主机上操作
模型接入层
三段式结构缺一不可: auth.profiles+models.providers+agents.defaults.modelagents.defaults.model.primary格式为"供应商ID/模型ID"工具调用场景将 reasoning设为false
六、总结
这次部署涉及三个层次,解法各不相同:
Kubernetes 基础设施层(端口、存储、资源):KubeSphere 图形界面可以完成大部分操作,但 YAML 直接编辑更可靠。 应用配置层(bind、CORS、模型接入):OpenClaw JSON Schema 校验严格,字段名容错率为零。任何字段疑问,优先查 openclaw --help和openclaw gateway --help。HostPath 的核心价值:提前挂载数据目录是贯穿整个排坑过程的关键决策。 openclaw.json映射到宿主机后,所有配置修改都不需要进入容器,大幅降低了排查成本。
AI 辅助开发经验:AI 建议并非每次都直接命中(例如 "host" 字段建议是错的),但能根据错误日志迅速调整方向。把错误日志和 --help 输出完整提供给 AI,是最高效的协作方式。
部署时间:2026-03-12 | 环境:Ubuntu 22.04 / KubeSphere / alpine/openclaw:latest (v2026.3.8)
夜雨聆风