0%

OpenClaw 一键安装最佳实践

OpenClaw 一键安装最佳实践

通过 Jenkins 自动部署到 K8S 集群

📋 目录

  1. 前置准备
  2. 环境要求
  3. 资源准备
  4. Jenkins 流水线配置
  5. K8S 部署配置
  6. 一键安装脚本
  7. 验证与测试
  8. 故障排查

🚨 前置准备

1. 环境检查清单

  • K8S 集群可用(v1.20+)
  • Jenkins 已安装(v2.553+)
  • GitLab 已配置
  • Docker 镜像仓库可用
  • kubectl 已安装并配置
  • Helm v3(可选)

2. 权限准备

  • K8S ServiceAccount(部署权限)
  • Jenkins K8S 凭证
  • GitLab API Token
  • Docker Registry 凭证

💻 环境要求

硬件要求

组件 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
"""

// 创建 Secrets(使用 Kubernetes Secrets 管理敏感信息)
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' # No Color

# 检查前置条件
check_prerequisites() {
echo -e "${YELLOW}📋 检查前置条件...${NC}"

# 检查 kubectl
if ! command -v kubectl &> /dev/null; then
echo -e "${RED}❌ kubectl 未安装${NC}"
exit 1
fi

# 检查 K8S 连接
if ! kubectl cluster-info &> /dev/null; then
echo -e "${RED}❌ 无法连接到 K8S 集群${NC}"
exit 1
fi

# 检查 Docker
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}"
}

# 创建 Secrets
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}"
}

# 部署 K8S 资源
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
# 获取 NodePort
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
# 检查 Pod 事件
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
# 检查 MySQL Pod
kubectl get pods -l app=mysql -n openclaw

# 检查 MySQL 日志
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
# 检查 Service 配置
kubectl get svc openclaw-gateway -n openclaw -o yaml

# 检查 Endpoint
kubectl get endpoints openclaw-gateway -n openclaw

# 检查 Pod 标签是否匹配
kubectl get pods --show-labels -n openclaw

# 测试集群内访问
kubectl run -it --rm test --image=curlimages/curl --restart=Never -n openclaw -- \\
curl http://openclaw-gateway/health

📖 参考链接


一键安装,自动部署,快速上线!🚀

提示:实际部署时请将 <DB_ROOT_PASSWORD><DB_USERNAME><DB_PASSWORD> 等占位符替换为真实配置。