本地部署方式
后面详细了解了下,这个功能其实就是一个npm包,不用买单独的云服务器。作为程序员,可以用的服务器可是有一堆,或者自己开个虚拟机在上面安装就行了。

官网地址: https://github.com/openclaw/openclaw

1.安装npm(第一种安装方式)
首先你得安装22.0以上版本的npm,此版本的npm不支持在类似centos7的低版本系统中运行。

例如,以下我是在centos8系统安装的。

# centos8、ubuntu22等系统用高版本的

# centos8、ubuntu22等系统用高版本的
wget https://nodejs.org/dist/v24.13.0/node-v24.13.0-linux-x64.tar.xz
# 解压缩
tar -xf node-v24.13.0-linux-x64.tar.xz
# 把这个解压缩的文件放到用户目录/usr/local
mv node-v24.13.0-linux-x64 /usr/local/node
# 配置软连接方便进行全局调用
sudo ln -s /usr/local/node/bin/node /usr/bin/node
sudo ln -s /usr/local/node/bin/npm /usr/bin/npm


2.安装openclaw

# 执行安装
npm install -g openclaw@latest
# 配置软连接
sudo ln -s /usr/local/node/bin/openclaw /usr/bin/openclaw
# 查看是否安装成功
openclaw --help


出现以下类似界面说明安装成功


我竟然安装失败了。可能因为网络原因吧。

2.使用脚本安装(第2种安装方式)

curl -fsSL https://openclaw.ai/install.sh | bash

这种安装方式还是有可能失败,解决方案如下:

###这样会输出安装的所有日志,方便查看到底哪里报错
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh \
  | CLAWDBOT_NPM_LOGLEVEL=verbose bash -s -- --verbose



###可以将报错信息丢给大模型去分析

常见原因:Git Key 问题(高频)
典型特征:
日志中出现:

git@github.com
Permission denied (publickey)
npm ERR! code 128
根本原因:
npm 表面失败,但根因在 git clone 私有仓库
Git SSH Key 没配置 / 配错了
四、解决步骤
1. 检查 SSH Key 配置
# 查看现有 SSH Key
ls -la ~/.ssh

# 测试 GitHub 连接
ssh -T git@github.com

2. 生成或配置 SSH Key
如果没有 SSH Key:

# 生成新的 SSH Key
ssh-keygen -t ed25519 -C "your_email@example.com"

# 将公钥添加到 GitHub
cat ~/.ssh/id_ed25519.pub


3. 将公钥添加到 GitHub
复制公钥内容
登录 GitHub → Settings → SSH and GPG keys → New SSH key
粘贴公钥并保存


五、其他常见问题
1. 网络问题
# 配置 npm 镜像(如果在中国大陆)
npm config set registry https://registry.npmmirror.com

2. Node 版本不兼容
# 检查 Node 版本
node -v

# 推荐使用 nvm 管理 Node 版本
nvm install 24
nvm use 24

出现下面安装


3.运行指引并安装守护进程
(1)手动配置
OpenClaw与常见的应用模板不同,官方提供了若干需用户自行手动配置的步骤,在首次登入服务器后,输入并回车运行如下命令开始配置:

openclaw onboard --install-daemon

运行上面的命令后,出现同意免责声明,将会出现一个问题:是否知晓风险,选择Yes就行。


(2)配置模式选择:快速入门
接下来需要选择Onboarding的模式。

第一个是快速启动,后续通过 openclaw configure 配置信息。

第二个是先手动配置。

我们选择QuickStart。

(3)模型配置
然后它会让你配置AI大模型。

你有什么就选什么吧,网上说智谱的GLM4.7比较好用,但是这个太火爆了,买不到。我自己目前用的是阿里的Qwen。【这不不想配置,可以直接跳过】

(4)选择频道
配置好模型后,会让你选择聊天频道。

这些全是海外的,我们用不了。

选择最后一个,直接跳过。

(5)配置Skills
然后会问你要不要配置技能。选YES

依赖Homebrew也选Yes装上。

然后会让你选择用什么管理器安装。

一般用npm,前面也安装过了。

再然后,会给你一堆Skills:


直接跳过吧,后续跟它对话也能装。

(6)配置Hooks
继续下一步,会问你要不要配置hooks。

可以理解为三个插件:

boot-md:启动时自动加载一段markdown文本当默认引导内容。常用于把你的规则、偏好、项目背景在每次启动时塞进去。

command-logger:把你在Clawdbot里执行过的命令和关键操作记一份日志,方便排查问题和复盘。如果你比较在意隐私或不想留痕,就别开它。

session-memory:保存会话相关的状态或记忆,让它下次能延续上下文,体验会更连贯。

建议都开,都非常实用。

(7)选择交互方式
它问你想要用什么方式孵化你的机器人?

命令行方式(推荐)
web界面方式
稍后选择

肯定有图形化界面最好了!这个新手选web界面方式吧。除非你是老手,只想用命令行界面方式交互。

4.配置web界面
这时候如果是用ubuntu系统安装的,不一定能打开网页界面。它只能本地http://127.0.0.1:18789进行访问,所以现在我们改下

(1)配置远程访问
首先防火墙放行端口

# 放行TCP端口
sudo ufw allow 18789/tcp
# 查看规则
sudo ufw status numbered

然后修改~/.openclaw/openclaw.json配置文件

vi openclaw.json
把bind的配置改为lan

  "gateway": {
    "mode": "local",
    "auth": {
      "mode": "token",
      "token": "***********"
    },
    "port": 18789,
    "bind": "loopback",  // 改为lan
    "tailscale": {
      "mode": "off",
      "resetOnExit": false
    }
  },


保存退出后重启应用

openclaw gateway restart

现在就能在浏览器通过http://你的IP:18789进行访问了。

(2)解决报错
这里发现报错了,openclaw提示 disconnected (1008): control ui requires HTTPS or localhost (secure context)所以什么都操作不了。

继续编辑配置,修改~/.openclaw/openclaw.json配置文件

 "gateway": {
    "port": 18789,
    "mode": "local",
    "bind": "lan",
    // 加入下面这行配置
    "controlUi": {
      "allowInsecureAuth": true
    },
    "auth": {
      "mode": "token",
      "token": "*************************************"
    },
    "tailscale": {
      "mode": "off",
      "resetOnExit": false
    },
    "http": {
      "endpoints": {
        "responses": {
          "enabled": true
        }
      }
    }
  }

然后重启应用

openclaw gateway restart

现在就不报错,能正常访问了。

(3)修改模型选择
如果要修改模型选择,需要在配置文件进行修改。【使用云平台模型】

openclaw config set 'models.providers.mass' --json '{
  "baseUrl": "https://api.modelarts-maas.com/openai/v1",
  "apiKey": "api值",
  "api": "openai-completions",
  "models": [
    { "id": "DeepSeek-V3", "name": "DeepSeek-V3" },
    { "id": "deepseek-r1-250528", "name": "deepseek-r1-250528" }
  ]
}'

设置 models.mode 为 merge

openclaw config set models.mode merge
设置默认模型(以deepseek-chat为例)

openclaw models set mass/DeepSeek-V3

openclaw gateway restart
{
"agents": {
 "defaults": {
   "model": { "primary": "bailian/qwen3-max-2026-01-23" },
   "models": {
     "bailian/qwen3-max-2026-01-23": { "alias": "通义千问 Max Thinking 版" }
   }
 }
},
"models": {
 "mode": "merge",
 "providers": {
   "bailian": {
     "baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
     "apiKey": "${DASHSCOPE_API_KEY}",
     "api": "openai-completions",
     "models": [
       {
         "id": "qwen3-max-2026-01-23",
         "name": "通义千问 Max Thinking 版",
         "reasoning": false,
         "input": ["text"],
         "cost": { "input": 0.0025, "output": 0.01, "cacheRead": 0, "cacheWrite": 0 },
         "contextWindow": 262144,
         "maxTokens": 65536
       }
     ]
   }
 }
}
}

第二种:使用本地ollama平台

"my-ollama": {
  "baseUrl": "http://127.0.0.1:11434/v1",
  "apiKey": "ollama",
  "api": "openai-completions",
  "models": [
    {
      "id": "qwen3:32b",
      "name": "Local Qwen3 32B",
      "reasoning": false,
      "input": ["text"],
      "contextWindow": 32000,
      "maxTokens": 4096,
      "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}
    }
  ]
}

3.使用

openclaw dashboard --no-open    ###查看token

浏览器里访问上面截图中带token的那个URL就可以了

再来看看如何用Openclaw来远程登录Linux机器,并执行任务。

首先,你要让Openclaw生成密钥对,并将公钥给到我们


我要远程登录一台Linux机器,我要使用SSH密钥验证的方式,
请生成一对密钥对,并提供给我公钥

它不仅提供了公钥内容,还告诉我们如何配置,我把公钥放到了目标服务器上后,然后告诉它可以登录服务器了

然后我再次发出需求

########配置文件模板
{
  // Workspace 配置
  agents: {
    defaults: {
      workspace: "~/.openclaw/workspace",
      repoRoot: "~/.openclaw/workspace",
      skipBootstrap: false,
      model: {
        primary: "provider/claude-sonnet-4",
        fallbacks: ["provider/claude-haiku-4"],
      },
      imageModel: "provider/claude-sonnet-4",
      timeoutSeconds: 600,
      compaction: {
        reserveTokensFloor: 20000,
        memoryFlush: {
          enabled: true,
          softThresholdTokens: 4000,
        },
      },
      heartbeat: {
        every: "30m",
        target: "last",
        activeHours: {
          start: "08:00",
          end: "23:00",
        },
      },
      blockStreamingDefault: "on",
      blockStreamingBreak: "text_end",
      blockStreamingChunk: {
        minChars: 200,
        maxChars: 1500,
      },
    },
  },

  // Gateway 配置
  gateway: {
    port: 18789,
    bind: "loopback",
    auth: {
      mode: "token",
      token: "your-secret-token",
    },
    reload: {
      mode: "hybrid",
    },
  },

  // 日志配置
  logging: {
    level: "info",
    consoleStyle: "pretty",
    redactSensitive: "tools",
  },

  // 渠道配置
  channels: {
    discord: {
      token: "your-discord-bot-token",
      allowFrom: ["server:your-server-id"],
      ackReaction: "👀",
      dm: {
        enabled: true,
        policy: "pairing",
      },
      historyLimit: 20,
      textChunkLimit: 2000,
    },
    telegram: {
      botToken: "your-telegram-bot-token",
      allowFrom: ["your-user-id"],
      dm: {
        enabled: true,
        policy: "pairing",
      },
      historyLimit: 50,
      replyToMode: "first",
      linkPreview: true,
      streamMode: "partial",
    },
  },

  // 向量检索配置
  memorySearch: {
    enabled: true,
    provider: "openai",
    remote: {
      baseUrl: "https://api.siliconflow.cn/v1",
      apiKey: "your-siliconflow-api-key",
    },
    model: "BAAI/bge-m3",
  },

  // 工具配置
  tools: {
    exec: {
      enabled: true,
    },
    web: {
      search: {
        enabled: true,
      },
    },
    media: {
      image: {
        enabled: true,
      },
    },
  },

  // Cron 配置
  cron: {
    enabled: true,
    maxConcurrentRuns: 2,
  },
}

4.nginx反向代理

sudo apt install nginx
sudo vim /etc/nginx/nginx.conf 
注释掉如下行 
#include /etc/nginx/sites-enabled/*;

上传SSL证书至/etc/nginx/ssl/
cd /etc/nginx/conf.d/
sudo vim openclaw_nginx_reverse_proxy.conf

