🚀 OpenClaw + GitHub Actions CI/CD 自动化部署指南

让AI Agent部署像点外卖一样简单 - 自动化才是正经事

📚 为什么要用 GitHub Actions 自动化部署 AI Agent?

话说江湖传闻,有个程序员每天手动部署OpenClaw,结果有一天他突然顿悟:"我这是在用AI,为啥还要手动干活?"

于是,GitHub Actions 降临了。它就像是给你的AI Agent请了个24小时不睡觉的管家,你只管写代码,剩下的事儿它全包了。

💡 妙趣金句:
"手动部署一时爽,一直手动一直爽?不不不,自动化才是真的爽!GitHub Actions让你从重复劳动中解脱,去做更有创造力的事情。"

🎯 核心价值

⏰ 时间就是生命

手动部署一次要15分钟?GitHub Actions让你喝口茶的功夫就搞定了。人生苦短,何必浪费在重复劳动上?

🎯 一致性保证

人总会犯错,但机器不会。每次部署都是标准化的流程,再也不用担心"在我机器上能跑"的尴尬。

🔄 快速迭代

push代码 → 自动测试 → 自动部署 → 自动通知。整个流程丝滑如德芙,让你专注在代码本身。

🛡️ 安全合规

自动执行安全扫描、代码审查、依赖检查。就像给你的Agent装了个24小时监控摄像头。

📊 可视化管理

每一次部署都有详细日志,出了问题秒定位。比查水表还清楚。

🌍 多环境支持

开发、测试、生产环境一键切换。就像切换电视频道一样简单(暴露年龄的比喻)。

🔄 典型 CI/CD 工作流

┌─────────────┐
│  开发者提交代码  │
│  (git push)  │
└──────┬──────┘
       │
       ▼
┌─────────────┐
│ GitHub Actions │
│  触发工作流    │
└──────┬──────┘
       │
       ├─▶ 代码检查 (Lint)
       ├─▶ 单元测试
       ├─▶ 构建 Docker 镜像
       ├─▶ 推送到镜像仓库
       ├─▶ 部署到环境
       └─▶ 发送通知
            

🛠️ 配置步骤详解

第一步:创建 GitHub Actions 工作流文件

在你的OpenClaw项目根目录下,创建 .github/workflows/deploy.yml 文件。这个文件就像是给你的AI Agent写的操作手册。

📁 目录结构

your-openclaw-project/
├── .github/
│   └── workflows/
│       └── deploy.yml    ← 这就是我们要创建的文件
├── Dockerfile
├── openclaw.json
└── skills/
                    

第二步:编写基础工作流配置

下面是一个基础的OpenClaw部署工作流配置,包含了从代码检查到部署的完整流程:

name: OpenClaw CI/CD Pipeline

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  DOCKER_REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: 设置 Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '22'
        cache: 'npm'
    
    - name: 安装依赖
      run: npm ci
    
    - name: 运行 Lint
      run: npm run lint
    
    - name: 运行测试
      run: npm test
    
    - name: 检查 OpenClaw 配置
      run: |
        npm install -g openclaw
        openclaw config validate

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v4
    
    - name: 登录到 GitHub Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.DOCKER_REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    
    - name: 构建 Docker 镜像
      run: |
        docker build -t ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest .
        docker tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
          ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
    
    - name: 推送 Docker 镜像
      run: |
        docker push ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
        docker push ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
                
⚠️ 注意:
记得在 GitHub 仓库的 Settings → Secrets and variables → Actions 中添加必要的 secrets,比如 GITHUB_TOKEN(通常自动提供)和其他敏感信息。

第三步:配置多环境部署

