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
|
📖 参考链接
一键安装,自动部署,快速上线!🚀
提示:实际部署时请将 <DB_ROOT_PASSWORD>、<DB_USERNAME>、<DB_PASSWORD> 等占位符替换为真实配置。