乐于分享
好东西不私藏

OpenClaw + KubeSphere 部署手册:从镜像选型到模型接入

OpenClaw + KubeSphere 部署手册:从镜像选型到模型接入
核心标签:

#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}}

四个关键字段说明

  1. gateway.mode: "local":必须显式声明,缺少此字段网关拒绝外部连接(最容易漏掉)。
  2. gateway.bind: "lan":从默认 loopback(127.0.0.1)改为 lan(0.0.0.0)。枚举值:loopback / lan / tailnet / auto / custom,不能直接填 IP。
  3. gateway.controlUi.allowedOrigins:CORS 白名单,必须含 http:// 前缀,末尾不能有 /
  4. gateway.controlUi.dangerouslyDisableDeviceAuth: true:HTTP 非安全上下文下必须开启,否则报 device identity required

关于 Tokenauth.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
声明使用哪个供应商的凭证
provider
 名必须与 models.providers 的 Key 完全一致
models.providers
声明可用模型列表及接口地址
api: "openai-completions"
 兼容所有 OpenAI 格式接口
agents.defaults.model
将具体模型指派给 Agent
格式固定为 "供应商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.json

4.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 永远 Pending
  • HostPath 多节点集群必须配 nodeSelector,防止 Pod 漂移"AI 失忆"

网络与访问层

  • gateway.bind 值为枚举字符串 "lan",不是 IP "0.0.0.0"
  • gateway.mode: "local" 不能遗漏
  • controlUi.allowedOrigins 每条 URL 必须带 http://,末尾不能有 /
  • HTTP 环境必须同时设置 allowInsecureAuth: true + dangerouslyDisableDeviceAuth: true
  • gateway.auth.token 建议写死固定值,避免重启后 token mismatch

配置文件操作层

  • OpenClaw JSON Schema 校验零容错:bind 不是 hostplugins.entries 不是 plugins.allow
  • 出现 Config invalid 时不要运行openclaw doctor --fix

容器持久化层

  • 修改 runAsUser 时必须同步修改 mountPath
  • 修改配置文件始终在宿主机上操作

模型接入层

  • 三段式结构缺一不可:auth.profiles + models.providers + agents.defaults.model
  • agents.defaults.model.primary 格式为 "供应商ID/模型ID"
  • 工具调用场景将 reasoning 设为 false

六、总结

这次部署涉及三个层次,解法各不相同:

  1. Kubernetes 基础设施层(端口、存储、资源):KubeSphere 图形界面可以完成大部分操作,但 YAML 直接编辑更可靠。
  2. 应用配置层(bind、CORS、模型接入):OpenClaw JSON Schema 校验严格,字段名容错率为零。任何字段疑问,优先查 openclaw --help 和 openclaw gateway --help
  3. HostPath 的核心价值:提前挂载数据目录是贯穿整个排坑过程的关键决策。openclaw.json 映射到宿主机后,所有配置修改都不需要进入容器,大幅降低了排查成本。

AI 辅助开发经验:AI 建议并非每次都直接命中(例如 "host" 字段建议是错的),但能根据错误日志迅速调整方向。把错误日志和 --help 输出完整提供给 AI,是最高效的协作方式。


部署时间:2026-03-12 | 环境:Ubuntu 22.04 / KubeSphere / alpine/openclaw:latest (v2026.3.8)