添加如下行
server {
     # 将原有 listen 80 修改为 listen 80 改为 listen 443 ssl
    listen 443 ssl;
    # 原有 server_name,可继续新增更多当前证书支持的域名
    server_name openclaw.openjarvis.net;

    # ======================= 证书配置开始 =======================
    # 指定证书文件(中间证书可以拼接至该pem文件中),请将 /etc/ssl/cert/ssl.pem 替换为您实际使用的证书文件的绝对路径
    ssl_certificate /etc/nginx/ssl/openclaw.openjarvis.net.pem;
    # 指定私钥文档,请将 /etc/ssl/cert/ssl.key 替换为您实际使用的私钥文件的绝对路径
    ssl_certificate_key /etc/nginx/ssl/openclaw.openjarvis.net.key;
    # 配置 SSL 会话缓存,提高性能
    ssl_session_cache shared:SSL:1m;
    # 设置 SSL 会话超时时间
    ssl_session_timeout 5m;
    # 自定义设置使用的TLS协议的类型以及加密套件(以下为配置示例,请您自行评估是否需要配置)
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    # 指定允许的 TLS 协议版本,TLS协议版本越高,HTTPS通信的安全性越高,但是相较于低版本TLS协议,高版本TLS协议对浏览器的兼容性较差
    ssl_protocols TLSv1.2 TLSv1.3;
    # 优先使用服务端指定的加密套件
    ssl_prefer_server_ciphers on;
    # ======================= 证书配置结束 =======================

    # 其它配置

    location / {
        proxy_pass http://127.0.0.1:18789;

        # WebSocket升级头
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';

        # 客户端真实信息
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 缓冲区设置
        proxy_buffering off;

        # 超时设置
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
        proxy_connect_timeout 30s;
    }
}

5.接入钉钉

安装openclaw-channel-dingtalk插件

插件Github地址:https://github.com/soimy/openclaw-channel-dingtalk

git clone https://github.com/soimy/openclaw-channel-dingtalk.git
cd openclaw-channel-dingtalk
openclaw plugins install -l .

图片

钉钉应用及机器人

  • 创建钉钉应用

  1. 访问 钉钉开发者后台

  2. 创建企业内部应用

  3. 添加「机器人」能力

  4. 配置消息接收模式为 Stream 模式

  5. 发布应用

  • 配置权限管理

在应用的权限管理页面,需要开启以下权限:

✅ Card.Instance.Write — 创建和投放卡片实例

✅ Card.Streaming.Write — 对卡片进行流式更新 步骤:

进入应用 → 权限管理 搜索「Card」相关权限 勾选上述两个权限 保存权限配置

图片

  • 建立卡片模板 如需使用 AI 互动卡片功能,需要在钉钉卡片平台创建模板:

  1. 访问 钉钉卡片平台

  2. 进入「我的模板」

  3. 点击「创建模板」

  4. 卡片模板场景选择 「AI 卡片」

  5. 无需选择预设模板,直接点击保存

  6. 复制模板 ID(格式如:xxxxx-xxxxx-xxxxx.schema)

  7. 在OpenClaw控制台的Channel标签->Dingtalk配置面板-> Card Template Id填入

  • 获取凭证 从开发者后台获取:

Client ID (AppKey) 

Client Secret (AppSecret) 

Robot Code (与 Client ID 相同) 

Corp ID (企业 ID) 

Agent ID (应用 ID)

图片

9. 重启 Gatewa

openclaw gateway restart

图片

10、与机器人进行对话进行验证

图片

#####升级版本

最近把版本升级到最新的4.9后有些参数改变

openclaw update

"gateway": {
    "port": 18789,
    "mode": "local",
    "bind": "lan",
    "controlUi": {
      "allowedOrigins": ["http://192.168.1.1:18789"],
      "allowInsecureAuth": true,
      "dangerouslyDisableDeviceAuth": true
    },

#######连接微信插件

npx -y @tencent-weixin/openclaw-weixin-cli@latest install
[openclaw-weixin] 已找到本地安装的 openclaw
[openclaw-weixin] 检测到 OpenClaw 版本: 2026.4.9
[openclaw-weixin] 匹配 dist-tag: latest
[openclaw-weixin] 正在安装插件 @tencent-weixin/openclaw-weixin@latest...
[openclaw-weixin] 插件安装失败,请手动执行:
ClawHub /api/v1/packages/%40tencent-weixin%2Fopenclaw-weixin failed (429): Rate limit exceeded

  openclaw plugins install "@tencent-weixin/openclaw-weixin@latest"
安装的时候会一直报429错误,需要先登录clawhub才行

npx clawhub login
Need to install the following packages:
clawhub@0.9.0
Ok to proceed? (y) y

Opening browser: https://clawhub.ai/cli/auth     根据连接登录clawhub才能安装,安装完成后根据二维码绑定就行了


 

Docker 部署汉化版 OpenClaw 程教程

 使用 Docker Compose

version: '3.8'
services:
  openclaw:
    image: 1186258278/openclaw-zh:latest
    container_name: openclaw
    ports:
      - "18789:18789"
    volumes:
      - openclaw-data:/root/.openclaw
    restart: unless-stopped
    command: openclaw gateway run
    # 新增优化配置
    environment:
      - TZ=Asia/Shanghai  # 统一时区,避免日志时间错乱
      - NODE_ENV=production
    logging:  # 日志配置(限制日志大小,避免占满磁盘)
      driver: "json-file"
      options:
        max-size: "100m"  # 单个日志文件最大100M
        max-file: "3"     # 最多保留3个日志文件
    privileged: false     # 非特权模式(提升安全性)
    mem_limit: 1G         # 限制容器内存使用(避免占用过多资源)
volumes:
  openclaw-data:
    driver: local






 ###先执行初始化基础数据的命令
//1. 手动初始化
docker-compose run --rm openclaw openclaw setup
docker-compose run --rm openclaw openclaw config set gateway.mode local

//2. 配置绑定和认证
docker-compose run --rm openclaw openclaw config set gateway.bind lan
docker-compose run --rm openclaw openclaw config set gateway.auth.token YOUR_TOKEN

//3. 设置模型配置,newapiapp是自定义的供应商名称,配置相应的apikey、baseurl、默认Id,可以设置多个
docker-compose run --rm openclaw openclaw config set models.providers.newapiapp '{
  "api": "openai-completions",
  "apiKey": "sk-xxxx",
  "baseUrl": "https://api.openai.com/v1",
  "models": [
    {
      "id": "modelscope-k2.5",
      "name": "modelscope-k2.5"
    }
  ]
}'

//设置默认主模型,后面的对话就可以默认使用对应供应商的模型了
docker-compose run --rm openclaw openclaw config set agents.defaults.model.primary "newapiapp/modelscope-k2.5"

//4. 允许不完全访问,可以通过ip、域名反代等远程访问
docker-compose run --rm openclaw openclaw config set gateway.controlUi.allowInsecureAuth true

###配置初始化完成后,可以启动服务,执行如下命令
docker-compose up -d

使用 Docker Compose 部署

# 启动服务 docker-compose up -d 

 # 查看日志 docker-compose logs -f 

 # 停止服务 docker-compose down  

# 重启服务 docker-compose restart

8.2 Nginx 反向代理 + HTTPS

📚 参考资源

官方文档:

•OpenClaw 汉化官网: https://openclaw.qingtong.cloud

•GitHub 仓库: https://github.com/1186258278/OpenClawChineseTranslation

•Docker Hub: https://hub.docker.com/r/1186258278/openclaw-zh

OpenClaw + K8s + Docker安装完整保姆级教程

环境要求

组件

版本要求

说明

操作系统

Ubuntu 22.04+ / Debian 12+

推荐 Ubuntu 22.04 LTS,内核 5.15+

Docker

24.0+

需要 Docker Compose V2(docker compose 命令)

Kubernetes

1.28+

推荐 1.30,需要支持 PV 动态供给

Node.js

24.x(容器内置)

OpenClaw 镜像基于 node:24-bookworm,无需手动安装

GPU(可选)

NVIDIA A100/A800/H100

仅 vLLM 推理服务需要,OpenClaw 网关本身不需要 GPU

内存

4GB+(网关) / 64GB+(推理)

网关内存需求低,推理节点建议 4 倍 GPU 显存

磁盘

20GB+(网关) / 500GB+ NVMe(推理)

推理节点需要存储模型权重文件

网络

集群内网互通,Ingress Controller 已部署

推荐 NGINX Ingress Controller 或 Traefik


二、详细步骤

2.1 准备工作

2.1.1 系统检查
# 检查系统版本
cat /etc/os-release

# 检查内核版本
uname -r

# 检查 Docker 版本(需要 24.0+)
docker --version
docker compose version

# 检查系统资源
free -h
df -h

# 如果部署 K8s 方案,检查集群状态
kubectl cluster-info
kubectl get nodes -o wide

预期输出:Docker 版本 24.0 以上,Docker Compose V2 正常输出版本号。K8s 集群所有节点 Ready 状态。

2.1.2 安装 Docker(如果还没装)
# Ubuntu/Debian 安装 Docker
curl -fsSL https://get.docker.com | bash -s docker

# 将当前用户加入 docker 组(避免每次 sudo)
sudo usermod -aG docker $USER
newgrp docker

# 验证安装
docker run hello-world
2.1.3 准备 OpenClaw 配置目录
# 创建配置目录
mkdir -p ~/.openclaw

# 创建工作空间目录
mkdir -p ~/openclaw-workspace

OpenClaw 的配置文件是 JSON5 格式,文件路径固定在 ~/.openclaw/openclaw.json。容器内部以 node 用户(uid 1000)运行,挂载目录时需要注意权限问题。

# 确保目录权限正确(容器内 node 用户 uid=1000)
sudo chown -R 1000:1000 ~/.openclaw
sudo chown -R 1000:1000 ~/openclaw-workspace

2.2 Docker Compose 部署(官方方案)

这是官方推荐的部署方式,适合开发测试和小规模生产环境。

2.2.1 使用官方安装脚本

OpenClaw 提供了 docker-setup.sh 一键安装脚本,流程是:拉取镜像 → 初始化配置(onboard)→ 启动服务。

# 拉取官方安装脚本并执行
curl -fsSL https://raw.githubusercontent.com/openclaw/openclaw/main/docker-setup.sh | bash

如果网络环境不方便直接执行远程脚本,也可以手动操作:

# 手动拉取镜像
docker pull ghcr.io/openclaw/openclaw:latest

# 初始化配置(交互式,会引导设置 Token 和基础配置)
docker run --rm -it \
  -v "$HOME/.openclaw:/home/node/.openclaw" \
  ghcr.io/openclaw/openclaw:latest \
  openclaw onboard
2.2.2 环境变量配置

docker-setup.sh 支持通过环境变量定制行为:

环境变量

默认值

说明

OPENCLAW_IMAGE ghcr.io/openclaw/openclaw:latest

镜像地址,私有仓库可改这个

OPENCLAW_GATEWAY_BIND 0.0.0.0:18789

网关监听地址和端口

OPENCLAW_HOME_VOLUME ~/.openclaw

配置文件挂载路径

OPENCLAW_SANDBOX 0

设为 1 启用沙箱模式

# 自定义启动示例
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
export OPENCLAW_GATEWAY_BIND="0.0.0.0:18789"
export OPENCLAW_HOME_VOLUME="$HOME/.openclaw"
2.2.3 编写 Docker Compose 文件

生产环境建议用 docker-compose.yml 管理,比裸 docker run 更容易维护:

# docker-compose.yml
version:"3.8"

services:
openclaw-gateway:
    image:ghcr.io/openclaw/openclaw:latest
    container_name:openclaw-gateway
    restart:unless-stopped
    ports:
      -"18789:18789"
    volumes:
      -./config:/home/node/.openclaw
      -./workspace:/home/node/workspace
    environment:
      -NODE_ENV=production
    user:"1000:1000"
    healthcheck:
      test:["CMD","curl","-f","http://localhost:18789/healthz"]
      interval:30s
      timeout:10s
      retries:3
      start_period:15s
    deploy:
      resources:
        limits:
          memory:2G
          cpus:"2.0"
        reservations:
          memory:512M
          cpus:"0.5"
    logging:
      driver:json-file
      options:
        max-size:"50m"
        max-file:"5"
2.2.4 编写 OpenClaw 配置文件

