Jenkins 自动触发构建配置手册

复制代码
# Jenkins 自动触发构建配置手册

> 适用场景:代码推送到指定分支后自动触发 Jenkins 构建部署,无需手动操作。

---

## 目录

- [方式一:Generic Webhook Trigger + GitHub Actions(当前方案)](#方式一generic-webhook-trigger--github-actions当前方案)
- [方式二:GitHub Webhook 直连 Jenkins(免 GitHub Actions)](#方式二github-webhook-直连-jenkins免-github-actions)
- [方式三:Jenkins Multibranch Pipeline + GitHub Integration](#方式三jenkins-multibranch-pipeline--github-integration)

---

## 方式一:Generic Webhook Trigger + GitHub Actions(当前方案)

### 架构

```
GitHub (push to uat)
  └─> GitHub Actions (self-hosted runner)
        └─> curl POST → Jenkins Generic Webhook Trigger
              └─> Jenkins Pipeline (build → deploy → notify)
```

### 前置条件

| 组件 | 要求 |
|------|------|
| Jenkins 插件 | [Generic Webhook Trigger](https://plugins.jenkins.io/generic-webhook-trigger/) |
| Jenkins 插件 | [Git Parameter](https://plugins.jenkins.io/git-parameter/) |
| Jenkins 插件 | [Build User Vars](https://plugins.jenkins.io/build-user-vars-plugin/) |
| GitHub Runner | self-hosted runner(标签 `ltp`) |
| 构建工具 | Maven 3 (`M3`)、JDK 17 (`jdk17`) |
| 凭据 | `SRE_LTP_TOKEN`(Jenkins Credentials) |

### Step 1:配置 Jenkins Pipeline

在 Jenkins Job 中使用 Declarative Pipeline,核心配置如下:

#### 1.1 触发器配置(triggers)

```groovy
triggers {
    GenericTrigger(
        genericVariables: [
            [key: 'ref', value: '$.ref']  // 从 webhook payload 提取分支名
        ],
        token: 'ltp-explore-project-uat',       // 自定义 token,需与 GitHub Actions 中一致
        regexpFilterText: '$ref',
        regexpFilterExpression: 'refs/heads/uat' // 仅 uat 分支触发
    )
}
```

**关键参数说明:**

| 参数 | 作用 | 示例 |
|------|------|------|
| `genericVariables` | 从 JSON payload 中提取变量 | `$.ref` 提取推送分支 |
| `token` | 触发认证 token,每个 Job 唯一 | `ltp-explore-project-uat` |
| `regexpFilterText` | 参与正则匹配的变量 | `$ref` |
| `regexpFilterExpression` | 正则表达式,匹配才触发 | `refs/heads/uat` |

#### 1.2 构建参数(parameters)

```groovy
parameters {
    gitParameter(
        name: 'BRANCH',
        type: 'PT_BRANCH_TAG',
        branchFilter: 'origin/(.*)',
        defaultValue: 'origin/uat',
        description: '选择要构建的分支/tag(不选择默认 origin/uat)',
        selectedValue: 'DEFAULT',
        sortMode: 'DESCENDING_SMART',
        useRepository: '.*',
        quickFilterEnabled: true,
        listSize: '5'
    )
    choice(name: 'Deploy_Env', choices: ['uat'], description: '选择部署环境')
    choice(name: 'start', choices: ['true','false'], description: '是否自动重启')
    booleanParam(name: 'MAVEN_API_MODE', defaultValue: false, description: 'Build JAR Only')
}
```

#### 1.3 流水线阶段(stages)

```
Checkout → Build → Deploy
```

**Checkout 阶段:**
- 浅克隆(`depth: 1, shallow: true`)加速拉取
- 提取 Git 提交者、提交信息、Commit SHA

**Build 阶段:**
- 注入 `SRE_LTP_TOKEN` 凭据到 `settings.xml`
- 调用 `/data/maven_build-nonprod.sh` 执行 Maven 构建
- 支持 `MAVEN_API_MODE`:`true` 时仅构建 JAR,不部署

**Deploy 阶段:**
- `MAVEN_API_MODE=true`:跳过部署(SDK/API 模式)
- `MAVEN_API_MODE=false`:调用 `/data/java_deploy-nonprod.sh` 执行部署
- 支持 dev / qa / 默认环境分发

#### 1.4 构建通知(post)

```groovy
post {
    success {
        // 调用飞书通知脚本
        sh "python3 /data/notify_lark.py <job> <build_number> <url> <author> <commit> <msg> <user> <env> <branch> success"
    }
    failure {
        sh "python3 /data/notify_lark.py ... fail"
    }
}
```

### Step 2:配置 GitHub Actions

在仓库 `.github/workflows/` 目录创建工作流文件:

```yaml
# .github/workflows/trigger-jenkins-uat.yml
name: Trigger Jenkins UAT

on:
  push:
    branches:
      - uat

jobs:
  trigger-jenkins:
    name: Trigger Jenkins UAT Job
    runs-on: [self-hosted, ltp]
    steps:
      - name: Trigger Jenkins
        run: |
          curl -X POST \
            "https://jenkins.icbc.com/generic-webhook-trigger/invoke?token=ltp-explore-project-uat" \
            -H "Content-Type: application/json" \
            -d '{"ref": "refs/heads/uat"}'
```

### Step 3:新项目适配清单

为新项目配置时,需修改以下内容:

| 修改项 | 位置 | 说明 |
|--------|------|------|
| `token` | Jenkins Pipeline `triggers` 块 | 改为项目唯一 token,如 `ltp-<project>-uat` |
| `regexpFilterExpression` | Jenkins Pipeline `triggers` 块 | 按需修改触发分支 |
| `url` | Pipeline `Checkout` 阶段 | 改为目标仓库 Git 地址 |
| `defaultValue` | `gitParameter` | 改为默认分支 |
| `choices` | `Deploy_Env` | 按需添加部署环境 |
| `token` | GitHub Actions `curl` 命令 | 与 Jenkins 中的 token 保持一致 |
| `branches` | GitHub Actions `on.push` | 改为目标触发分支 |

---

## 方式二:GitHub Webhook 直连 Jenkins(免 GitHub Actions)

### 架构

```
GitHub (push event)
  └─> GitHub Webhook (直接 POST)
        └─> Jenkins Generic Webhook Trigger
              └─> Jenkins Pipeline
```

### 优势

- 无需 self-hosted runner,减少基础设施维护
- 延迟更低(少一跳)
- 配置更简单

### 配置步骤

#### 2.1 Jenkins 侧(与方式一相同)

Pipeline 中的 `triggers` 块保持不变,确保 Generic Webhook Trigger 插件已安装。

#### 2.2 GitHub 仓库配置 Webhook

1. 进入仓库 **Settings → Webhooks → Add webhook**
2. 填写以下信息:

| 字段 | 值 |
|------|------|
| Payload URL | `https://jenkins.icbc.com/generic-webhook-trigger/invoke?token=ltp-explore-project-uat` |
| Content type | `application/json` |
| Secret | (可选)设置 HMAC 密钥验证请求来源 |
| Events | 选择 **Just the push event** |
| Active | 勾选 |

#### 2.3 分支过滤

分支过滤完全由 Jenkins 侧的 `regexpFilterExpression` 负责。GitHub Webhook 会在每次 push 时发送事件,Jenkins 收到后用正则匹配 `$.ref` 字段,不匹配则忽略。

#### 2.4 安全加固(推荐)

```groovy
triggers {
    GenericTrigger(
        genericVariables: [
            [key: 'ref', value: '$.ref']
        ],
        token: 'ltp-explore-project-uat',
        tokenCredentialId: '',        // 或使用 Jenkins Credential 存储 token
        regexpFilterText: '$ref',
        regexpFilterExpression: 'refs/heads/uat',
        silentResponse: true          // 不返回触发详情,防止信息泄露
    )
}
```

如果配置了 Webhook Secret,需在 Jenkins 的 Generic Webhook Trigger 配置中启用 HMAC 验证:

```groovy
hmacKeyId: 'github-webhook-secret'  // Jenkins Credentials ID
```

#### 2.5 验证

```bash
# 在 GitHub Webhook 页面点击 "Recent Deliveries" 查看投递结果
# 或手动测试:
curl -X POST \
  "https://jenkins.icbc.com/generic-webhook-trigger/invoke?token=ltp-explore-project-uat" \
  -H "Content-Type: application/json" \
  -d '{"ref": "refs/heads/uat"}'
```

---

## 方式三:Jenkins Multibranch Pipeline + GitHub Integration

### 架构

```
GitHub (push / PR event)
  └─> GitHub App / Webhook
        └─> Jenkins GitHub Branch Source
              └─> Multibranch Pipeline (自动发现分支)
                    └─> Jenkinsfile (per branch)
```

### 优势

- 自动发现新分支和 PR,无需为每个分支手动配置 Job
- 天然支持 PR 构建和状态回报
- 分支删除后自动清理 Job
- 更符合 GitOps 理念

### 前置条件

| 组件 | 要求 |
|------|------|
| Jenkins 插件 | [GitHub Branch Source](https://plugins.jenkins.io/github-branch-source/) |
| Jenkins 插件 | [Pipeline: Multibranch](https://plugins.jenkins.io/workflow-multibranch/) |
| GitHub | GitHub App 或 Personal Access Token |

### 配置步骤

#### 3.1 创建 GitHub App(推荐)或 PAT

**GitHub App 方式(推荐):**
1. GitHub → Settings → Developer settings → GitHub Apps → New GitHub App
2. 权限:`Contents: Read`、`Metadata: Read`、`Commit statuses: Read & Write`
3. 生成 Private Key,下载 `.pem` 文件
4. 在 Jenkins 中添加 Credential:`Kind: GitHub App`

**PAT 方式(简单):**
1. GitHub → Settings → Developer settings → Personal access tokens
2. 权限:`repo`(Full control)
3. 在 Jenkins 中添加 Credential:`Kind: Username with password`(用户名填 GitHub 用户名,密码填 PAT)

#### 3.2 创建 Multibranch Pipeline Job

1. Jenkins → New Item → **Multibranch Pipeline**
2. Branch Sources → Add source → **GitHub**
3. 配置:

| 字段 | 值 |
|------|------|
| Credentials | 选择上一步创建的凭据 |
| Repository HTTPS URL | `https://github.com/LiquidityTech/ltp-explore-project.git` |
| Behaviours | Discover branches: All branches |
| Build Configuration | Mode: by Jenkinsfile / Script Path: `Jenkinsfile` |
| Scan Multibranch Pipeline Triggers | Periodically if not otherwise run: 1 minute(兜底轮询) |

#### 3.3 仓库根目录放置 Jenkinsfile

```groovy
// Jenkinsfile(放在仓库根目录)
pipeline {
    agent any
    tools {
        maven "M3"
        jdk 'jdk17'
    }

    stages {
        stage('Check Branch') {
            steps {
                script {
                    // 仅 uat 分支执行完整流程,其他分支仅构建
                    env.IS_UAT = (env.BRANCH_NAME == 'uat') ? 'true' : 'false'
                    echo "Branch: ${env.BRANCH_NAME}, IS_UAT: ${env.IS_UAT}"
                }
            }
        }

        stage('Build') {
            steps {
                script {
                    GIT_COMMIT = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
                    GIT_AUTHOR = sh(script: 'git log -1 --pretty=format:%an', returnStdout: true).trim()
                    GIT_MSG = sh(script: 'git log -1 --pretty=format:%s', returnStdout: true).trim()

                    withCredentials([string(credentialsId: 'SRE_LTP_TOKEN', variable: 'SRE_LTP_TOKEN')]) {
                        sh """
                        sed -i "s|SRE_LTP_TOKEN|\${SRE_LTP_TOKEN}|g" .github/workflows/settings.xml
                        GIT_COMMIT=${GIT_COMMIT} JOB_NAME=${env.JOB_BASE_NAME} sh /data/maven_build-nonprod.sh
                        """
                    }
                }
            }
        }

        stage('Deploy') {
            when {
                environment name: 'IS_UAT', value: 'true'
            }
            steps {
                script {
                    withEnv([
                        "GIT_COMMIT=${GIT_COMMIT}",
                        "JOB_NAME=${env.JOB_BASE_NAME}",
                        "Deploy_Env=uat",
                        "GIT_MSG=${GIT_MSG}",
                        "start=true"
                    ]) {
                        sh "sh /data/java_deploy-nonprod.sh"
                    }
                }
            }
        }
    }

    post {
        success {
            script {
                if (env.IS_UAT == 'true') {
                    sh """
                    python3 /data/notify_lark.py \
                        "${env.JOB_NAME}" "${env.BUILD_NUMBER}" "${env.BUILD_URL}" \
                        "${GIT_AUTHOR}" "${GIT_COMMIT}" "${GIT_MSG}" "auto" "uat" "${env.BRANCH_NAME}" "success"
                    """
                }
            }
        }
        failure {
            script {
                if (env.IS_UAT == 'true') {
                    sh """
                    python3 /data/notify_lark.py \
                        "${env.JOB_NAME}" "${env.BUILD_NUMBER}" "${env.BUILD_URL}" \
                        "${GIT_AUTHOR}" "${GIT_COMMIT}" "${GIT_MSG}" "auto" "uat" "${env.BRANCH_NAME}" "fail"
                    """
                }
            }
        }
    }
}
```

#### 3.4 自动触发机制

Multibranch Pipeline 通过以下方式感知代码变更:

1. **GitHub Webhook(推荐):** GitHub 推送事件通知 Jenkins 立即扫描
   - Webhook URL: `https://jenkins.icbc.com/github-webhook/`
   - Events: `push`, `pull_request`
2. **轮询兜底:** 配置 `Scan Multibranch Pipeline Triggers` 周期性扫描(建议 1-5 分钟)

---

## 方案对比

| 维度 | 方式一:GWT + GH Actions | 方式二:GWT + GitHub Webhook | 方式三:Multibranch Pipeline |
|------|--------------------------|-------------------------------|------------------------------|
| 复杂度 | 中等 | **最低** | 较高(初始配置) |
| 依赖 | self-hosted runner | 无额外依赖 | GitHub App/PAT |
| 分支管理 | 手动配置 token | 手动配置 token | **自动发现** |
| PR 构建 | 需额外配置 | 需额外配置 | **原生支持** |
| 延迟 | ~5-10s(经 GH Actions) | **~1-2s(直连)** | ~1-5s |
| 安全性 | Runner 网络隔离 | 需暴露 Jenkins 端点 | GitHub App 权限粒度细 |
| 适合场景 | 已有 GH Actions 基础设施 | 简单项目、快速接入 | 多分支开发、PR 驱动工作流 |

## 推荐选择

- **已有 self-hosted runner + 少量项目** → 方式一(当前方案)
- **快速接入 / 减少依赖** → 方式二(GitHub Webhook 直连)
- **多分支开发 / 需要 PR 构建 / 新项目** → 方式三(Multibranch Pipeline)