真实世界的部署通常有多个环境,让我们来配置一个完整的多环境部署策略:

  deploy-dev:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/develop'
    environment: development
    
    steps:
    - name: 部署到开发环境
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.DEV_SERVER_HOST }}
        username: ${{ secrets.DEV_SERVER_USER }}
        key: ${{ secrets.DEV_SERVER_SSH_KEY }}
        script: |
          cd /opt/openclaw
          docker-compose pull
          docker-compose up -d
          docker system prune -f
    
    - name: 健康检查
      run: |
        sleep 10
        curl -f http://${{ secrets.DEV_SERVER_HOST }}:3000/health || exit 1
    
    - name: 发送飞书通知
      if: always()
      uses: foxundermoon/feishu-action@v2
      with:
        url: ${{ secrets.FEISHU_WEBHOOK_URL }}
        msg_type: text
        content: |
          开发环境部署完成 ✅
          提交: ${{ github.sha }}
          作者: ${{ github.actor }}
          状态: ${{ job.status }}

  deploy-prod:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    
    steps:
    - name: 手动审批
      uses: trstringer/manual-approval@v1
      with:
        secret: ${{ github.TOKEN }}
        approvers: admin1,admin2
        minimum-approvals: 1
    
    - name: 部署到生产环境
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.PROD_SERVER_HOST }}
        username: ${{ secrets.PROD_SERVER_USER }}
        key: ${{ secrets.PROD_SERVER_SSH_KEY }}
        script: |
          cd /opt/openclaw
          docker-compose pull
          docker-compose up -d --no-deps openclaw
          docker system prune -f
    
    - name: 发送部署通知
      if: always()
      run: |
        curl -X POST ${{ secrets.DISCORD_WEBHOOK_URL }} \
          -H "Content-Type: application/json" \
          -d '{
            "embeds": [{
              "title": "🚀 OpenClaw 生产环境部署",
              "description": "部署完成",
              "color": 65280,
              "fields": [
                {"name": "版本", "value": "${{ github.sha }}", "inline": true},
                {"name": "状态", "value": "${{ job.status }}", "inline": true}
              ]
            }]
          }'
                

🏆 最佳实践