在 ./config/ 目录下创建 openclaw.json(JSON5 格式,支持注释):

// ./config/openclaw.json
{
  // 网关配置
  gateway: {
    bind: "0.0.0.0:18789",
    auth: {
      // 生产环境必须改成随机生成的强 Token
      token: "oc-prod-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
    }
  },

  // 模型配置
  models: {
    // 默认模型(客户端不指定模型时使用)
    default: "vllm-local/Qwen3.5-35B",

    providers: {
      // 自托管 vLLM 推理服务
      "vllm-local": {
        baseUrl: "http://vllm-service:8000/v1",
        api: "openai-responses",
        models: [
          "Qwen/Qwen3.5-35B-A3B-FP8"
        ]
      }
    }
  }
}

注意gateway.auth.token 这个值必须是强随机字符串,别用示例里的值。生成方法:

# 生成 32 字节随机 Token
openssl rand -hex 32
2.2.5 启动并验证
# 启动服务(后台运行)
docker compose up -d

# 查看日志,确认启动成功
docker compose logs -f openclaw-gateway

# 健康检查
curl -s http://localhost:18789/healthz
# 预期输出:{"status":"ok"}

# 就绪检查
curl -s http://localhost:18789/readyz
# 预期输出:{"status":"ready"}

# 带 Token 认证的请求测试
curl -s -H "Authorization: Bearer oc-prod-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  http://localhost:18789/v1/models

如果 /healthz 返回 {"status":"ok"} 就说明网关启动成功了。/readyz 还会检查后端模型连通性,如果 vLLM 还没部署,/readyz 可能返回 not ready,这是正常的。

2.3 Kubernetes 部署方案

官方没有提供 K8s 部署方案,以下配置是基于 Docker 方案转写的。核心思路:把 Docker 的 bind mount 换成 PVC,把环境变量和配置文件换成 ConfigMap/Secret,把容器换成 Deployment + Service。

2.3.1 创建 Namespace
kubectl create namespace openclaw

所有 OpenClaw 相关资源都放在 openclaw Namespace 下,方便管理和 RBAC 隔离。

2.3.2 ConfigMap:OpenClaw 配置文件
# openclaw-configmap.yaml
apiVersion:v1
kind:ConfigMap
metadata:
name:openclaw-config
namespace:openclaw
labels:
    app:openclaw
    component:gateway
data:
openclaw.json: |
    {
      // 网关配置
      "gateway": {
        "bind": "0.0.0.0:18789",
        "auth": {
          // Token 从 Secret 注入,这里用环境变量占位
          // 实际运行时由 entrypoint 脚本替换
          "token": "${OPENCLAW_AUTH_TOKEN}"
        }
      },
      "models": {
        "default": "vllm-local/Qwen3.5-35B",
        "providers": {
          "vllm-local": {
            "baseUrl": "http://vllm-service.openclaw.svc.cluster.local:8000/v1",
            "api": "openai-responses",
            "models": [
              "Qwen/Qwen3.5-35B-A3B-FP8"
            ]
          }
        }
      }
    }

模型服务地址使用 K8s 内部 DNS:vllm-service.openclaw.svc.cluster.local:8000,不需要走集群外部网络。

2.3.3 Secret:敏感信息
# 生成随机 Token
GATEWAY_TOKEN=$(openssl rand -hex 32)

# 创建 Secret
kubectl create secret generic openclaw-secrets \
  --namespace=openclaw \
  --from-literal=gateway-token="${GATEWAY_TOKEN}" \
  --from-literal=openai-api-key="sk-your-openai-key-if-needed"

# 验证 Secret 创建成功
kubectl get secret openclaw-secrets -n openclaw

也可以用 YAML 声明式创建(Token 需要 base64 编码):

# openclaw-secret.yaml
apiVersion:v1
kind:Secret
metadata:
name:openclaw-secrets
namespace:openclaw
labels:
    app:openclaw
type:Opaque
data:
# echo -n "your-token" | base64
gateway-token:"b2MtcHJvZC1hMWIyYzNkNGU1ZjZnN2g4aTlqMGsxbDJtM240bzVwNg=="
openai-api-key:""
2.3.4 PersistentVolumeClaim:持久化存储
# openclaw-pvc.yaml
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:openclaw-data
namespace:openclaw
labels:
    app:openclaw
spec:
accessModes:
    -ReadWriteOnce
storageClassName:standard
resources:
    requests:
      storage:10Gi
---
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:openclaw-workspace
namespace:openclaw
labels:
    app:openclaw
spec:
accessModes:
    -ReadWriteOnce
storageClassName:standard
resources:
    requests:
      storage:50Gi

storageClassName 根据集群实际情况调整。云厂商环境一般用 gp3(AWS)、pd-ssd(GCP)、managed-csi(Azure)。自建集群用 local-path 或 NFS。

如果 Gateway 需要多副本,accessModes 要改成 ReadWriteMany,存储后端也要支持(NFS、CephFS 等)。单副本用 ReadWriteOnce 就够了。

2.3.5 Deployment:OpenClaw Gateway
# openclaw-deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:openclaw-gateway
namespace:openclaw
labels:
    app:openclaw
    component:gateway
spec:
replicas:2
selector:
    matchLabels:
      app:openclaw
      component:gateway
strategy:
    type:RollingUpdate
    rollingUpdate:
      maxSurge:1
      maxUnavailable:0
template:
    metadata:
      labels:
        app:openclaw
        component:gateway
    spec:
      securityContext:
        runAsUser:1000
        runAsGroup:1000
        fsGroup:1000
      initContainers:
        # initContainer 用于将 ConfigMap 中的配置文件复制到可写目录
        # 并替换 Token 占位符
        -name:config-init
          image:ghcr.io/openclaw/openclaw:latest
          command:
            -/bin/sh
            --c
            -|
              cp /config-readonly/openclaw.json /home/node/.openclaw/openclaw.json
              sed -i "s|\${OPENCLAW_AUTH_TOKEN}|${GATEWAY_TOKEN}|g" /home/node/.openclaw/openclaw.json
          env:
            -name:GATEWAY_TOKEN
              valueFrom:
                secretKeyRef:
                  name:openclaw-secrets
                  key:gateway-token
          volumeMounts:
            -name:config-readonly
              mountPath:/config-readonly
            -name:openclaw-data
              mountPath:/home/node/.openclaw
      containers:
        -name:openclaw-gateway
          image:ghcr.io/openclaw/openclaw:latest
          ports:
            -name:http
              containerPort:18789
              protocol:TCP
          env:
            -name:NODE_ENV
              value:"production"
            -name:OPENCLAW_AUTH_TOKEN
              valueFrom:
                secretKeyRef:
                  name:openclaw-secrets
                  key:gateway-token
          volumeMounts:
            -name:openclaw-data
              mountPath:/home/node/.openclaw
            -name:openclaw-workspace
              mountPath:/home/node/workspace
          resources:
            requests:
              cpu:"500m"
              memory:"512Mi"
            limits:
              cpu:"2000m"
              memory:"2Gi"
          livenessProbe:
            httpGet:
              path:/healthz
              port:18789
            initialDelaySeconds:15
            periodSeconds:30
            timeoutSeconds:5
            failureThreshold:3
          readinessProbe:
            httpGet:
              path:/readyz
              port:18789
            initialDelaySeconds:10
            periodSeconds:10
            timeoutSeconds:5
            failureThreshold:3
          startupProbe:
            httpGet:
              path:/healthz
              port:18789
            initialDelaySeconds:5
            periodSeconds:5
            failureThreshold:12
      volumes:
        -name:config-readonly
          configMap:
            name:openclaw-config
        -name:openclaw-data
          persistentVolumeClaim:
            claimName:openclaw-data
        -name:openclaw-workspace
          persistentVolumeClaim:
            claimName:openclaw-workspace
      terminationGracePeriodSeconds:30

几个关键设计点:

  1. initContainer 处理配置:ConfigMap 挂载的目录是只读的,但 OpenClaw 运行时需要读写 ~/.openclaw 目录。所以用 initContainer 把配置文件从 ConfigMap 复制到 PVC,同时替换 Token 占位符。

  2. securityContext uid=1000:OpenClaw 镜像以 node 用户运行(uid 1000),PVC 目录的 fsGroup 也设为 1000,避免权限问题。

  3. 三种探针都配了:startupProbe 给容器 60 秒启动时间(5s × 12次),livenessProbe 检测进程存活,readinessProbe 检测服务就绪。

  4. RollingUpdate maxUnavailable=0:更新时先拉起新 Pod 再下旧 Pod,服务零中断。

2.3.6 Service
# openclaw-service.yaml
apiVersion:v1
kind:Service
metadata:
name:openclaw-gateway
namespace:openclaw
labels:
    app:openclaw
    component:gateway
spec:
type:ClusterIP
ports:
    -name:http
      port:18789
      targetPort:18789
      protocol:TCP
selector:
    app:openclaw
    component:gateway
---
# NodePort Service(可选,用于无 Ingress 环境直接访问)
apiVersion:v1
kind:Service
metadata:
name:openclaw-gateway-nodeport
namespace:openclaw
labels:
    app:openclaw
    component:gateway
spec:
type:NodePort
ports:
    -name:http
      port:18789
      targetPort:18789
      nodePort:31789
      protocol:TCP
selector:
    app:openclaw
    component:gateway

ClusterIP Service 供集群内部访问(Ingress 转发用),NodePort Service 供没有 Ingress 的环境直接通过 节点IP:31789 访问。生产环境推荐走 Ingress + ClusterIP,不暴露 NodePort。

2.3.7 Ingress:HTTPS 暴露
# openclaw-ingress.yaml
apiVersion:networking.k8s.io/v1
kind:Ingress
metadata:
name:openclaw-gateway
namespace:openclaw
labels:
    app:openclaw
annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout:"3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout:"3600"
    # WebSocket 支持(OpenClaw 端口复用 HTTP + WS)
    nginx.ingress.kubernetes.io/proxy-http-version:"1.1"
    nginx.ingress.kubernetes.io/upstream-hash-by:"$remote_addr"
    # 请求体大小限制(Agent 对话上下文可能很长)
    nginx.ingress.kubernetes.io/proxy-body-size:"50m"
    # TLS 证书自动签发(需要 cert-manager)
    cert-manager.io/cluster-issuer:"letsencrypt-prod"
spec:
ingressClassName:nginx
tls:
    -hosts:
        -openclaw.example.com
      secretName:openclaw-tls
rules:
    -host:openclaw.example.com
      http:
        paths:
          -path:/
            pathType:Prefix
            backend:
              service:
                name:openclaw-gateway
                port:
                  number:18789

Ingress 的 proxy-read-timeout 设成 3600 秒,因为大模型推理响应时间可能很长(特别是长文本生成场景)。默认 60 秒超时在生产环境一定会出问题,这个坑踩过的人都知道。

WebSocket 的 proxy-http-version 必须设为 1.1,否则 WS 连接建不起来。

2.4 vLLM 推理服务部署

OpenClaw 网关本身不做推理,需要后端挂一个推理服务。这里用 vLLM 部署 Qwen/Qwen3.5-35B-A3B-FP8 模型。

2.4.1 vLLM Deployment
# vllm-deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:vllm-inference
namespace:openclaw
labels:
    app:openclaw
    component:vllm
spec:
replicas:1
selector:
    matchLabels:
      app:openclaw
      component:vllm
