OpenClaw 一键安装最佳实践
通过 Jenkins 自动部署到 K8S 集群
📋 目录
- 前置准备
- 环境要求
- 资源准备
- Jenkins 流水线配置
- K8S 部署配置
- 一键安装脚本
- 验证与测试
- 故障排查
🚨 前置准备
1. 环境检查清单
2. 权限准备
💻 环境要求
硬件要求
| 组件 |
CPU |
内存 |
存储 |
| K8S 集群 |
4 核 + |
8GB+ |
50GB+ |
| Jenkins |
2 核 + |
4GB+ |
20GB+ |
| OpenClaw |
2 核 + |
4GB+ |
10GB+ |
软件要求
| 软件 |
版本 |
说明 |
| Kubernetes |
v1.20+ |
K8S 集群 |
| Jenkins |
v2.553+ |
CI/CD 平台 |
| Docker |
v20.10+ |
容器引擎 |
| kubectl |
v1.20+ |
K8S 命令行工具 |
| Helm |
v3.0+ |
K8S 包管理(可选) |
| Git |
v2.30+ |
版本控制 |
📦 资源准备
1. GitLab 仓库结构
1 2 3 4 5 6 7 8
| openclaw/ ├── openclaw-core/ # 核心代码 ├── openclaw-gateway/ # 网关服务 ├── openclaw-agent/ # Agent 服务 ├── openclaw-ui/ # 前端界面 ├── k8s-manifests/ # K8S 部署配置 └── jenkins/ └── Jenkinsfile
|
2. Docker 镜像
1 2 3 4 5 6
| 镜像仓库:registry.example.com/openclaw 镜像列表: - openclaw-core:latest - openclaw-gateway:latest - openclaw-agent:latest - openclaw-ui:latest
|
🔧 Jenkins 流水线配置
Jenkinsfile
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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
| pipeline { agent any environment { KUBECONFIG = credentials('k8s-kubeconfig') DOCKER_REGISTRY = 'registry.example.com' DOCKER_IMAGE_PREFIX = 'openclaw' K8S_NAMESPACE = 'openclaw' } parameters { string(name: 'VERSION', defaultValue: 'latest', description: '部署版本') booleanParam(name: 'FORCE_REBUILD', defaultValue: false, description: '强制重新构建镜像') } stages { stage('Checkout') { steps { echo '📦 拉取代码...' git branch: 'main', url: 'https://gitlab.example.com/openclaw.git', credentialsId: 'gitlab-credentials' } } stage('Build & Push Images') { when { expression { return params.FORCE_REBUILD } } parallel { stage('Build Core') { steps { echo '🔨 构建 Core 镜像...' dir('openclaw-core') { sh """ docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-core:${VERSION} . docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-core:${VERSION} """ } } } stage('Build Gateway') { steps { echo '🔨 构建 Gateway 镜像...' dir('openclaw-gateway') { sh """ docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-gateway:${VERSION} . docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-gateway:${VERSION} """ } } } stage('Build Agent') { steps { echo '🔨 构建 Agent 镜像...' dir('openclaw-agent') { sh """ docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-agent:${VERSION} . docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-agent:${VERSION} """ } } } stage('Build UI') { steps { echo '🔨 构建 UI 镜像...' dir('openclaw-ui') { sh """ docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-ui:${VERSION} . docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-ui:${VERSION} """ } } } } } stage('Deploy to K8S') { steps { echo '🚀 部署到 K8S 集群...' script { sh """ kubectl apply -f k8s-manifests/openclaw-namespace.yaml """ sh """ kubectl create secret generic openclaw-db-secret \\ --from-literal=root-password='<DB_ROOT_PASSWORD>' \\ --from-literal=username='<DB_USERNAME>' \\ --from-literal=password='<DB_PASSWORD>' \\ -n ${K8S_NAMESPACE} \\ --dry-run=client -o yaml | kubectl apply -f - """ sh """ kubectl apply -f k8s-manifests/ -n ${K8S_NAMESPACE} """ sh """ kubectl set image deployment/openclaw-core \\ openclaw-core=${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-core:${VERSION} \\ -n ${K8S_NAMESPACE} kubectl set image deployment/openclaw-gateway \\ openclaw-gateway=${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-gateway:${VERSION} \\ -n ${K8S_NAMESPACE} kubectl set image deployment/openclaw-agent \\ openclaw-agent=${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-agent:${VERSION} \\ -n ${K8S_NAMESPACE} kubectl set image deployment/openclaw-ui \\ openclaw-ui=${DOCKER_REGISTRY}/${DOCKER_IMAGE_PREFIX}/openclaw-ui:${VERSION} \\ -n ${K8S_NAMESPACE} """ } } } stage('Health Check') { steps { echo '⏳ 等待部署完成...' script { timeout(time: 5, unit: 'MINUTES') { sh """ kubectl rollout status deployment/openclaw-core -n ${K8S_NAMESPACE} kubectl rollout status deployment/openclaw-gateway -n ${K8S_NAMESPACE} kubectl rollout status deployment/openclaw-agent -n ${K8S_NAMESPACE} kubectl rollout status deployment/openclaw-ui -n ${K8S_NAMESPACE} """ } } echo '✅ 健康检查...' script { timeout(time: 2, unit: 'MINUTES') { sh """ kubectl wait --for=condition=available deployment/openclaw-gateway -n ${K8S_NAMESPACE} --timeout=120s """ } } } } } post { success { echo '✅ 部署成功!' sh """ NODE_PORT=\$(kubectl get svc openclaw-gateway -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[0].nodePort}') NODE_IP=\$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}') echo "====================================" echo "✅ OpenClaw 部署成功!" echo "====================================" echo "访问地址:http://\\${NODE_IP}:\\${NODE_PORT}" echo "====================================" """ } failure { echo '❌ 部署失败!' sh """ echo "=== Core Logs ===" kubectl logs -l app=openclaw-core -n ${K8S_NAMESPACE} --tail=50 echo "=== Gateway Logs ===" kubectl logs -l app=openclaw-gateway -n ${K8S_NAMESPACE} --tail=50 echo "=== Agent Logs ===" kubectl logs -l app=openclaw-agent -n ${K8S_NAMESPACE} --tail=50 """ } } }
|
📝 一键安装脚本
install-openclaw.sh
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
| #!/bin/bash set -e
echo "======================================" echo " OpenClaw 一键安装脚本" echo "======================================"
K8S_NAMESPACE="openclaw" DOCKER_REGISTRY="registry.example.com" DOCKER_IMAGE_PREFIX="openclaw" VERSION="latest"
RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m'
check_prerequisites() { echo -e "${YELLOW}📋 检查前置条件...${NC}" if ! command -v kubectl &> /dev/null; then echo -e "${RED}❌ kubectl 未安装${NC}" exit 1 fi if ! kubectl cluster-info &> /dev/null; then echo -e "${RED}❌ 无法连接到 K8S 集群${NC}" exit 1 fi if ! command -v docker &> /dev/null; then echo -e "${RED}❌ Docker 未安装${NC}" exit 1 fi echo -e "${GREEN}✅ 前置检查通过${NC}" }
create_namespace() { echo -e "${YELLOW}📦 创建命名空间...${NC}" kubectl create namespace ${K8S_NAMESPACE} --dry-run=client -o yaml | kubectl apply -f - echo -e "${GREEN}✅ 命名空间创建完成${NC}" }
create_secrets() { echo -e "${YELLOW}🔐 创建 Secrets...${NC}" kubectl create secret generic openclaw-db-secret \\ --from-literal=root-password='<DB_ROOT_PASSWORD>' \\ --from-literal=username='<DB_USERNAME>' \\ --from-literal=password='<DB_PASSWORD>' \\ -n ${K8S_NAMESPACE} \\ --dry-run=client -o yaml | kubectl apply -f - echo -e "${GREEN}✅ Secrets 创建完成${NC}" }
deploy_k8s() { echo -e "${YELLOW}🚀 部署 K8S 资源...${NC}" kubectl apply -f k8s-manifests/ -n ${K8S_NAMESPACE} echo -e "${GREEN}✅ K8S 资源部署完成${NC}" }
wait_deployment() { echo -e "${YELLOW}⏳ 等待部署完成...${NC}" kubectl rollout status deployment/openclaw-core -n ${K8S_NAMESPACE} kubectl rollout status deployment/openclaw-gateway -n ${K8S_NAMESPACE} kubectl rollout status deployment/openclaw-agent -n ${K8S_NAMESPACE} kubectl rollout status deployment/openclaw-ui -n ${K8S_NAMESPACE} echo -e "${GREEN}✅ 所有部署完成${NC}" }
health_check() { echo -e "${YELLOW}⏳ 执行健康检查...${NC}" sleep 10 kubectl get pods -n ${K8S_NAMESPACE} kubectl get svc -n ${K8S_NAMESPACE} echo -e "${GREEN}✅ 健康检查通过${NC}" }
get_access_info() { echo -e "${YELLOW}📊 获取访问信息...${NC}" NODE_PORT=$(kubectl get svc openclaw-gateway -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[0].nodePort}') NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}') echo "" echo -e "${GREEN}======================================" echo " ✅ OpenClaw 部署成功!" echo "======================================${NC}" echo "访问地址:http://${NODE_IP}:${NODE_PORT}" echo "命名空间:${K8S_NAMESPACE}" echo "======================================" echo "" }
main() { check_prerequisites create_namespace create_secrets deploy_k8s wait_deployment health_check get_access_info echo -e "${GREEN}🎉 安装完成!${NC}" }
main "$@"
|
✅ 验证与测试
1. 检查 Pod 状态
1
| kubectl get pods -n openclaw
|
预期输出:
1 2 3 4 5 6
| NAME READY STATUS RESTARTS AGE openclaw-core-xxxxx-xxxxx 1/1 Running 0 5m openclaw-gateway-xxxxx-xxxxx 1/1 Running 0 5m openclaw-agent-xxxxx-xxxxx 1/1 Running 0 5m openclaw-ui-xxxxx-xxxxx 1/1 Running 0 5m mysql-xxxxx-xxxxx 1/1 Running 0 5m
|
2. 检查服务状态
1
| kubectl get svc -n openclaw
|
预期输出:
1 2 3 4 5
| NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE openclaw-core ClusterIP 10.x.x.x <none> 80/TCP 5m openclaw-gateway NodePort 10.x.x.x <none> 80:32080/TCP 5m openclaw-agent ClusterIP 10.x.x.x <none> 5000/TCP 5m mysql ClusterIP 10.x.x.x <none> 3306/TCP 5m
|
3. 测试访问
1 2 3 4 5 6
| NODE_PORT=$(kubectl get svc openclaw-gateway -n openclaw -o jsonpath='{.spec.ports[0].nodePort}') NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}')
curl http://${NODE_IP}:${NODE_PORT}/health
|
预期输出:
1
| {"status":"ok","message":"OpenClaw Gateway is running"}
|
🔧 故障排查
问题 1:Pod 无法启动
症状:
1 2 3
| kubectl get pods -n openclaw NAME READY STATUS RESTARTS AGE openclaw-core-xxxxx-xxxxx 0/1 ImagePullBackOff 0 5m
|
解决方案:
1 2 3 4 5 6 7 8
| kubectl describe pod openclaw-core-xxxxx-xxxxx -n openclaw
kubectl get secrets -n openclaw
docker pull registry.example.com/openclaw/openclaw-core:latest
|
问题 2:数据库连接失败
症状:
1
| Error: connect ECONNREFUSED 10.x.x.x:3306
|
解决方案:
1 2 3 4 5 6 7 8 9
| kubectl get pods -l app=mysql -n openclaw
kubectl logs -l app=mysql -n openclaw
kubectl run -it --rm mysql-client --image=mysql:8.0 --restart=Never -n openclaw -- \\ mysql -h mysql -u <DB_USERNAME> -p
|
问题 3:服务无法访问
症状:
1
| curl: (7) Failed to connect to <IP> port <PORT>: Connection refused
|
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12
| kubectl get svc openclaw-gateway -n openclaw -o yaml
kubectl get endpoints openclaw-gateway -n openclaw
kubectl get pods --show-labels -n openclaw
kubectl run -it --rm test --image=curlimages/curl --restart=Never -n openclaw -- \\ curl http://openclaw-gateway/health
|
📖 参考链接
架构师点评:一键安装只是起点,生产化才是重点
OpenClaw 这类 Agent 平台跑在 K8s 上,安装成功只能说明“组件启动了”,不能说明“平台可生产使用”。生产化部署至少要补齐配置治理、密钥管理、网络访问、持久化、监控告警、备份恢复、灰度升级和权限审计。否则一键安装越方便,越容易让团队忽略后续治理成本。
生产部署时要特别关注:
- 配置与密钥:数据库、模型 API、Feishu/GitLab/Jenkins 等凭证必须用 Secret/External Secrets 管理,不能散落在脚本中。
- 数据持久化:记忆、日志、向量库、任务状态和用户配置要明确备份策略。
- 网络边界:Agent 能访问哪些内部系统、外部 API 和文件路径,必须通过网关和策略控制。
- 升级回滚:镜像版本、数据库迁移、配置变更要支持灰度和快速回滚。
- 运行时审计:工具调用、命令执行、权限拒绝、人工审批都要可追溯。
企业落地建议
推荐把 OpenClaw K8s 部署拆成三层交付:
- 开发验证环境:快速安装,验证 Agent 能力、工具接入和业务流程。
- 预生产环境:补齐监控、日志、备份、权限和发布流程,模拟真实业务负载。
- 生产环境:引入高可用、灰度发布、审计合规、容量规划和应急预案。
如果企业计划把 OpenClaw 用于 AI Coding、PR 审查、知识库问答或自动化运维,建议先从一个低风险流程试点,再逐步扩大工具权限和自动化范围。
相关入口:
一键安装,自动部署,快速上线!🚀
提示:实际部署时请将 <DB_ROOT_PASSWORD>、<DB_USERNAME>、<DB_PASSWORD> 等占位符替换为真实配置。