🎯 分支策略:Git Flow 的妙趣版

  • main 分支:生产环境专属,只接受来自 develop 的合并
  • develop 分支:开发主分支,所有新功能都从这里出发
  • feature/* 分支:功能开发分支,开发完成后合并回 develop
  • hotfix/* 分支:紧急修复分支,直接合并到 main 和 develop

🔐 环境管理:安全第一

使用 GitHub Environments

在 GitHub 仓库设置中配置 Environments(环境),可以:

  • 设置环境变量(加密存储)
  • 配置部署保护规则(必需审批)
  • 限制哪些分支可以部署到该环境
# 示例:在不同环境中使用不同的配置
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'development' }}
    
    steps:
    - name: 使用环境专属配置
      run: |
        echo "部署到 ${{ environment.name }} 环境"
        ./deploy.sh --env ${{ environment.name }}
      env:
        API_KEY: ${{ secrets.API_KEY }}
        DB_URL: ${{ secrets.DB_URL }}
                

🧪 自动测试:Quality First

测试是自动化的基石,没有测试的CI/CD就像没有调料的方便面——能吃,但没味儿。

  test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [18, 20, 22]
    
    steps:
    - uses: actions/checkout@v4
    
    - name: 使用 Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
    
    - name: 运行单元测试
      run: npm run test:unit
    
    - name: 运行集成测试
      run: npm run test:integration
      env:
        OPENCLAW_TEST_MODE: true
    
    - name: 运行 Skills 测试
      run: |
        npm install -g openclaw
        openclaw skills test --all
    
    - name: 上传测试报告
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: test-reports-${{ matrix.node-version }}
        path: |
          coverage/
          test-results/
                

🏷️ 版本自动标记:让版本管理飞起来

每次部署都手动打tag?太土了!让GitHub Actions自动帮你做:

  tag-version:
    needs: deploy-prod
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    
    - name: 生成版本号
      id: version
      run: |
        VERSION=$(date +'%Y.%m.%d')-${{ github.run_number }}
        echo "version=$VERSION" >> $GITHUB_OUTPUT
        echo "生成的版本号: $VERSION"
    
    - name: 创建 Git Tag
      run: |
        git config user.name "GitHub Actions"
        git config user.email "actions@github.com"
        git tag -a v${{ steps.version.outputs.version }} -m "自动发布版本 v${{ steps.version.outputs.version }}"
        git push origin v${{ steps.version.outputs.version }}
    
    - name: 创建 GitHub Release
      uses: softprops/action-gh-release@v1
      with:
        tag_name: v${{ steps.version.outputs.version }}
        name: Release v${{ steps.version.outputs.version }}
        body: |
          ## 🚀 自动发布
          
          本次发布包含以下变更:
          ${{ github.event.head_commit.message }}
          
          ## 📦 Docker 镜像
          ```bash
          docker pull ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}
          ```
        draft: false
        prerelease: false
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                

💻 完整 Workflow 文件代码示例

下面是一个生产级别的完整 GitHub Actions workflow 文件,包含了所有最佳实践:

name: OpenClaw 完整 CI/CD 流程

on:
  push:
    branches: [ main, develop, 'feature/*' ]
  pull_request:
    branches: [ main, develop ]

# 环境变量
env:
  DOCKER_REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
  NODE_VERSION: '22'

# 权限设置
permissions:
  contents: read
  packages: write
  deployments: write

jobs:
  # ==================== 第一阶段:代码质量检查 ====================
  lint-and-format:
    name: 🔍 代码质量检查
    runs-on: ubuntu-latest
    
    steps:
    - name: 检出代码
      uses: actions/checkout@v4
    
    - name: 设置 Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: 安装依赖
      run: npm ci
    
    - name: 运行 ESLint
      run: npm run lint
    
    - name: 检查代码格式
      run: npm run format:check
    
    - name: 类型检查
      run: npm run type-check

  # ==================== 第二阶段:测试 ====================
  test:
    name: 🧪 运行测试
    runs-on: ubuntu-latest
    needs: lint-and-format
    
    strategy:
      matrix:
        test-group: [unit, integration, e2e]
    
    steps:
    - name: 检出代码
      uses: actions/checkout@v4
    
    - name: 设置 Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: 安装依赖
      run: npm ci
    
    - name: 运行 ${{ matrix.test-group }} 测试
      run: npm run test:${{ matrix.test-group }}
      env:
        OPENCLAW_TEST_MODE: true
        OPENCLAW_LOG_LEVEL: debug
    
    - name: 上传测试报告
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: test-report-${{ matrix.test-group }}
        path: coverage/

  # ==================== 第三阶段:构建 ====================
  build:
    name: 🏗️ 构建 Docker 镜像
    runs-on: ubuntu-latest
    needs: test
    if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
    
    outputs:
      image-tag: ${{ steps.meta.outputs.tags }}
      image-digest: ${{ steps.build.outputs.digest }}
    
    steps:
    - name: 检出代码
      uses: actions/checkout@v4
    
    - name: 设置 Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: 登录到 GitHub Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.DOCKER_REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    
    - name: 提取元数据
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=semver,pattern={{version}}
          type=sha,format=short
          type=schedule,pattern={{date 'YYYYMMDD'}}
    
    - name: 构建并推送
      id: build
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max
        build-args: |
          NODE_VERSION=${{ env.NODE_VERSION }}
          BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}

  # ==================== 第四阶段:部署到开发环境 ====================
  deploy-dev:
    name: 🚀 部署到开发环境
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'
    environment:
      name: development
      url: https://dev.openclaw.example.com
    
    steps:
    - name: 部署到服务器
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.DEV_HOST }}
        username: ${{ secrets.DEV_USER }}
        key: ${{ secrets.DEV_SSH_KEY }}
        script: |
          cd /opt/openclaw-dev
          echo "拉取最新镜像..."
          docker-compose -f docker-compose.dev.yml pull
          echo "重启服务..."
          docker-compose -f docker-compose.dev.yml up -d --remove-orphans
          echo "清理旧镜像..."
          docker system prune -f
          echo "部署完成!"
    
    - name: 健康检查
      run: |
        echo "等待服务启动..."
        sleep 15
        for i in {1..5}; do
          if curl -f https://dev.openclaw.example.com/health; then
            echo "✅ 健康检查通过"
            exit 0
          fi
          echo "重试 $i/5..."
          sleep 10
        done
        echo "❌ 健康检查失败"
        exit 1
    
    - name: 发送飞书通知
      if: always()
      uses: foxundermoon/feishu-action@v2
      with:
        url: ${{ secrets.FEISHU_WEBHOOK_DEV }}
        msg_type: interactive
        content: |
          {
            "config": {"wide_screen_mode": true},
            "elements": [
              {"tag": "div", "text": {"tag": "lark_md", "content": "**🚀 开发环境部署完成**"}},
              {"tag": "div", "text": {"tag": "lark_md", "content": "**版本:** ${{ github.sha }}\n**分支:** develop\n**状态:** ${{ job.status }}\n**执行者:** ${{ github.actor }}"}},
              {"tag": "action", "actions": [{"tag": "button", "text": {"tag": "plain_text", "content": "查看详情"}, "url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "type": "default"}]}
            ]
          }

  # ==================== 第五阶段:部署到生产环境 ====================
  deploy-prod:
    name: 🎯 部署到生产环境
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: https://openclaw.example.com
    
    steps:
    - name: 审批检查
      run: echo "等待生产环境部署审批..."
    
    - name: 部署到生产服务器
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.PROD_HOST }}
        username: ${{ secrets.PROD_USER }}
        key: ${{ secrets.PROD_SSH_KEY }}
        script: |
          cd /opt/openclaw-prod
          echo "📦 拉取最新镜像..."
          docker-compose pull openclaw
          echo "🔄 滚动更新服务..."
          docker-compose up -d --no-deps openclaw
          echo "🧹 清理旧资源..."
          docker system prune -f
          echo "✅ 部署完成!"
    
    - name: 生产环境健康检查
      run: |
        echo "等待服务完全启动..."
        sleep 30
        RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" https://openclaw.example.com/health)
        if [ "$RESPONSE" = "200" ]; then
          echo "✅ 生产环境健康检查通过"
        else
          echo "❌ 生产环境健康检查失败 (HTTP $RESPONSE)"
          exit 1
        fi
    
    - name: 创建 GitHub Release
      uses: softprops/action-gh-release@v1
      with:
        tag_name: v${{ github.run_number }}
        name: "Release v${{ github.run_number }} (Production)"
        body: |
          ## 🎉 生产环境发布
          
          **版本:** v${{ github.run_number }}
          **提交:** ${{ github.sha }}
          **发布时间:** ${{ github.event.head_commit.timestamp }}
          
          ### 📝 变更日志
          ${{ github.event.head_commit.message }}
          
          ### 🔗 相关链接
          - [查看提交](https://github.com/${{ github.repository }}/commit/${{ github.sha }})
          - [完整日志](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
        draft: false
        prerelease: false
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    
    - name: 发送多渠道通知
      if: always()
      run: |
        # 飞书通知
        curl -X POST ${{ secrets.FEISHU_WEBHOOK_PROD }} \
          -H "Content-Type: application/json" \
          -d '{
            "msg_type": "post",
            "content": {
              "post": {
                "zh_cn": {
                  "title": "🎯 生产环境部署",
                  "content": [[
                    {"tag": "text", "text": "部署完成\n版本: v${{ github.run_number }}\n状态: ${{ job.status }}"}
                  ]]
                }
              }
            }
          }'
        
        # Discord 通知
        curl -X POST ${{ secrets.DISCORD_WEBHOOK_URL }} \
          -H "Content-Type: application/json" \
          -d '{
            "embeds": [{
              "title": "🚀 OpenClaw Production Deploy",
              "color": 65280,
              "fields": [
                {"name": "Version", "value": "v${{ github.run_number }}", "inline": true},
                {"name": "Commit", "value": "${{ github.sha }}", "inline": true},
                {"name": "Status", "value": "${{ job.status }}", "inline": true}
              ]
            }]
          }'

# ==================== 工作流运行后清理 ====================
  cleanup:
    name: 🧹 清理
    runs-on: ubuntu-latest
    if: always()
    needs: [lint-and-format, test, build, deploy-dev, deploy-prod]
    
    steps:
    - name: 清理临时文件
      run: echo "清理完成"
                
🎬 王家卫风格提示:
"有些部署,就像重庆森林里的凤梨罐头,过期了就再也回不来了。但有了GitHub Actions,每一次部署都像是王家卫电影里的镜头——精准、优雅、从不拖泥带水。"
🎭 周星驰风格彩蛋:
"曾经有一份完美的CI/CD配置摆在我面前,我没有珍惜,直到上线前一晚才后悔莫及。人世间最痛苦的事莫过于此。如果上天给我一个机会再来一次,我会对那个YAML文件说三个字:我会写。如果非要在这份配置上加一个版本号,我希望是——v1.0.0!"