template:
    metadata:
      labels:
        app:openclaw
        component:vllm
    spec:
      containers:
        -name:vllm
          image:vllm/vllm-openai:latest
          command:
            -python3
            --m
            -vllm.entrypoints.openai.api_server
          args:
            -"--model"
            -"Qwen/Qwen3.5-35B-A3B-FP8"
            -"--host"
            -"0.0.0.0"
            -"--port"
            -"8000"
            -"--tensor-parallel-size"
            -"4"
            -"--max-model-len"
            -"32768"
            -"--gpu-memory-utilization"
            -"0.90"
            -"--block-size"
            -"16"
            -"--swap-space"
            -"8"
            -"--dtype"
            -"auto"
            -"--trust-remote-code"
          ports:
            -name:http
              containerPort:8000
              protocol:TCP
          env:
            -name:HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name:openclaw-secrets
                  key:openai-api-key
                  optional:true
            -name:VLLM_WORKER_MULTIPROC_METHOD
              value:"spawn"
          resources:
            requests:
              cpu:"8"
              memory:"64Gi"
              nvidia.com/gpu:"4"
            limits:
              cpu:"16"
              memory:"128Gi"
              nvidia.com/gpu:"4"
          volumeMounts:
            -name:model-cache
              mountPath:/root/.cache/huggingface
            -name:shm
              mountPath:/dev/shm
          livenessProbe:
            httpGet:
              path:/health
              port:8000
            initialDelaySeconds:120
            periodSeconds:30
            timeoutSeconds:10
            failureThreshold:5
          readinessProbe:
            httpGet:
              path:/health
              port:8000
            initialDelaySeconds:120
            periodSeconds:15
            timeoutSeconds:10
            failureThreshold:5
      volumes:
        -name:model-cache
          persistentVolumeClaim:
            claimName:vllm-model-cache
        -name:shm
          emptyDir:
            medium:Memory
            sizeLimit:16Gi
      tolerations:
        -key:nvidia.com/gpu
          operator:Exists
          effect:NoSchedule
      nodeSelector:
        gpu-type:a100
---
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:vllm-model-cache
namespace:openclaw
spec:
accessModes:
    -ReadWriteOnce
storageClassName:standard
resources:
    requests:
      storage:200Gi

几个坑点说明:

  1. /dev/shm 必须挂载 emptyDir:vLLM 多进程通信依赖共享内存,Docker 默认的 64MB shm 远远不够。这里给了 16Gi,35B 模型 4 卡并行至少需要这个量级。

  2. **tensor-parallel-size=4**:Qwen3.5-35B-A3B-FP8 是 FP8 量化模型,4 张 A100 80GB 可以稳定加载。2 张卡勉强能跑但显存利用率太高,留不出 KV Cache 空间。

  3. **initialDelaySeconds=120**:大模型加载需要时间,35B 模型从磁盘加载到 GPU 至少要 90 秒,设短了 Pod 会被 K8s 反复杀掉重启。

  4. **gpu-memory-utilization=0.90**:给 KV Cache 留 10% 的显存余量。设成 0.95 虽然能多接几个并发,但在突发流量下容易 OOM。

  5. nodeSelector:确保 Pod 调度到有 GPU 的节点,标签 gpu-type: a100 需要提前给节点打好。

2.4.2 vLLM Service
# vllm-service.yaml
apiVersion:v1
kind:Service
metadata:
name:vllm-service
namespace:openclaw
labels:
    app:openclaw
    component:vllm
spec:
type:ClusterIP
ports:
    -name:http
      port:8000
      targetPort:8000
      protocol:TCP
selector:
    app:openclaw
    component:vllm

这个 Service 只在集群内部暴露,OpenClaw 网关通过 http://vllm-service.openclaw.svc.cluster.local:8000/v1 访问。不需要对外暴露推理服务端口,安全性更好。

2.5 OpenClaw 对接 vLLM

2.5.1 配置 models.providers

OpenClaw 的 openclaw.json 中 models.providers 部分配置 vLLM 作为推理后端:

{
  models: {
    default: "vllm-local/Qwen3.5-35B",
    providers: {
      "vllm-local": {
        // K8s 环境使用 Service DNS
        baseUrl: "http://vllm-service.openclaw.svc.cluster.local:8000/v1",
        // Docker 环境使用容器名或宿主机 IP
        // baseUrl: "http://host.docker.internal:8000/v1",
        api: "openai-responses",
        models: [
          "Qwen/Qwen3.5-35B-A3B-FP8"
        ]
      }
    }
  }
}

Provider 名称 vllm-local 可以自定义,客户端请求时通过 provider/model 格式指定模型,比如 vllm-local/Qwen3.5-35B

如果有多个推理后端,可以配置多个 Provider:

{
  models: {
    default: "vllm-local/Qwen3.5-35B",
    providers: {
      "vllm-local": {
        baseUrl: "http://vllm-service.openclaw.svc.cluster.local:8000/v1",
        api: "openai-responses",
        models: ["Qwen/Qwen3.5-35B-A3B-FP8"]
      },
      "vllm-code": {
        baseUrl: "http://vllm-code-service.openclaw.svc.cluster.local:8000/v1",
        api: "openai-responses",
        models: ["Qwen/Qwen3-Coder-30B-A3B-FP8"]
      }
    }
  }
}
2.5.2 验证模型连通性
# K8s 环境:在集群内部验证
kubectl run -it --rm debug-curl \
  --namespace=openclaw \
  --image=curlimages/curl \
  --restart=Never \
  -- curl -s http://vllm-service:8000/v1/models

# 预期输出:
# {"data":[{"id":"Qwen/Qwen3.5-35B-A3B-FP8","object":"model",...}]}

# 验证 OpenClaw 网关到 vLLM 的端到端连通性
kubectl run -it --rm debug-curl \
  --namespace=openclaw \
  --image=curlimages/curl \
  --restart=Never \
  -- curl -s -H "Authorization: Bearer <your-gateway-token>" \
     http://openclaw-gateway:18789/v1/models

2.6 启动验证

2.6.1 K8s 部署一键执行
# 按顺序部署所有资源
kubectl apply -f openclaw-configmap.yaml
kubectl apply -f openclaw-secret.yaml
kubectl apply -f openclaw-pvc.yaml
kubectl apply -f vllm-deployment.yaml
kubectl apply -f vllm-service.yaml
kubectl apply -f openclaw-deployment.yaml
kubectl apply -f openclaw-service.yaml
kubectl apply -f openclaw-ingress.yaml

# 查看所有资源状态
kubectl get all -n openclaw

# 等待所有 Pod 就绪
kubectl wait --for=condition=ready pod \
  -l app=openclaw \
  -n openclaw \
  --timeout=300s
2.6.2 健康检查验证
# Docker 方案验证
curl -s http://localhost:18789/healthz | python3 -m json.tool
curl -s http://localhost:18789/readyz | python3 -m json.tool

# K8s 方案验证(通过 Ingress)
curl -s https://openclaw.example.com/healthz | python3 -m json.tool
curl -s https://openclaw.example.com/readyz | python3 -m json.tool

# K8s 方案验证(通过 NodePort)
curl -s http://<node-ip>:31789/healthz | python3 -m json.tool

# K8s 方案验证(通过 port-forward,调试用)
kubectl port-forward svc/openclaw-gateway 18789:18789 -n openclaw &
curl -s http://localhost:18789/healthz | python3 -m json.tool
2.6.3 端到端功能测试
# 发送一个完整的对话请求,验证网关→vLLM 链路
curl -s -X POST \
  -H "Authorization: Bearer <your-gateway-token>" \
  -H "Content-Type: application/json" \
  http://localhost:18789/v1/chat/completions \
  -d '{
    "model": "vllm-local/Qwen3.5-35B",
    "messages": [
      {"role": "system", "content": "You are a helpful assistant."},
      {"role": "user", "content": "Hello, what is Kubernetes?"}
    ],
    "max_tokens": 200,
    "temperature": 0.7
  }' | python3 -m json.tool

如果返回了正常的模型响应,说明整条链路跑通了:客户端 → OpenClaw Gateway(认证 + 路由)→ vLLM(推理)→ 返回结果。


三、示例代码和配置

3.1 完整 docker-compose.yml(含 vLLM)

Docker 方案的完整 Compose 文件,一个文件跑起整套服务:

# docker-compose.yml - OpenClaw + vLLM 完整部署
version:"3.8"

services:
# OpenClaw Gateway
openclaw-gateway:
    image:ghcr.io/openclaw/openclaw:latest
    container_name:openclaw-gateway
    restart:unless-stopped
    ports:
      -"18789:18789"
    volumes:
      -./config:/home/node/.openclaw
      -./workspace:/home/node/workspace
    environment:
      -NODE_ENV=production
    user:"1000:1000"
    depends_on:
      vllm:
        condition:service_healthy
    healthcheck:
      test:["CMD","curl","-f","http://localhost:18789/healthz"]
      interval:30s
      timeout:10s
      retries:3
      start_period:15s
    deploy:
      resources:
        limits:
          memory:2G
          cpus:"2.0"
        reservations:
          memory:512M
          cpus:"0.5"
    networks:
      -openclaw-net
    logging:
      driver:json-file
      options:
        max-size:"50m"
        max-file:"5"

# vLLM 推理服务
vllm:
    image:vllm/vllm-openai:latest
    container_name:vllm-inference
    restart:unless-stopped
    ports:
      -"8000:8000"
    command:
      -"--model"
      -"Qwen/Qwen3.5-35B-A3B-FP8"
      -"--host"
      -"0.0.0.0"
      -"--port"
      -"8000"
      -"--tensor-parallel-size"
      -"4"
      -"--max-model-len"
      -"32768"
      -"--gpu-memory-utilization"
      -"0.90"
      -"--block-size"
      -"16"
      -"--swap-space"
      -"8"
      -"--dtype"
      -"auto"
      -"--trust-remote-code"
    volumes:
      -model-cache:/root/.cache/huggingface
    environment:
      -HUGGING_FACE_HUB_TOKEN=${HF_TOKEN:-}
      -VLLM_WORKER_MULTIPROC_METHOD=spawn
    healthcheck:
      test:["CMD","curl","-f","http://localhost:8000/health"]
      interval:30s
      timeout:15s
      retries:10
      start_period:180s
    shm_size:"16gb"
    deploy:
      resources:
        reservations:
          devices:
            -driver:nvidia
              count:4
              capabilities:[gpu]
    networks:
      -openclaw-net

# OpenClaw CLI(管理工具,按需启动)
openclaw-cli:
    image:ghcr.io/openclaw/openclaw:latest
    container_name:openclaw-cli
    profiles:
      -tools
    volumes:
      -./config:/home/node/.openclaw
      -./workspace:/home/node/workspace
    user:"1000:1000"
    stdin_open:true
    tty:true
    networks:
      -openclaw-net

volumes:
model-cache:
    driver:local

networks:
openclaw-net:
    driver:bridge

使用方法:

# 启动网关 + 推理服务
docker compose up -d

# 查看所有服务状态
docker compose ps

# 按需启动 CLI 管理工具
docker compose --profile tools run --rm openclaw-cli openclaw --help

# 查看实时日志
docker compose logs -f

# 停止所有服务
docker compose down

# 停止并清理数据卷(谨慎操作)
docker compose down -v

3.2 完整 K8s YAML(All-in-One Manifest)

把所有 K8s 资源合并到一个文件,方便一键部署:

# openclaw-all-in-one.yaml
# 使用方法:kubectl apply -f openclaw-all-in-one.yaml

# --- Namespace ---
apiVersion:v1
kind:Namespace
metadata:
name:openclaw
labels:
    app:openclaw

---
# --- ConfigMap ---
apiVersion:v1
kind:ConfigMap
metadata:
name:openclaw-config
namespace:openclaw
data:
openclaw.json:|
    {
      "gateway": {
        "bind": "0.0.0.0:18789",
        "auth": {
          "token": "${OPENCLAW_AUTH_TOKEN}"
        }
      },
      "models": {
        "default": "vllm-local/Qwen3.5-35B",
        "providers": {
          "vllm-local": {
            "baseUrl": "http://vllm-service.openclaw.svc.cluster.local:8000/v1",
            "api": "openai-responses",
            "models": [
              "Qwen/Qwen3.5-35B-A3B-FP8"
            ]
          }
        }
      }
    }

---
# --- Secret(部署前先替换 Token) ---
apiVersion:v1
kind:Secret
metadata:
name:openclaw-secrets
namespace:openclaw
type:Opaque
stringData:
gateway-token:"REPLACE_WITH_RANDOM_TOKEN"

---
# --- PVC: Gateway 数据 ---
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:openclaw-data
namespace:openclaw
spec:
accessModes:[ReadWriteOnce]
storageClassName:standard
resources:
    requests:
      storage:10Gi

---
# --- PVC: Gateway 工作空间 ---
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:openclaw-workspace
namespace:openclaw
spec:
accessModes:[ReadWriteOnce]
storageClassName:standard
resources:
    requests:
      storage:50Gi

---
# --- PVC: vLLM 模型缓存 ---
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:vllm-model-cache
namespace:openclaw
spec:
accessModes:[ReadWriteOnce]
storageClassName:standard
resources:
    requests:
      storage:200Gi

---
# --- Deployment: OpenClaw Gateway ---
apiVersion:apps/v1
kind:Deployment
metadata:
name:openclaw-gateway
namespace:openclaw
spec:
replicas:2
selector:
    matchLabels:
      app:openclaw
      component:gateway
strategy:
    type:RollingUpdate
    rollingUpdate:
      maxSurge:1
      maxUnavailable:0
template:
    metadata:
      labels:
        app:openclaw
        component:gateway
    spec:
      securityContext:
        runAsUser:1000
        runAsGroup:1000
        fsGroup:1000
      initContainers:
        -name:config-init
          image:ghcr.io/openclaw/openclaw:latest
          command:["/bin/sh","-c"]
          args:
            -|
              cp /config-readonly/openclaw.json /home/node/.openclaw/openclaw.json
              sed -i "s|\${OPENCLAW_AUTH_TOKEN}|${GATEWAY_TOKEN}|g" /home/node/.openclaw/openclaw.json
          env:
            -name:GATEWAY_TOKEN
              valueFrom:
                secretKeyRef:
                  name:openclaw-secrets
                  key:gateway-token
          volumeMounts:
            -name:config-readonly
              mountPath:/config-readonly
            -name:openclaw-data
              mountPath:/home/node/.openclaw
      containers:
        -name:gateway
          image:ghcr.io/openclaw/openclaw:latest
          ports:
            -containerPort:18789
          env:
            -name:NODE_ENV
              value:"production"
          resources:
            requests:
              cpu:"500m"
              memory:"512Mi"
            limits:
              cpu:"2000m"
              memory:"2Gi"
          livenessProbe:
            httpGet:
              path:/healthz
              port:18789
            initialDelaySeconds:15
            periodSeconds:30
          readinessProbe:
            httpGet:
              path:/readyz
              port:18789
            initialDelaySeconds:10
            periodSeconds:10
          startupProbe:
            httpGet:
              path:/healthz
              port:18789
            periodSeconds:5
            failureThreshold:12
          volumeMounts:
            -name:openclaw-data
              mountPath:/home/node/.openclaw
            -name:openclaw-workspace
              mountPath:/home/node/workspace
      volumes:
        -name:config-readonly
          configMap:
            name:openclaw-config
        -name:openclaw-data
          persistentVolumeClaim:
            claimName:openclaw-data
        -name:openclaw-workspace
          persistentVolumeClaim:
            claimName:openclaw-workspace
      terminationGracePeriodSeconds:30

---
# --- Deployment: vLLM ---
apiVersion:apps/v1
kind:Deployment
metadata:
name:vllm-inference
namespace:openclaw
spec:
replicas:1
selector:
    matchLabels:
      app:openclaw
      component:vllm
template:
    metadata:
      labels:
        app:openclaw
        component:vllm
    spec:
      containers:
        -name:vllm
          image:vllm/vllm-openai:latest
          command:["python3","-m","vllm.entrypoints.openai.api_server"]
          args:
            -"--model=Qwen/Qwen3.5-35B-A3B-FP8"
            -"--host=0.0.0.0"
            -"--port=8000"
            -"--tensor-parallel-size=4"
            -"--max-model-len=32768"
            -"--gpu-memory-utilization=0.90"
            -"--block-size=16"
            -"--swap-space=8"
            -"--dtype=auto"
            -"--trust-remote-code"
          ports:
            -containerPort:8000
          env:
            -name:VLLM_WORKER_MULTIPROC_METHOD
              value:"spawn"
          resources:
            requests:
              cpu:"8"
              memory:"64Gi"
              nvidia.com/gpu:"4"
            limits:
              cpu:"16"
              memory:"128Gi"
              nvidia.com/gpu:"4"
          volumeMounts:
            -name:model-cache
              mountPath:/root/.cache/huggingface
            -name:shm
              mountPath:/dev/shm
          livenessProbe:
            httpGet:
              path:/health
              port:8000
            initialDelaySeconds:120
            periodSeconds:30
          readinessProbe:
            httpGet:
              path:/health
              port:8000
            initialDelaySeconds:120
            periodSeconds:15
      volumes:
        -name:model-cache
          persistentVolumeClaim:
            claimName:vllm-model-cache
        -name:shm
          emptyDir:
            medium:Memory
            sizeLimit:16Gi
      tolerations:
        -key:nvidia.com/gpu
          operator:Exists
          effect:NoSchedule
      nodeSelector:
        gpu-type:a100

---
# --- Service: OpenClaw Gateway ---
apiVersion:v1
kind:Service
metadata:
name:openclaw-gateway
namespace:openclaw
spec:
type:ClusterIP
ports:
    -port:18789
      targetPort:18789
selector:
    app:openclaw
    component:gateway

---
# --- Service: vLLM ---
apiVersion:v1
kind:Service
metadata:
name:vllm-service
namespace:openclaw
spec:
type:ClusterIP
ports:
    -port:8000
      targetPort:8000
selector:
    app:openclaw
    component:vllm

---
# --- Ingress ---
apiVersion:networking.k8s.io/v1
kind:Ingress
metadata:
name:openclaw-gateway
namespace:openclaw
annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout:"3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout:"3600"
    nginx.ingress.kubernetes.io/proxy-http-version:"1.1"
    nginx.ingress.kubernetes.io/proxy-body-size:"50m"
    cert-manager.io/cluster-issuer:"letsencrypt-prod"
spec:
ingressClassName:nginx
tls:
    -hosts:[openclaw.example.com]
      secretName:openclaw-tls
rules:
    -host:openclaw.example.com
      http:
        paths:
          -path:/
            pathType:Prefix
            backend:
              service:
                name:openclaw-gateway
                port:
                  number:18789

部署命令:

# 先替换 Token(手动或用 envsubst)
export GATEWAY_TOKEN=$(openssl rand -hex 32)
sed -i "s/REPLACE_WITH_RANDOM_TOKEN/${GATEWAY_TOKEN}/g" openclaw-all-in-one.yaml

# 一键部署
kubectl apply -f openclaw-all-in-one.yaml

# 查看部署状态
kubectl get all -n openclaw

3.3 openclaw.json 生产配置

完整的生产级配置文件,包含 vLLM Provider、Qwen3.5 模型和多 Provider 路由:

// ~/.openclaw/openclaw.json
// 生产环境配置 - 多 Provider 路由 + vLLM 推理后端
{
  gateway: {
    // 监听地址,容器环境用 0.0.0.0
    bind: "0.0.0.0:18789",

    auth: {
      // 每个接入方使用独立 Token
      // 通过 openclaw CLI 管理多 Token
      token: "oc-prod-<your-random-token-here>"
    },

    // 请求限流配置
    rateLimit: {
      // 每分钟最大请求数
      maxRequestsPerMinute: 600,
      // 单个 Token 每分钟最大请求数
      maxRequestsPerMinutePerToken: 60
    }
  },

  models: {
    // 默认模型(不指定模型时使用)
    default: "vllm-local/Qwen3.5-35B",

    providers: {
      // 主力推理后端:vLLM + Qwen3.5
      "vllm-local": {
        baseUrl: "http://vllm-service.openclaw.svc.cluster.local:8000/v1",
        api: "openai-responses",
        models: [
          "Qwen/Qwen3.5-35B-A3B-FP8"
        ]
      },

      // 代码生成专用后端(可选)
      "vllm-code": {
        baseUrl: "http://vllm-code.openclaw.svc.cluster.local:8000/v1",
        api: "openai-responses",
        models: [
          "Qwen/Qwen3-Coder-30B-A3B-FP8"
        ]
      },

      // 备用云端 Provider(可选,用于降级)
      "openai-cloud": {
        baseUrl: "https://api.openai.com/v1",
        api: "openai-responses",
        apiKey: "${OPENAI_API_KEY}",
        models: [
          "gpt-4o",
          "gpt-4o-mini"
        ]
      }
    }
  },

  // 日志配置
  logging: {
    level: "info",
    // 生产环境建议 JSON 格式,方便 ELK/Loki 采集
    format: "json"
  }
}

3.4 案例一:企业微信 / Telegram 多渠道接入

场景描述:公司同时使用企业微信(内部沟通)和 Telegram(海外团队),需要同一个 AI 助手在两个平台上提供服务。OpenClaw 作为网关统一接入,后端共用同一个 vLLM 推理实例。

架构图

企业微信 Bot ──→ Webhook ──→ OpenClaw Gateway (:18789) ──→ vLLM (:8000)
Telegram Bot ──→ Webhook ──↗                                  ↓
                                                    Qwen3.5-35B-A3B-FP8

实现步骤

  1. 在企业微信管理后台创建应用,获取 CorpIDAgentIDSecret

  2. 在 Telegram 通过 @BotFather 创建 Bot,获取 BOT_TOKEN

  3. 配置 OpenClaw 渠道接入

// openclaw.json - 多渠道配置
{
  gateway: {
    bind: "0.0.0.0:18789",
    auth: {
      token: "oc-prod-<your-token>"
    }
  },

  // 渠道配置
  channels: {
    // 企业微信接入
    "wechat-work": {
      type: "wechat-work",
      corpId: "ww1234567890abcdef",
      agentId: 1000002,
      secret: "${WECHAT_WORK_SECRET}",
      token: "${WECHAT_WORK_TOKEN}",
      encodingAesKey: "${WECHAT_WORK_AES_KEY}",
      // 消息回调地址:https://openclaw.example.com/webhook/wechat-work
      webhookPath: "/webhook/wechat-work"
    },

    // Telegram 接入
    "telegram": {
      type: "telegram",
      botToken: "${TELEGRAM_BOT_TOKEN}",
      // 消息回调地址:https://openclaw.example.com/webhook/telegram
      webhookPath: "/webhook/telegram"
    }
  },

  models: {
    default: "vllm-local/Qwen3.5-35B",
    providers: {
      "vllm-local": {
        baseUrl: "http://vllm-service.openclaw.svc.cluster.local:8000/v1",
        api: "openai-responses",
        models: ["Qwen/Qwen3.5-35B-A3B-FP8"]
      }
    }
  }
}

设置 Webhook 回调

# Telegram:设置 Webhook URL
curl -s -X POST \
  "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://openclaw.example.com/webhook/telegram"}'

# 企业微信:在管理后台「应用管理」→「接收消息」中配置
# URL: https://openclaw.example.com/webhook/wechat-work
# Token 和 EncodingAESKey 与 openclaw.json 中保持一致

验证

# 验证 Telegram Webhook 状态
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getWebhookInfo" | python3 -m json.tool

# 在企业微信中给 Bot 发消息,观察 OpenClaw 日志
kubectl logs -f -l app=openclaw,component=gateway -n openclaw

# 在 Telegram 中给 Bot 发消息,观察响应

3.5 案例二:K8s 多租户隔离部署

场景描述:公司有三个部门(研发部、市场部、客服部),每个部门需要独立的 AI 助手,使用不同的模型和配置。要求部门之间网络隔离,互不影响。

隔离方案:Namespace 隔离 + NetworkPolicy 网络隔离 + RBAC 权限隔离 + 独立 vLLM 实例。

3.5.1 Namespace 规划
# 创建部门级 Namespace
kubectl create namespace openclaw-dev      # 研发部
kubectl create namespace openclaw-marketing # 市场部
kubectl create namespace openclaw-support   # 客服部

# 打标签用于 NetworkPolicy 选择
kubectl label namespace openclaw-dev department=dev
kubectl label namespace openclaw-marketing department=marketing
kubectl label namespace openclaw-support department=support
3.5.2 NetworkPolicy:部门间网络隔离
# networkpolicy-isolation.yaml
# 默认拒绝所有跨 Namespace 流量,只允许同 Namespace 内通信

# 研发部 NetworkPolicy
apiVersion:networking.k8s.io/v1
kind:NetworkPolicy
metadata:
name:deny-cross-namespace
namespace:openclaw-dev
spec:
podSelector:{}
policyTypes:
    -Ingress
    -Egress
ingress:
    # 允许同 Namespace 内 Pod 互访
    -from:
        -podSelector:{}
    # 允许 Ingress Controller 访问(必须,否则外部请求进不来)
    -from:
        -namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name:ingress-nginx
egress:
    # 允许同 Namespace 内 Pod 互访
    -to:
        -podSelector:{}
    # 允许 DNS 查询
    -to:
        -namespaceSelector:{}
          podSelector:
            matchLabels:
              k8s-app:kube-dns
      ports:
        -protocol:UDP
          port:53
        -protocol:TCP
          port:53
    # 允许访问外部网络(模型下载、API 调用)
    -to:
        -ipBlock:
            cidr:0.0.0.0/0
            except:
              -10.0.0.0/8
              -172.16.0.0/12
              -192.168.0.0/16
---
# 市场部和客服部使用相同模板,修改 namespace 即可
apiVersion:networking.k8s.io/v1
kind:NetworkPolicy
metadata:
name:deny-cross-namespace
namespace:openclaw-marketing
spec:
podSelector:{}
policyTypes:[Ingress,Egress]
ingress:
    -from:
        -podSelector:{}
    -from:
        -namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name:ingress-nginx
egress:
    -to:
        -podSelector:{}
    -to:
        -namespaceSelector:{}
          podSelector:
            matchLabels:
              k8s-app:kube-dns
      ports:
        -{protocol:UDP,port:53}
        -{protocol:TCP,port:53}
    -to:
        -ipBlock:
            cidr:0.0.0.0/0
            except:[10.0.0.0/8,172.16.0.0/12,192.168.0.0/16]
3.5.3 RBAC:部门管理员权限
# rbac-dev-admin.yaml
# 研发部管理员只能管理自己 Namespace 的资源
apiVersion:rbac.authorization.k8s.io/v1
kind:Role
metadata:
name:openclaw-admin
namespace:openclaw-dev
rules:
-apiGroups:["","apps","networking.k8s.io"]
    resources:["pods","services","deployments","configmaps","ingresses"]
    verbs:["get","list","watch","create","update","patch"]
-apiGroups:[""]
    resources:["pods/log"]
    verbs:["get","list"]
# 禁止删除操作和 Secret 访问
-apiGroups:[""]
    resources:["secrets"]
    verbs:["get","list"]
---
apiVersion:rbac.authorization.k8s.io/v1
kind:RoleBinding
metadata:
name:dev-admin-binding
namespace:openclaw-dev
subjects:
-kind:User
    name:dev-admin@company.com
    apiGroup:rbac.authorization.k8s.io
roleRef:
kind:Role
name:openclaw-admin
apiGroup:rbac.authorization.k8s.io
3.5.4 各部门独立部署

每个部门在自己的 Namespace 部署独立的 OpenClaw Gateway + vLLM 实例。以研发部为例:

# 部署研发部实例
# 1. 生成独立 Token
DEV_TOKEN=$(openssl rand -hex 32)

# 2. 创建 Secret
kubectl create secret generic openclaw-secrets \
  --namespace=openclaw-dev \
  --from-literal=gateway-token="${DEV_TOKEN}"

# 3. 部署(使用 all-in-one 模板,修改 namespace)
sed 's/namespace: openclaw/namespace: openclaw-dev/g' openclaw-all-in-one.yaml | \
  kubectl apply -f -

# 4. 验证
kubectl get all -n openclaw-dev

部门间完全隔离:不同 Token、不同网络策略、不同模型配置、不同资源配额。研发部的请求不会路由到市场部的 vLLM,市场部的 Pod 也无法访问研发部的服务。

3.5.5 ResourceQuota:资源配额限制
# resourcequota-dev.yaml
apiVersion:v1
kind:ResourceQuota
metadata:
name:openclaw-quota
namespace:openclaw-dev
spec:
hard:
    requests.cpu:"16"
    requests.memory:"128Gi"
    limits.cpu:"32"
    limits.memory:"256Gi"
    requests.nvidia.com/gpu:"4"
    persistentvolumeclaims:"5"
    pods:"10"
---
# 市场部配额(不需要 GPU,使用云端 API)
apiVersion:v1
kind:ResourceQuota
metadata:
name:openclaw-quota
namespace:openclaw-marketing
spec:
hard:
    requests.cpu:"4"
    requests.memory:"8Gi"
    limits.cpu:"8"
    limits.memory:"16Gi"
    requests.nvidia.com/gpu:"0"
    persistentvolumeclaims:"3"
    pods:"5"

市场部只部署 OpenClaw Gateway,模型对接云端 API(如 OpenAI),不需要 GPU 资源。研发部自带 vLLM + GPU,资源配额更高。这样既满足了不同部门的需求差异,又避免了资源争抢。


四、最佳实践和注意事项

4.1 最佳实践

4.1.1 性能优化
  • Gateway 并发调优:OpenClaw 基于 Node.js 单线程事件循环,默认并发能力取决于 libuv 线程池大小。生产环境建议设置 UV_THREADPOOL_SIZE=16,可将 I/O 密集型操作的并发提升 4 倍(默认值 4)。

    # Deployment 中添加环境变量
    env:
      - name: UV_THREADPOOL_SIZE
        value: "16"
      - name: NODE_OPTIONS
        value: "--max-old-space-size=1536"
    

    max-old-space-size 限制 V8 堆内存上限,设为容器 memory limit 的 75%。2Gi 内存限制对应 1536MB 堆上限,留出余量给 Node.js 的非堆内存(Buffer、Native 模块等)。

  • vLLM Continuous Batching 参数:vLLM 的 continuous batching 是吞吐量的关键。max-num-seqs 控制同时处理的最大序列数,默认 256。A100 80GB 4 卡跑 35B 模型,实测 max-num-seqs=128 是甜点值,QPS 稳定在 40-60。设太高会导致 KV Cache 不够分,反而降低吞吐。

    args:
      - "--max-num-seqs=128"
      - "--max-num-batched-tokens=32768"
      - "--enable-chunked-prefill"
    

    enable-chunked-prefill 开启后,长 prompt 的 prefill 阶段会分块执行,不会阻塞其他请求的 decode 阶段。实测开启后 P99 延迟从 12s 降到 4s。

  • 资源 limits 设置原则:CPU request 设为 limit 的 25-50%,给突发流量留余量。内存 request 和 limit 建议设成一样,避免 OOM Kill 后 Pod 被驱逐到其他节点引发雪崩。GPU 的 request 和 limit 必须相等(NVIDIA device plugin 的硬性要求)。

    resources:
      requests:
        cpu: "500m"      # limit 的 25%
        memory: "2Gi"    # 和 limit 相同
      limits:
        cpu: "2000m"
        memory: "2Gi"
    
4.1.2 安全加固
  • Token 轮换机制:生产环境建议每 90 天轮换一次 Gateway Token。轮换流程:生成新 Token → 更新 Secret → 滚动重启 Gateway Pod → 通知接入方更新 Token。可以通过 CronJob 自动化:

    # token-rotation-cronjob.yaml
    apiVersion:batch/v1
    kind:CronJob
    metadata:
    name:token-rotation
    namespace:openclaw
    spec:
    schedule:"0 2 1 */3 *"# 每季度 1 号凌晨 2 点执行
    jobTemplate:
        spec:
          template:
            spec:
              serviceAccountName:token-rotator
              containers:
                -name:rotate
                  image:bitnami/kubectl:latest
                  command:["/bin/sh","-c"]
                  args:
                    -|
                      NEW_TOKEN=$(openssl rand -hex 32)
                      kubectl create secret generic openclaw-secrets \
                        --namespace=openclaw \
                        --from-literal=gateway-token="${NEW_TOKEN}" \
                        --dry-run=client -o yaml | kubectl apply -f -
                      kubectl rollout restart deployment/openclaw-gateway -n openclaw
                      echo "Token rotated at $(date). New token prefix: ${NEW_TOKEN:0:8}..."
              restartPolicy:OnFailure
    
  • NetworkPolicy 最小权限:Gateway Pod 只需要出站访问 vLLM Service(端口 8000)和 DNS。入站只允许 Ingress Controller。别偷懒开 allow-all,网络层隔离是多租户安全的基础。

    # networkpolicy-gateway.yaml
    apiVersion:networking.k8s.io/v1
    kind:NetworkPolicy
    metadata:
    name:gateway-policy
    namespace:openclaw
    spec:
    podSelector:
        matchLabels:
          component:gateway
    policyTypes:[Ingress,Egress]
    ingress:
        -from:
            -namespaceSelector:
                matchLabels:
                  kubernetes.io/metadata.name:ingress-nginx
          ports:
            -port:18789
    egress:
        # 允许访问 vLLM Service
        -to:
            -podSelector:
                matchLabels:
                  component:vllm
          ports:
            -port:8000
        # 允许 DNS
        -to:
            -namespaceSelector:{}
              podSelector:
                matchLabels:
                  k8s-app:kube-dns
          ports:
            -{protocol:UDP,port:53}
            -{protocol:TCP,port:53}
    
  • RBAC 最小权限原则:运维人员使用 ClusterRole,开发人员只给 Namespace 级别 Role。Secret 的 get 权限要谨慎分配,能用 list 就别给 getlist 只返回 Secret 名称,get 会返回内容)。

  • TLS 全链路加密:Ingress 到 Gateway 走 HTTPS(cert-manager 自动签发),Gateway 到 vLLM 在集群内部走 HTTP(性能考虑)。如果安全要求极高,可以用 Service Mesh(Istio/Linkerd)实现集群内部 mTLS。

4.1.3 高可用配置
  • Gateway 多副本 + PDB:生产环境至少 2 个副本,配合 PodDisruptionBudget 保证滚动更新和节点维护时至少有 1 个 Pod 可用。

    # pdb.yaml
    apiVersion:policy/v1
    kind:PodDisruptionBudget
    metadata:
    name:openclaw-gateway-pdb
    namespace:openclaw
    spec:
    minAvailable:1
    selector:
        matchLabels:
          app:openclaw
          component:gateway
    
  • HPA 自动扩缩容:基于 CPU 使用率自动扩缩 Gateway 副本数。Gateway 是 I/O 密集型,CPU 通常不高,建议同时监控自定义指标(如请求队列长度)。

    # hpa.yaml
    apiVersion:autoscaling/v2
    kind:HorizontalPodAutoscaler
    metadata:
    name:openclaw-gateway-hpa
    namespace:openclaw
    spec:
    scaleTargetRef:
        apiVersion:apps/v1
        kind:Deployment
        name:openclaw-gateway
    minReplicas:2
    maxReplicas:8
    metrics:
        -type:Resource
          resource:
            name:cpu
            target:
              type:Utilization
              averageUtilization:70
        -type:Resource
          resource:
            name:memory
            target:
              type:Utilization
              averageUtilization:80
    behavior:
        scaleUp:
          stabilizationWindowSeconds:60
          policies:
            -type:Pods
              value:2
              periodSeconds:60
        scaleDown:
          stabilizationWindowSeconds:300
          policies:
            -type:Pods
              value:1
              periodSeconds:120
    

    scaleDown.stabilizationWindowSeconds=300 很重要,防止流量波动导致频繁缩容。缩容太快会在下一波请求到来时来不及扩容,用户体验骤降。

  • vLLM 高可用:vLLM 本身是有状态服务(GPU 显存中有模型权重),不支持多副本负载均衡。高可用方案是部署 2 个独立的 vLLM 实例(不同 Deployment),在 OpenClaw 配置多 Provider,主 Provider 故障时手动切换到备用 Provider。未来可以用 OpenClaw 的 Provider 健康检查实现自动故障转移。

4.2 注意事项

4.2.1 配置注意事项

uid 1000 权限问题:这是新手踩得最多的坑。OpenClaw 容器以 node 用户(uid 1000)运行,如果宿主机目录的 owner 不是 1000,容器内写入会报 EACCES: permission denied

# 修复权限(Docker 方案)
sudo chown -R 1000:1000 ./config ./workspace

# K8s 方案通过 fsGroup 自动处理
# spec.securityContext.fsGroup: 1000

bind 地址配置:容器内必须 bind 0.0.0.0,别写 127.0.0.1。写 127.0.0.1 只能容器内部访问,外部请求过来全是 connection refused。这个错误在日志里不会报错,排查起来很头疼。

配置热重载:OpenClaw 目前不支持配置文件热重载,修改 openclaw.json 后需要重启服务才能生效。K8s 环境下 kubectl rollout restart deployment/openclaw-gateway -n openclaw 就行,Docker 环境 docker compose restart openclaw-gateway

4.2.2 常见错误

错误现象

原因分析

解决方案

EACCES: permission denied

 启动失败

挂载目录 owner 不是 uid 1000

chown -R 1000:1000

 挂载目录,或 K8s 设置 fsGroup: 1000

connect ECONNREFUSED 127.0.0.1:8000

Gateway 无法连接 vLLM

检查 vLLM Service 是否 Ready,检查 baseUrl 地址是否正确

/healthz

 返回 200 但 /readyz 返回 503

Gateway 启动了但后端模型不可用

等待 vLLM Pod Ready,或检查 Provider 配置中的 baseUrl

401 Unauthorized

请求 Token 和配置的 Token 不一致

检查 Authorization: Bearer <token> 头,和 gateway.auth.token 对比

Pod 状态 CrashLoopBackOff

容器反复崩溃重启

kubectl logs <pod-name> --previous

 查看崩溃前日志

vLLM Pod OOMKilled

GPU 显存或系统内存不足

降低 gpu-memory-utilization,或增加 GPU 数量 / 减小 max-model-len

Ingress 返回 504 Gateway Timeout

大模型推理超时

增加 proxy-read-timeout 到 3600+,检查 vLLM 是否过载

vLLM 日志 torch.cuda.OutOfMemoryError

KV Cache 不够分

降低 max-num-seqs 或 max-model-len,增加 GPU 显存

4.2.3 兼容性问题
  • Docker Compose V1 vs V2:OpenClaw 的 docker-compose.yml 使用了 deploy.resources.reservations.devices 语法(GPU 声明),只有 Docker Compose V2 支持。V1 的 docker-compose 命令会报语法错误。用 docker compose(没有横杠)确认是 V2。

  • K8s 版本兼容:Ingress API networking.k8s.io/v1 从 K8s 1.19 开始稳定,1.22 移除了 extensions/v1beta1。如果集群版本低于 1.19,需要改用旧 API 版本。

  • NVIDIA Device Plugin:K8s 使用 GPU 需要安装 NVIDIA Device Plugin DaemonSet。没装的话 Pod 的 nvidia.com/gpu 资源请求永远无法满足,Pod 会一直 Pending。

    # 检查 Device Plugin 是否安装
    kubectl get ds -n kube-system | grep nvidia
    
    # 如果没有,安装
    kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.17.0/deployments/static/nvidia-device-plugin.yml
    
  • Container Runtime:containerd 1.7+ 和 Docker 24+ 都支持 GPU 直通。CRI-O 需要额外配置 nvidia-container-runtime。


五、故障排查和监控

5.1 故障排查

5.1.1 日志查看
# K8s 环境:查看 Gateway 日志
kubectl logs -f -l app=openclaw,component=gateway -n openclaw

# K8s 环境:查看 vLLM 日志
kubectl logs -f -l app=openclaw,component=vllm -n openclaw

# K8s 环境:查看崩溃前的日志(Pod 重启后之前的日志会丢失)
kubectl logs <pod-name> -n openclaw --previous

# Docker 环境:查看实时日志
docker compose logs -f openclaw-gateway
docker compose logs -f vllm

# 容器内日志路径(如果需要进容器看)
# OpenClaw: /home/node/.openclaw/logs/
# vLLM: 标准输出(无文件日志,靠容器日志驱动收集)

# 过滤错误日志
kubectl logs -l component=gateway -n openclaw | grep -i "error\|fatal\|exception"
5.1.2 常见问题排查

问题一:Gateway Pod 状态 Pending,无法调度

# 诊断:查看 Pod 事件
kubectl describe pod -l component=gateway -n openclaw | tail -20

# 常见原因
# 1. PVC 无法绑定(storageClassName 不存在)
kubectl get pvc -n openclaw
kubectl get storageclass

# 2. 资源不足(CPU/内存不够)
kubectl describe nodes | grep -A 5 "Allocated resources"

# 3. nodeSelector 不匹配
kubectl get nodes --show-labels

解决方案

  1. PVC Pending → 检查 StorageClass 是否存在,是否有可用 PV。云环境检查 CSI Driver 是否正常

  2. 资源不足 → 降低 resource requests,或扩容节点

  3. nodeSelector 不匹配 → kubectl label node <node-name> gpu-type=a100

问题二:vLLM Pod OOMKilled

# 诊断:查看 Pod 终止原因
kubectl get pod -l component=vllm -n openclaw -o jsonpath='{.items[0].status.containerStatuses[0].lastState.terminated.reason}'

# 查看节点内存使用
kubectl top nodes

# 查看 Pod 内存使用趋势
kubectl top pod -l component=vllm -n openclaw

解决方案

  1. 系统内存 OOM → 增加 Pod memory limit,确保节点物理内存充足(建议 4 倍 GPU 显存)

  2. GPU 显存 OOM → 降低 gpu-memory-utilization 到 0.85,减小 max-model-len,或增加 tensor-parallel-size

  3. /dev/shm 不足 → 确认 emptyDir 的 sizeLimit 足够大(建议 16Gi+)

问题三:Token 认证失败,返回 401

# 诊断:确认配置的 Token 值
kubectl get secret openclaw-secrets -n openclaw -o jsonpath='{.data.gateway-token}' | base64 -d

# 确认 ConfigMap 中的占位符已被替换
kubectl exec -it <gateway-pod> -n openclaw -- cat /home/node/.openclaw/openclaw.json | grep token

# 测试请求
curl -v -H "Authorization: Bearer <token>" http://localhost:18789/healthz

解决方案

  1. 确认请求头格式:Authorization: Bearer <token>,注意 Bearer 后面有空格

  2. 确认 initContainer 的 sed 替换逻辑正确执行了(查看 initContainer 日志)

  3. 如果 Secret 更新了但 Pod 没重启,Token 不会自动生效。执行 kubectl rollout restart deployment/openclaw-gateway -n openclaw

5.1.3 调试模式
# OpenClaw 开启 debug 日志
# 方法一:环境变量
kubectl set env deployment/openclaw-gateway -n openclaw DEBUG=openclaw:*

# 方法二:修改 ConfigMap 中的 logging.level
kubectl edit configmap openclaw-config -n openclaw
# 将 "level": "info" 改为 "level": "debug"
# 然后重启
kubectl rollout restart deployment/openclaw-gateway -n openclaw

# vLLM 开启详细日志
# 在 args 中添加 --log-level=debug
kubectl edit deployment/vllm-inference -n openclaw

# 进入容器交互式调试
kubectl exec -it <gateway-pod> -n openclaw -- /bin/bash
# 容器内检查网络连通性
curl -s http://vllm-service:8000/health
# 容器内查看进程状态
ps aux
# 容器内查看内存使用
node -e "console.log(process.memoryUsage())"

5.2 性能监控

5.2.1 关键指标监控
# Gateway 基础监控
# CPU 使用率
kubectl top pod -l component=gateway -n openclaw

# 内存使用
kubectl top pod -l component=gateway -n openclaw

# 网络连接数(进入容器内查看)
kubectl exec -it <gateway-pod> -n openclaw -- ss -s

# vLLM 推理性能指标(vLLM 内置 metrics 端点)
curl -s http://vllm-service:8000/metrics

# 关键 vLLM 指标
curl -s http://vllm-service:8000/metrics | grep -E "vllm:num_requests|vllm:gpu_cache|vllm:avg_generation"
5.2.2 监控指标说明

指标名称

正常范围

告警阈值

说明

Gateway CPU 使用率

10-40%

>70%

Node.js 单线程,持续高 CPU 说明事件循环阻塞

Gateway 内存使用

200-800MB

>1.5GB

接近 limit 时有 OOM 风险

Gateway 请求延迟 P95

100-500ms

>2000ms

不含模型推理时间,纯网关转发延迟

Gateway 活跃连接数

0-500

>1000

WebSocket 长连接场景下可能较高

vLLM GPU 利用率

60-90%

>95%

持续 95%+ 说明需要扩容

vLLM KV Cache 使用率

40-80%

>90%

超 90% 新请求会排队等待

vLLM 请求队列长度

0-20

>50

队列积压说明推理速度跟不上请求速度

vLLM 生成速率

30-50 tokens/s/req

<10 tokens/s

低于 10 说明 GPU 资源不足或 batch 配置有问题

5.2.3 Prometheus 监控告警配置
# prometheus-rules.yaml
apiVersion:monitoring.coreos.com/v1
kind:PrometheusRule
metadata:
name:openclaw-alerts
namespace:openclaw
labels:
    release:prometheus
spec:
groups:
    -name:openclaw-gateway
      rules:
        # Gateway Pod 挂了
        -alert:OpenClawGatewayDown
          expr:up{job="openclaw-gateway"}==0
          for:1m
          labels:
            severity:critical
          annotations:
            summary:"OpenClaw Gateway 实例不可用"
            description:"{{ $labels.pod }} 已停止响应超过 1 分钟"

        # Gateway 内存使用过高
        -alert:OpenClawGatewayHighMemory
          expr:|
            container_memory_working_set_bytes{namespace="openclaw", container="gateway"}
            / container_spec_memory_limit_bytes{namespace="openclaw", container="gateway"}
            > 0.85
          for:5m
          labels:
            severity:warning
          annotations:
            summary:"OpenClaw Gateway 内存使用超过 85%"
            description:"{{ $labels.pod }} 内存使用 {{ $value | humanizePercentage }}"

        # Gateway 重启次数过多
        -alert:OpenClawGatewayRestarts
          expr:|
            increase(kube_pod_container_status_restarts_total{
              namespace="openclaw", container="gateway"
            }[1h]) > 3
          labels:
            severity:warning
          annotations:
            summary:"OpenClaw Gateway 1 小时内重启超过 3 次"

    -name:openclaw-vllm
      rules:
        # vLLM GPU 显存使用过高
        -alert:VllmGpuMemoryHigh
          expr:|
            vllm:gpu_cache_usage_perc > 0.90
          for:10m
          labels:
            severity:warning
          annotations:
            summary:"vLLM GPU KV Cache 使用率超过 90%"
            description:"KV Cache 使用率 {{ $value | humanizePercentage }},新请求可能排队"

        # vLLM 请求队列积压
        -alert:VllmQueueBacklog
          expr:|
            vllm:num_requests_waiting > 50
          for:5m
          labels:
            severity:warning
          annotations:
            summary:"vLLM 请求队列积压超过 50"
            description:"等待处理的请求数: {{ $value }}"

        # vLLM 推理延迟过高
        -alert:VllmHighLatency
          expr:|
            histogram_quantile(0.95,
              rate(vllm:e2e_request_latency_seconds_bucket[5m])
            ) > 30
          for:5m
          labels:
            severity:warning
          annotations:
            summary:"vLLM P95 推理延迟超过 30 秒"

Prometheus ServiceMonitor 配置(需要 Prometheus Operator):

# servicemonitor.yaml
apiVersion:monitoring.coreos.com/v1
kind:ServiceMonitor
metadata:
name:vllm-metrics
namespace:openclaw
labels:
    release:prometheus
spec:
selector:
    matchLabels:
      component:vllm
endpoints:
    -port:http
      path:/metrics
      interval:15s

5.3 备份与恢复

5.3.1 备份策略

需要备份的数据:

  1. openclaw.json 配置文件(ConfigMap 已版本化,但建议额外备份)

  2. Gateway 工作空间数据(PVC)

  3. K8s 资源定义(YAML 文件)

  4. Secret(Token、API Key)

#!/bin/bash
# backup-openclaw.sh - OpenClaw 备份脚本
# 建议通过 CronJob 每天执行一次

BACKUP_DIR="/backup/openclaw/$(date +%Y%m%d)"
NAMESPACE="openclaw"

mkdir -p "${BACKUP_DIR}"

# 1. 备份 ConfigMap
kubectl get configmap openclaw-config -n ${NAMESPACE} -o yaml > "${BACKUP_DIR}/configmap.yaml"

# 2. 备份 Secret(加密存储)
kubectl get secret openclaw-secrets -n ${NAMESPACE} -o yaml > "${BACKUP_DIR}/secret.yaml.enc"
# 生产环境用 age/sops 加密
# sops --encrypt "${BACKUP_DIR}/secret.yaml" > "${BACKUP_DIR}/secret.yaml.enc"

# 3. 备份所有 K8s 资源定义
kubectl get all,configmap,secret,pvc,ingress,networkpolicy -n ${NAMESPACE} -o yaml > "${BACKUP_DIR}/all-resources.yaml"

# 4. 备份 PVC 数据(需要 Velero 或手动快照)
# 云环境使用 VolumeSnapshot
kubectl apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: openclaw-data-snapshot-$(date +%Y%m%d)
  namespace: ${NAMESPACE}
spec:
  volumeSnapshotClassName: csi-snapclass
source:
    persistentVolumeClaimName: openclaw-data
EOF

echo"Backup completed: ${BACKUP_DIR}"
# 清理 30 天前的备份
find /backup/openclaw -maxdepth 1 -mtime +30 -type d -exec rm -rf {} \;
5.3.2 恢复流程
# 1. 停止现有服务
kubectl scale deployment openclaw-gateway -n openclaw --replicas=0

# 2. 恢复配置
kubectl apply -f /backup/openclaw/20260313/configmap.yaml
kubectl apply -f /backup/openclaw/20260313/secret.yaml

# 3. 恢复 PVC 数据(从 VolumeSnapshot)
kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: openclaw-data
  namespace: openclaw
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: standard
  resources:
    requests:
      storage: 10Gi
  dataSource:
    name: openclaw-data-snapshot-20260313
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
EOF

# 4. 重新启动服务
kubectl scale deployment openclaw-gateway -n openclaw --replicas=2

# 5. 验证恢复结果
kubectl wait --for=condition=ready pod -l component=gateway -n openclaw --timeout=120s
curl -s http://localhost:18789/healthz

六、总结

6.1 技术要点回顾

  • Docker 方案快速启动docker-setup.sh 一键部署,适合开发测试。docker-compose.yml 管理服务依赖和健康检查,比裸 docker run 更可控。核心配置就一个 openclaw.json(JSON5 格式),改完重启即可。

  • K8s 方案生产就绪:Deployment + Service + Ingress 三件套,配合 ConfigMap/Secret 管理配置和敏感信息。initContainer 解决 ConfigMap 只读问题,securityContext 解决 uid 1000 权限问题。三种探针(startup/liveness/readiness)保证服务可靠性。

  • vLLM 推理后端:tensor-parallel 多卡并行,/dev/shm 共享内存必须挂载,initialDelaySeconds 要给够(120s+)。gpu-memory-utilization=0.90 是安全值,别贪心设 0.95。

  • 多租户隔离:Namespace + NetworkPolicy + RBAC + ResourceQuota 四层隔离。NetworkPolicy 默认拒绝跨 Namespace 流量,RBAC 限制管理权限,ResourceQuota 防止资源争抢。每个部门独立 Token,独立 vLLM 实例。

  • 安全加固:Token 定期轮换(建议 90 天),NetworkPolicy 最小权限,TLS 全链路加密。Secret 的 RBAC 权限严格控制,别给 get 权限只给 list

  • 监控告警:Gateway 关注 CPU、内存、连接数;vLLM 关注 GPU Cache 使用率、请求队列长度、生成速率。Prometheus + ServiceMonitor 采集指标,PrometheusRule 配置告警。

6.2 进阶学习方向

  1. Service Mesh 集成:用 Istio 或 Linkerd 实现集群内部 mTLS、流量镜像、金丝雀发布。OpenClaw Gateway 的多副本可以利用 Istio 的加权路由实现灰度更新,新版本先承接 10% 流量,验证稳定后逐步扩大。

    • 实践建议:先在测试环境部署 Istio,给 openclaw namespace 打上 istio-injection=enabled 标签,观察 sidecar 注入后的性能影响。

  2. GitOps 持续交付:用 ArgoCD 或 Flux 管理 OpenClaw 的 K8s 资源定义,配置变更通过 Git PR 审批,自动同步到集群。ConfigMap 变更自动触发 Deployment 滚动更新,告别手动 kubectl apply

    • 实践建议:把 openclaw-all-in-one.yaml 拆分成独立文件放进 Git 仓库,ArgoCD Application 指向仓库路径,开启自动同步。

  3. 多集群联邦部署:使用 KubeFed 或 Karmada 实现跨集群部署,不同区域的用户请求路由到就近的 OpenClaw 实例。GPU 资源池跨集群调度,提升利用率。

    • 实践建议:先实现两个集群的同配置部署,DNS 层做地域路由(AWS Route53 Geolocation / Cloudflare Load Balancing),再考虑联邦管理。

6.3 参考资料

  • OpenClaw 官方文档 - 项目源码和官方 Docker 部署指南

  • vLLM 官方文档 - vLLM 部署配置和性能调优参考

  • Kubernetes 官方文档 - NetworkPolicy - 网络策略配置详解

  • NVIDIA GPU Operator - K8s GPU 资源管理和驱动自动化

  • Qwen3.5 模型卡 - 模型规格、硬件需求和推理配置


附录

A. 命令速查表

# ========== Docker 方案 ==========
docker compose up -d                                  # 启动所有服务
docker compose down                                   # 停止所有服务
docker compose logs -f openclaw-gateway               # 查看 Gateway 日志
docker compose restart openclaw-gateway               # 重启 Gateway
docker compose ps                                     # 查看服务状态
docker compose exec openclaw-gateway /bin/bash        # 进入 Gateway 容器
curl -s http://localhost:18789/healthz                 # 健康检查
curl -s http://localhost:18789/readyz                  # 就绪检查

# ========== K8s 方案 ==========
kubectl apply -f openclaw-all-in-one.yaml              # 一键部署
kubectl get all -n openclaw                            # 查看所有资源
kubectl logs -f -l component=gateway -n openclaw       # 查看 Gateway 日志
kubectl logs -f -l component=vllm -n openclaw          # 查看 vLLM 日志
kubectl rollout restart deploy/openclaw-gateway -n openclaw  # 重启 Gateway
kubectl rollout status deploy/openclaw-gateway -n openclaw   # 查看滚动更新状态
kubectl port-forward svc/openclaw-gateway 18789:18789 -n openclaw  # 端口转发
kubectl top pod -n openclaw                            # 查看资源使用
kubectl describe pod <pod-name> -n openclaw            # 查看 Pod 详情
kubectl exec -it <pod-name> -n openclaw -- /bin/bash   # 进入容器

# ========== 调试命令 ==========
kubectl run debug-curl --rm -it --image=curlimages/curl -n openclaw -- sh  # 启动调试 Pod
kubectl get events -n openclaw --sort-by='.lastTimestamp'                   # 查看事件(按时间排序)
kubectl get pvc -n openclaw                            # 查看存储卷状态
kubectl get networkpolicy -n openclaw                  # 查看网络策略

# ========== Token 管理 ==========
openssl rand -hex 32                                   # 生成随机 Token
kubectl get secret openclaw-secrets -n openclaw -o jsonpath='{.data.gateway-token}' | base64 -d  # 查看当前 Token

B. 配置参数详解

openclaw.json 核心参数

参数路径

类型

默认值

说明

gateway.bind

string

"0.0.0.0:18789"

网关监听地址,格式 host:port

gateway.auth.token

string

-

Gateway 认证 Token,必填

gateway.rateLimit.maxRequestsPerMinute

number

600

全局每分钟最大请求数

gateway.rateLimit.maxRequestsPerMinutePerToken

number

60

单 Token 每分钟最大请求数

models.default

string

-

默认模型,格式 provider/model

models.providers.<name>.baseUrl

string

-

推理后端 API 地址

models.providers.<name>.api

string

"openai-responses"

API 兼容模式

models.providers.<name>.apiKey

string

-

后端 API Key(自托管可不填)

models.providers.<name>.models

array

[]

该 Provider 支持的模型列表

logging.level

string

"info"

日志级别:debug/info/warn/error

logging.format

string

"json"

日志格式:json/text

vLLM 关键启动参数

参数

默认值

推荐值

说明

--model

-

-

模型名称或路径,必填

--tensor-parallel-size 1

按 GPU 数量设置

张量并行度,等于使用的 GPU 数量

--max-model-len

模型默认值

32768

最大序列长度,影响 KV Cache 大小

--gpu-memory-utilization 0.90 0.85-0.90

GPU 显存利用率上限

--block-size 16 16

KV Cache 块大小(tokens/block)

--max-num-seqs 256 64-128

同时处理的最大序列数

--max-num-batched-tokens 32768 32768

单批次最大 token 数

--swap-space 4 8

CPU swap 空间大小(GiB)

--dtype auto auto

计算精度,FP8 模型用 auto 即可

--enable-chunked-prefill false true

分块预填充,降低长 prompt 延迟

--trust-remote-code false true

允许执行模型仓库的自定义代码

C. 术语表

术语

英文

解释

AI Agent Gateway

AI Agent Gateway

AI 代理网关,负责多渠道消息接入、认证、模型路由和协议转换

Provider

Provider

模型提供方,在 OpenClaw 中指一个推理后端配置(包含 baseUrl 和模型列表)

KV Cache

Key-Value Cache

大模型推理过程中缓存的注意力机制键值对,占用 GPU 显存

Tensor Parallel

Tensor Parallelism

张量并行,将模型参数切分到多张 GPU 上并行计算

PagedAttention

Paged Attention

vLLM 的核心技术,将 KV Cache 按页管理,提升显存利用率

Continuous Batching

Continuous Batching

连续批处理,动态将新请求加入正在处理的批次,提升吞吐量

PDB

Pod Disruption Budget

Pod 中断预算,限制同时不可用的 Pod 数量

HPA

Horizontal Pod Autoscaler

水平 Pod 自动扩缩容器

NetworkPolicy

Network Policy

K8s 网络策略,控制 Pod 间的网络流量

RBAC

Role-Based Access Control

基于角色的访问控制

ConfigMap

ConfigMap

K8s 配置映射,存储非敏感配置数据

Secret

Secret

K8s 密钥对象,存储敏感数据(Token、密码等)

JSON5

JSON5

JSON 的超集,支持注释、尾逗号、单引号等语法

D. 端口清单

服务

端口

协议

用途

暴露方式

OpenClaw Gateway

18789

HTTP + WebSocket

API 网关入口(认证、路由、协议转换)

Ingress / NodePort 31789

vLLM Inference

8000

HTTP

OpenAI 兼容 API(推理服务)

ClusterIP(仅集群内部)

vLLM Metrics

8000

HTTP

Prometheus 指标端点(/metrics)

ClusterIP(Prometheus 抓取)

Prometheus

9090

HTTP

监控数据查询

按需暴露

Grafana

3000

HTTP

监控面板

按需暴露

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