Skip to content

Jenkins 多租户保姆级教程

版本: 1.0 | 日期: 2026-08-26
基于真实生产环境编写(K8s + JCasC + role-strategy + Job DSL)
技术栈: Jenkins LTS JDK21 (Helm) + GitLab v19.2 + RKE2 K8s


📋 目录


一、总览:Jenkins 多租户架构

┌─────────────────────────────────────────────────────────────────────┐
│                    Jenkins Controller (JCasC)                        │
│                                                                     │
│  ┌─── 全局角色 ──────────────────────────────────────────────────┐  │
│  │ admin (Overall/Administer)                                    │  │
│  │ readonly (Overall/Read → authenticated)                       │  │
│  │ webhook-trigger (Job/Build → anonymous)                       │  │
│  └───────────────────────────────────────────────────────────────┘  │
│                                                                     │
│  ┌─── 项目角色 (Item Roles) ─────────────────────────────────────┐  │
│  │                                                               │  │
│  │  📁 dev/          📁 test/          📁 ops/                    │  │
│  │  ├─ dev-developer ├─ test-developer ├─ ops-developer          │  │
│  │  │  (dev-team)    │  (test-team)    │  (ops-team)             │  │
│  │  ├─ dev-folder    ├─ test-folder    ├─ ops-folder             │  │
│  │  │                │                 │                          │  │
│  │  │ Jobs:          │ Jobs:           │ Jobs:                    │  │
│  │  │ toolchain-check│ integration-    │ infra-health-           │  │
│  │  │ java-demo      │   suite         │   check                  │  │
│  │  │ gitlab-cicd-   │                 │                          │  │
│  │  │   demo         │                 │                          │  │
│  │  │ sonarqube-scan │                 │                          │  │
│  │  │ ai-assisted-   │                 │                          │  │
│  │  │   build        │                 │                          │  │
│  │  │ gitlab-mr-     │                 │                          │  │
│  │  │   trigger      │                 │                          │  │
│  │  │ java21         │                 │                          │  │
│  │  │                │                 │                          │  │
│  │  │ Agents:        │ Agents:         │ Agents:                  │  │
│  │  │ maven8 maven21 │ python node21   │ python                   │  │
│  │  │ node21 golang  │ golang          │                          │  │
│  │  │ python         │                 │                          │  │
│  └───┴────────────────┴─────────────────┴──────────────────────────┘  │
│                                                                     │
│  ┌─── 共享层 ─────────────────────────────────────────────────────┐  │
│  │ Shared Library: ai-pipeline-lib (GitLab SCM)                  │  │
│  │ 凭证: gitlab-api-token, gitlab-git-user, sonarqube-token      │  │
│  └───────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

                    K8s Pod 动态调度

        ┌──────────┬──────────┼──────────┬──────────┐
        ▼          ▼          ▼          ▼          ▼
   ┌─────────┐┌─────────┐┌─────────┐┌─────────┐┌─────────┐
   │ maven8  ││ maven21 ││ node21  ││ golang  ││ python  │
   │ JDK8    ││ JDK21   ││ Node 21 ││ Go 1.24 ││ Py 3.12 │
   │ Maven   ││ Maven   ││ Alpine  ││ Alpine  ││ Alpine  │
   └─────────┘└─────────┘└─────────┘└─────────┘└─────────┘
   Harbor 镜像仓库: 192.168.122.156:30000/jenkins/*

三条隔离维度

维度实现方式作用
权限隔离role-strategy 插件 + Pattern 匹配团队只能看到/操作自己的 Job
资源隔离K8s Agent Pod 模板 + 命名空间构建环境动态分配,互不干扰
配置即代码JCasC + Job DSL + Helm values所有配置版本化,可审计,可回滚

二、前置条件

2.1 必需的基础设施

组件版本用途
K8s 集群RKE2 v1.35运行 Jenkins + Agent Pods
JenkinsLTS JDK21 (Helm)CI/CD 引擎
Harborv2.12Agent 镜像私有仓库
GitLabv19.2代码仓库 + OAuth SSO

2.2 必需的 Jenkins 插件

在 Helm values 的 controller.additionalPlugins 中安装:

插件版本用途
role-strategy898.v多租户核心:基于角色的权限控制
job-dsl1.91自动创建 Job:声明式定义文件夹和流水线
cloudbees-folder6.1106文件夹:组织 Job 到团队空间
workflow-multibranch841.v多分支:Git 分支自动创建 Pipeline
git5.10.1Git 操作:checkout scm
gitlab-plugin1.9.16GitLab 集成:Commit Status 回写
pipeline-utility-steps3.810工具步骤:readJSON, writeJSON
oic-authSSO 登录:OpenID Connect (GitLab OAuth)
matrix-auth辅助:矩阵权限视图
generic-webhook-trigger2.4.2触发器:外部 Webhook 触发构建

2.3 Controller 资源配置

yaml
# Helm values: controller
resources:
  requests:
    cpu: "2"
    memory: 6Gi
  limits:
    cpu: "4"
    memory: 10Gi
javaOpts: >-
  -Xms4g -Xmx6g
  -XX:+UseG1GC -XX:MaxGCPauseMillis=200
  -XX:+ParallelRefProcEnabled -XX:+ExplicitGCInvokesConcurrent
  -Djava.awt.headless=true
  -Djenkins.model.Jenkins.slaveAgentPort=50000
numExecutors: 0          # Controller 不执行任务,全部分配给 Agent
persistence:
  enabled: true
  size: 100Gi
  accessMode: ReadWriteMany
  storageClass: nfs-nvme  # NFS 存储,支持多节点挂载

为什么 numExecutors: 0 多租户环境下,Controller 只负责调度和 API 响应,所有构建任务都分配给动态 Agent Pod,避免单点瓶颈和资源竞争。


三、核心概念:三层隔离模型

┌─────────────────────────────────────────────────────────────┐
│                    第一层:全局角色                           │
│                                                             │
│  admin ──────────→ Overall/Administer (全部权限)             │
│  readonly ───────→ Overall/Read (所有已认证用户)             │
│  webhook-trigger → Job/Build + Job/Read (anonymous 用户)    │
│                                                             │
│  作用:控制"谁能登录 Jenkins"和"谁能触发构建"                │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│                    第二层:项目角色                           │
│                                                             │
│  dev-developer ──→ pattern: "dev/.*"  (dev 文件夹下所有 Job) │
│  dev-folder ─────→ pattern: "^dev$"   (dev 文件夹本身)      │
│  test-developer ─→ pattern: "test/.*"                        │
│  test-folder ────→ pattern: "^test$"                        │
│  ops-developer ──→ pattern: "ops/.*"                        │
│  ops-folder ─────→ pattern: "^ops$"                         │
│                                                             │
│  作用:控制"谁能操作哪些 Job"(文件夹级别的隔离)            │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│                    第三层:资源隔离                           │
│                                                             │
│  Agent Pod 模板 ─→ K8s 动态调度(每次构建创建独立 Pod)     │
│  命名空间 ───────→ jenkins (所有 Agent Pod 在同一 namespace) │
│  镜像隔离 ───────→ 每种语言独立的 Docker 镜像               │
│  资源限制 ───────→ 每个容器的 CPU/内存 Request + Limit       │
│                                                             │
│  作用:控制"构建任务的运行环境"(互不干扰)                  │
└─────────────────────────────────────────────────────────────┘

关键概念:Global Roles vs Item Roles

类型作用域配置位置示例
Global Roles整个 Jenkins 实例roles.globaladmin, readonly, webhook-trigger
Item Roles特定 Job/文件夹roles.itemsdev-developer (pattern: dev/.*)

为什么分两层?

  • Global Role 的 Overall/Read 允许用户登录 Jenkins
  • Item Role 控制用户看到和操作哪些 Job
  • 没有 Item Role 的用户登录后只能看到空白页面

四、第一步:RBAC 权限配置(角色 + 权限 + 用户)

4.1 全局角色

全局角色控制 Jenkins 实例级别的操作权限。

admin(管理员)

yaml
- name: "admin"
  description: "Jenkins 全局管理员"
  permissions:
    - "Overall/Administer"
  entries:
    - user: "admin"           # 本地 admin 账户
    - group: "jenkins-admins" # 管理员组(OIC SSO 登录后映射)
权限 ID含义
Overall/Administer超级管理员,拥有所有权限

谁拥有此角色?

  • admin:Helm values 中配置的本地管理员账户
  • jenkins-admins 组:通过 OIC Auth (GitLab OAuth) 登录后,GitLab Group 映射为 Jenkins Group

readonly(只读用户)

yaml
- name: "readonly"
  description: "已认证用户可登录 Jenkins"
  permissions:
    - "Overall/Read"
  entries:
    - group: "authenticated"   # 所有已登录用户
权限 ID含义
Overall/Read可以登录 Jenkins 并查看全局信息

设计意图:任何人只要能通过 SSO 登录 Jenkins,就自动获得只读权限。但能否看到具体 Job 取决于 Item Role。

webhook-trigger(Webhook 触发器)

yaml
- name: "webhook-trigger"
  description: "允许匿名 Webhook 触发构建"
  permissions:
    - "Overall/Read"
    - "Job/Build"
    - "Job/Read"
  entries:
    - user: "anonymous"
权限 ID含义
Overall/Read可以访问 Jenkins API
Job/Build可以触发构建
Job/Read可以读取 Job 信息

为什么是 anonymous GitLab Webhook 通过 Basic Auth (admin:TOKEN) 调用 Jenkins API,如果该用户不存在于 Jenkins 用户库中,Jenkins 将其识别为 anonymouswebhook-trigger 角色正是为此设计的。

4.2 项目角色(Item Roles)

项目角色控制特定 Job/文件夹的操作权限。每个团队有两个角色:

  • {team}-developer:操作文件夹下的 Job
  • {team}-folder:管理文件夹本身

dev 团队

yaml
# dev-developer:操作 dev/ 下的所有 Job
- name: "dev-developer"
  description: "dev 团队完整权限"
  pattern: "dev/.*"           # ← 匹配 dev/ 下的所有 Job
  permissions:
    - "Job/Build"             # 触发构建
    - "Job/Cancel"            # 取消构建
    - "Job/Read"              # 查看 Job 详情
    - "Job/Workspace"         # 查看工作区文件
    - "Job/Configure"         # 修改 Job 配置
    - "Job/Create"            # 创建新 Job
    - "Job/Delete"            # 删除 Job
    - "Run/Delete"            # 删除构建记录
    - "Run/Replay"            # 重放构建
  entries:
    - group: "dev-team"       # dev 团队组
    - user: "dev01"           # dev01 用户(直接绑定)

# dev-folder:管理 dev 文件夹本身
- name: "dev-folder"
  description: "dev 文件夹管理权限"
  pattern: "^dev$"            # ← 精确匹配 "dev" 文件夹
  permissions:
    - "Job/Configure"
    - "Job/Create"
    - "Job/Delete"
    - "Job/Build"
    - "Job/Read"
  entries:
    - group: "dev-team"
    - user: "dev01"

test 团队

yaml
- name: "test-developer"
  description: "test 团队完整权限"
  pattern: "test/.*"
  permissions:
    - "Job/Build"
    - "Job/Cancel"
    - "Job/Read"
    - "Job/Workspace"
  entries:
    - group: "test-team"

- name: "test-folder"
  description: "test 文件夹管理权限"
  pattern: "^test$"
  permissions:
    - "Job/Configure"
    - "Job/Create"
    - "Job/Delete"
    - "Job/Build"
    - "Job/Read"
  entries:
    - group: "test-team"

注意:test 团队没有 Job/ConfigureJob/CreateJob/DeleteRun/DeleteRun/Replay 权限,相比 dev 团队更受限。这是有意设计的——测试团队只需要触发和查看,不需要修改 Job 配置。

ops 团队

yaml
- name: "ops-developer"
  description: "ops 团队完整权限"
  pattern: "ops/.*"
  permissions:
    - "Job/Build"
    - "Job/Cancel"
    - "Job/Read"
    - "Job/Workspace"
    - "Job/Configure"
    - "Job/Create"
    - "Job/Delete"
    - "Run/Delete"
    - "Run/Replay"
  entries:
    - group: "ops-team"

- name: "ops-folder"
  description: "ops 文件夹管理权限"
  pattern: "^ops$"
  permissions:
    - "Job/Configure"
    - "Job/Create"
    - "Job/Delete"
    - "Job/Build"
    - "Job/Read"
  entries:
    - group: "ops-team"

4.3 完整 RBAC JCasC 配置

以下是 ConfigMap jenkins-jenkins-config-rbac 的完整内容:

yaml
jenkins:
  authorizationStrategy:
    roleBased:
      roles:
        # ===== 全局角色 =====
        global:
          - name: "admin"
            description: "Jenkins 全局管理员"
            permissions:
              - "Overall/Administer"
            entries:
              - user: "admin"
              - group: "jenkins-admins"

          - name: "readonly"
            description: "已认证用户可登录 Jenkins"
            permissions:
              - "Overall/Read"
            entries:
              - group: "authenticated"

          - name: "webhook-trigger"
            description: "允许匿名 Webhook 触发构建"
            permissions:
              - "Overall/Read"
              - "Job/Build"
              - "Job/Read"
            entries:
              - user: "anonymous"

        # ===== 项目角色 =====
        items:
          # ----- dev 团队 -----
          - name: "dev-developer"
            description: "dev 团队完整权限"
            pattern: "dev/.*"
            permissions:
              - "Job/Build"
              - "Job/Cancel"
              - "Job/Read"
              - "Job/Workspace"
              - "Job/Configure"
              - "Job/Create"
              - "Job/Delete"
              - "Run/Delete"
              - "Run/Replay"
            entries:
              - group: "dev-team"
              - user: "dev01"

          - name: "dev-folder"
            description: "dev 文件夹管理权限"
            pattern: "^dev$"
            permissions:
              - "Job/Configure"
              - "Job/Create"
              - "Job/Delete"
              - "Job/Build"
              - "Job/Read"
            entries:
              - group: "dev-team"
              - user: "dev01"

          # ----- test 团队 -----
          - name: "test-developer"
            description: "test 团队完整权限"
            pattern: "test/.*"
            permissions:
              - "Job/Build"
              - "Job/Cancel"
              - "Job/Read"
              - "Job/Workspace"
            entries:
              - group: "test-team"

          - name: "test-folder"
            description: "test 文件夹管理权限"
            pattern: "^test$"
            permissions:
              - "Job/Configure"
              - "Job/Create"
              - "Job/Delete"
              - "Job/Build"
              - "Job/Read"
            entries:
              - group: "test-team"

          # ----- ops 团队 -----
          - name: "ops-developer"
            description: "ops 团队完整权限"
            pattern: "ops/.*"
            permissions:
              - "Job/Build"
              - "Job/Cancel"
              - "Job/Read"
              - "Job/Workspace"
              - "Job/Configure"
              - "Job/Create"
              - "Job/Delete"
              - "Run/Delete"
              - "Run/Replay"
            entries:
              - group: "ops-team"

          - name: "ops-folder"
            description: "ops 文件夹管理权限"
            pattern: "^ops$"
            permissions:
              - "Job/Configure"
              - "Job/Create"
              - "Job/Delete"
              - "Job/Build"
              - "Job/Read"
            entries:
              - group: "ops-team"

4.4 权限矩阵总览

角色类型匹配模式绑定对象BuildCancelReadWorkspaceConfigureCreateDeleteRun/DeleteRun/Replay
adminGlobaladmin, jenkins-admins
readonlyGlobalauthenticated
webhook-triggerGlobalanonymous
dev-developerItemdev/.*dev-team, dev01
dev-folderItem^dev$dev-team, dev01
test-developerItemtest/.*test-team
test-folderItem^test$test-team
ops-developerItemops/.*ops-team
ops-folderItem^ops$ops-team

4.5 Pattern 匹配规则详解

Item Role 的 pattern 字段使用正则表达式匹配 Job 全路径:

Pattern匹配不匹配说明
dev/.*dev/toolchain-checkdev.* 匹配 / 后的所有内容
^dev$devdev/toolchain-check^...$ 精确匹配文件夹名
test/.*test/integration-suitetest同上
ops/.*ops/infra-health-checkops同上

为什么要两个 Pattern?

  • dev/.* → 控制文件夹内部的 Job
  • ^dev$ → 控制文件夹本身(重命名、删除文件夹等)

如果只有 dev/.* 没有 ^dev$,用户能操作文件夹里的 Job 但无法管理文件夹本身。


五、第二步:文件夹 + Job 自动创建(Job DSL)

5.1 文件夹结构

Jenkins 根目录
├── 📁 dev/                    开发团队工作区
│   ├── toolchain-check        工具链验证(5种语言并行检查)
│   ├── java-demo              Java 21 Maven 构建示例
│   ├── gitlab-cicd-demo       GitLab CI/CD 完整演示 (Multibranch)
│   ├── sonarqube-scan         SonarQube 代码扫描
│   ├── ai-assisted-build      AI 辅助构建(代码审查+测试生成+失败分析)
│   ├── gitlab-mr-trigger      GitLab MR Webhook 触发
│   └── java21                 Java 21 独立构建

├── 📁 test/                   测试团队工作区
│   └── integration-suite      集成测试(并行多维测试 + AI 报告)

├── 📁 ops/                    运维团队工作区
│   └── infra-health-check     基础设施健康检查(K8s/NFS/Harbor/GitLab)

├── 📄 toolchain-check         全局工具链验证(旧版,在根目录)
├── 📄 java-demo               全局 Java Demo(旧版)
└── 📄 sonarqube-demo          全局 SonarQube Demo(旧版)

5.2 dev/ 开发团队 Jobs

toolchain-check(工具链验证)

验证所有 Agent Pod 模板是否正常工作,并行检查 5 种语言环境:

groovy
// Pipeline 脚本(内嵌在 Job DSL 中)
def checks = [
    maven8 : ['maven' , 'echo "== Java 8 =="  && java -version && mvn -v'],
    maven21: ['maven' , 'echo "== Java 21 ==" && java -version && mvn -v'],
    node21 : ['node'  , 'echo "== Node 21 ==" && node -v && npm -v'],
    golang : ['golang', 'echo "== Golang =="  && go version'],
    python : ['python', 'echo "== Python =="  && python3 --version && pip3 --version'],
]
def stages = [:]
checks.each { agentLabel, cfg ->
    stages[agentLabel] = {
        node(agentLabel) {
            container(cfg[0]) { sh cfg[1] }
        }
    }
}
parallel stages

执行效果

T+0s  ┌─ maven8  ─→ Java 8 + Maven 3.9 ─┐
      ├─ maven21 ─→ Java 21 + Maven 3.9 ─┤
      ├─ node21  ─→ Node 21 + npm 10 ────┤  5 个 Pod 并行
      ├─ golang  ─→ Go 1.24 ─────────────┤
      └─ python  ─→ Python 3.12 + pip ───┘

java-demo(Java 构建示例)

groovy
pipeline {
    agent { label 'maven21' }
    options { timestamps() }
    stages {
        stage('准备代码') {
            steps {
                container('maven') {
                    sh """
                        mkdir -p src/main/java/demo src/test/java/demo
                        cp /examples/java-demo-pom.xml pom.xml
                        cp /examples/java-demo-App.java src/main/java/demo/App.java
                        cp /examples/java-demo-AppTest.java src/test/java/demo/AppTest.java
                    """
                }
            }
        }
        stage('构建与测试') {
            steps {
                container('maven') {
                    sh 'mvn -B -Dmaven.repo.local=$WORKSPACE/.m2 clean package'
                }
            }
            post {
                always {
                    junit allowEmptyResults: true,
                          testResults: 'target/surefire-reports/*.xml'
                }
                success {
                    archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
                }
            }
        }
    }
}

/examples 从哪来? ConfigMap jenkins-examples 挂载到 Agent Pod 的 /examples 路径,包含示例 Java 代码和 Maven POM 文件。

gitlab-cicd-demo(Multibranch Pipeline)

这是生产环境中最核心的 Job 类型——从 GitLab 仓库的每个分支自动创建 Pipeline:

groovy
// Job DSL 定义
multibranchPipelineJob('dev/gitlab-cicd-demo') {
    description('GitLab CI/CD Demo: Java + Python + AI Review')
    branchSources {
        git {
            id('gitlab-demo')
            remote('http://gitlab-webservice-default.gitlab.svc.cluster.local:8181/root/demo-app-v2.git')
            credentialsId('gitlab-git-user')
            traits {
                branchDiscovery()   // 发现所有分支
            }
        }
    }
    factory {
        workflowBranchProjectFactory {
            scriptPath('Jenkinsfile')  // 每个分支根目录的 Jenkinsfile
        }
    }
    triggers {
        periodicFolderTrigger { interval('1d') }  // 每天扫描新分支
    }
}

Multibranch 工作原理

1. Jenkins 定期扫描 GitLab 仓库的所有分支
2. 对每个包含 Jenkinsfile 的分支,自动创建一个子 Pipeline
3. 分支删除后,对应的子 Pipeline 也自动清理

Jenkins Web UI 显示:
  dev/gitlab-cicd-demo/
    ├── main     [blue]    ← main 分支,最近构建成功
    ├── develop  [blue]    ← develop 分支
    └── feature  [red]     ← feature 分支,最近构建失败

ai-assisted-build(AI 辅助构建)

使用 Shared Library 中的 AI 函数,实现完整的 AI 辅助 CI/CD:

groovy
@Library('ai-pipeline-lib') _
pipeline {
    agent { label 'maven21' }
    options { timestamps() }
    stages {
        stage('准备代码') {
            steps {
                container('maven') {
                    sh """
                        mkdir -p src/main/java/demo src/test/java/demo
                        cp /examples/java-demo-pom.xml pom.xml
                        cp /examples/java-demo-App.java src/main/java/demo/App.java
                        cp /examples/java-demo-AppTest.java src/test/java/demo/AppTest.java
                    """
                }
            }
        }
        stage('AI 代码审查') {
            steps {
                aiCodeReview(
                    patterns: ['src/main/java/**/*.java'],
                    rules: ['命名camelCase','圈复杂度<=15','方法<=80行','异常处理','禁空catch','禁硬编码密钥']
                )
            }
        }
        stage('构建') {
            steps {
                container('maven') {
                    sh 'mvn -B -Dmaven.repo.local=$WORKSPACE/.m2 clean compile'
                }
            }
        }
        stage('AI 测试生成') {
            steps {
                aiTestGeneration(
                    sourceDir: 'src/main/java', testDir: 'src/test/java', framework: 'junit5'
                )
            }
        }
        stage('测试') {
            steps {
                container('maven') {
                    sh 'mvn -B -Dmaven.repo.local=$WORKSPACE/.m2 test'
                }
            }
            post {
                always {
                    junit allowEmptyResults: true, testResults: 'target/surefire-reports/*.xml'
                }
            }
        }
        stage('打包') {
            steps {
                container('maven') {
                    sh 'mvn -B -Dmaven.repo.local=$WORKSPACE/.m2 package -DskipTests'
                }
            }
            post { success { archiveArtifacts 'target/*.jar' } }
        }
    }
    post {
        failure {
            aiFailureAnalysis(
                logPatterns: ['ERROR','FAILURE','Exception'],
                notifyChannels: ['slack','email']
            )
        }
    }
}

gitlab-mr-trigger(GitLab MR 触发 + Commit Status 回写)

groovy
@Library('ai-pipeline-lib') _
pipeline {
    agent { label 'maven21' }
    options { timestamps() }
    stages {
        stage('检出') {
            steps { container('maven') { echo "Branch: ${env.GIT_BRANCH ?: 'main'}" } }
        }
        stage('构建') {
            steps { container('maven') { sh 'echo "Building ${env.GIT_BRANCH}"' } }
        }
        stage('AI 审查') {
            steps {
                aiCodeReview(
                    patterns: ['**/*.java','**/*.go','**/*.py'],
                    rules: ['安全漏洞','性能反模式','代码重复']
                )
            }
        }
    }
    post {
        success  { updateGitlabCommitStatus name: 'jenkins', state: 'success' }
        failure  { updateGitlabCommitStatus name: 'jenkins', state: 'failed'
                   aiFailureAnalysis(logPatterns: ['ERROR'], notifyChannels: ['gitlab-note']) }
    }
}

5.3 test/ 测试团队 Jobs

integration-suite(集成测试)

groovy
@Library('ai-pipeline-lib') _
pipeline {
    agent any
    options { timestamps() }
    stages {
        stage('并行测试') {
            parallel {
                stage('API 测试') {
                    agent { label 'python' }
                    steps { container('python') {
                        sh 'pip3 install pytest requests -q; echo "API OK"' } }
                }
                stage('UI 测试') {
                    agent { label 'node21' }
                    steps { container('node') { sh 'echo "UI OK"' } }
                }
                stage('性能基线') {
                    agent { label 'golang' }
                    steps { container('golang') { sh 'echo "Perf OK"' } }
                }
            }
        }
        stage('AI 测试报告') {
            steps { aiTestReport(sources: ['api','ui','performance'], outputFormat: 'html') }
        }
    }
}

并行测试的 Agent 分配

test/integration-suite
    ├── API 测试  ─→ Agent: python Pod   (python:3.12-alpine)
    ├── UI 测试   ─→ Agent: node21 Pod   (node:21-alpine)
    └── 性能基线  ─→ Agent: golang Pod   (golang:1.24-alpine)
    3 个 Pod 同时创建,并行执行测试

5.4 ops/ 运维团队 Jobs

infra-health-check(基础设施健康检查)

groovy
@Library('ai-pipeline-lib') _
pipeline {
    agent { label 'python' }
    options { timestamps() }
    stages {
        stage('K8s') {
            steps { container('python') { sh """
                kubectl get pods -A --no-headers 2>/dev/null | head -20 || echo 'N/A'
                kubectl top nodes 2>/dev/null || echo 'N/A'
            """ } }
        }
        stage('NFS') {
            steps { container('python') { sh """
                mount | grep nfs || echo 'No NFS'
                df -h / 2>/dev/null || true
            """ } }
        }
        stage('服务') {
            steps { container('python') { sh """
                curl -sk https://ai-ear.cn:30003/v2/ -w 'Harbor:%{http_code}\n' -o /dev/null 2>/dev/null || echo 'Harbor:NA'
                curl -sk https://ai-ear.cn/-/health -w 'GitLab:%{http_code}\n' -o /dev/null 2>/dev/null || echo 'GitLab:NA'
                curl -sk https://ai-ear.cn:9010/login -w 'Jenkins:%{http_code}\n' -o /dev/null 2>/dev/null || echo 'Jenkins:NA'
            """ } }
        }
        stage('AI 运维') {
            steps { aiOpsAnalysis(
                targets: ['k8s-pods','nfs-storage','service-health'], alertThreshold: 'warning'
            ) }
        }
    }
}

5.5 完整 Job DSL JCasC 配置

ConfigMap jenkins-jenkins-config-jobs 核心结构(完整内容较长,此处展示骨架):

yaml
jobs:
  # ===== 多租户文件夹 =====
  - script: |
      folder('dev') { description('开发团队工作区') }
      folder('test') { description('测试团队工作区') }
      folder('ops') { description('运维团队工作区') }

  # ===== dev/ 工具链验证 =====
  - script: |
      pipelineJob('dev/toolchain-check') {
        description('工具链验证:java8 / java21 / node21 / golang / python')
        definition { cps { sandbox(true); script('''...parallel stages...''') } }
      }

  # ===== dev/ GitLab CI/CD Demo (Multibranch) =====
  - script: |
      multibranchPipelineJob('dev/gitlab-cicd-demo') {
        branchSources {
          git {
            id('gitlab-demo')
            remote('http://gitlab-webservice-default.gitlab.svc.cluster.local:8181/root/demo-app-v2.git')
            credentialsId('gitlab-git-user')
            traits { branchDiscovery() }
          }
        }
        factory { workflowBranchProjectFactory { scriptPath('Jenkinsfile') } }
        triggers { periodicFolderTrigger { interval('1d') } }
      }

  # ===== dev/ AI 辅助构建 / SonarQube / Java Demo / MR Trigger =====
  # ... (完整代码见上文各小节)

  # ===== test/ 集成测试 =====
  - script: |
      pipelineJob('test/integration-suite') { ... }

  # ===== ops/ 基础设施健康检查 =====
  - script: |
      pipelineJob('ops/infra-health-check') { ... }

关键配置项

  • sandbox(true):所有 Pipeline 脚本在 Groovy Sandbox 中运行,限制危险操作
  • credentialsId('gitlab-git-user'):使用 JCasC 中定义的 Git 凭证克隆代码
  • periodicFolderTrigger { interval('1d') }:Multibranch Job 每天扫描新分支

六、第三步:Agent Pod 模板(多语言构建环境)

6.1 Pod 模板总览

Label镜像CPU Req/LimitMem Req/Limit用途
defaultinbound-agent:latest-jdk21基础模板(jnlp 容器)
maven8maven:3.9-eclipse-temurin-8500m / 21Gi / 2GiJava 8 构建
maven21maven:3.9-eclipse-temurin-21500m / 21Gi / 2GiJava 21 构建
node21node:21-alpine250m / 1512Mi / 1GiNode.js 前端构建
golanggolang:1.24-alpine250m / 1512Mi / 1GiGo 语言构建
pythonpython:3.12-alpine250m / 1512Mi / 1GiPython 测试 + AI 审查

所有镜像来源192.168.122.156:30000/jenkins/ (Harbor 私有仓库)

6.2 模板继承机制

┌─────────────────────────────────────────┐
│  default 模板 (基础)                     │
│  ┌─────────────────────────────────────┐│
│  │ Container: jnlp                     ││ ← 所有模板都继承
│  │   image: inbound-agent:latest-jdk21 ││
│  │   memory: 512Mi                     ││
│  │   (Jenkins Agent 通信)              ││
│  └─────────────────────────────────────┘│
└─────────────────────────────────────────┘
        ▲  inheritFrom: default

┌───────┴─────────────────────────────────┐
│  maven21 模板 (继承 default)             │
│  ┌─────────────────────────────────────┐│
│  │ Container: jnlp (继承自 default)    ││
│  │ Container: maven (新增)             ││ ← 构建容器
│  │   image: maven:3.9-temurin-21       ││
│  │   CPU: 500m / 2                     ││
│  │   Mem: 1Gi / 2Gi                    ││
│  ├─────────────────────────────────────┤│
│  │ Volume: /examples (ConfigMap)       ││ ← 示例代码
│  │ Volume: /root/.m2 (ConfigMap)       ││ ← Maven settings.xml
│  └─────────────────────────────────────┘│
└─────────────────────────────────────────┘

inheritFrom: default 的效果

  • 自动包含 jnlp 容器(Jenkins Agent 通信必需)
  • 自动继承 default 模板的 namespace、serviceAccount 等配置
  • 只需定义额外的构建容器和 Volume

6.3 各模板详细配置

maven21(Java 21 构建)

yaml
maven21: |
  - name: maven21
    label: maven21
    inheritFrom: default
    containers:
      - name: maven
        image: "192.168.122.156:30000/jenkins/maven:3.9-eclipse-temurin-21"
        command: "sleep"
        args: "99d"
        ttyEnabled: true
        resourceRequestCpu: "500m"
        resourceRequestMemory: "1Gi"
        resourceLimitCpu: "2"
        resourceLimitMemory: "2Gi"
    volumes:
      - configMapVolume:
          configMapName: jenkins-examples
          mountPath: /examples
      - configMapVolume:
          configMapName: maven-settings
          mountPath: /root/.m2

关键配置解释

配置项说明
command: "sleep" + args: "99d"保持容器运行Jenkins 通过 kubectl exec 进入容器执行命令
ttyEnabled: true分配 TTY某些工具(如 Maven)需要 TTY 才能正常输出
resourceLimitMemory: "2Gi"内存上限 2GB防止 Maven 编译大项目时 OOM 影响其他 Pod
/root/.m2Maven settings.xml配置阿里云 Maven 镜像,加速依赖下载

python(Python 测试 + AI 审查)

yaml
python: |
  - name: python
    label: python
    inheritFrom: default
    containers:
      - name: python
        image: "192.168.122.156:30000/jenkins/python:3.12-alpine"
        command: "sleep"
        args: "99d"
        ttyEnabled: true
        resourceRequestCpu: "250m"
        resourceRequestMemory: "512Mi"
        resourceLimitCpu: "1"
        resourceLimitMemory: "1Gi"
        envVars:
          - envVar:
              key: PIP_INDEX_URL
              value: "https://mirrors.aliyun.com/pypi/simple/"
    volumes:
      - configMapVolume:
          configMapName: jenkins-examples
          mountPath: /examples

⚠️ Alpine 限制python:3.12-alpine 镜像没有 bashcurlgitjq。所有脚本必须用 #!/bin/sh,HTTP 请求用 Python urllib

golang(Go 构建)

yaml
golang: |
  - name: golang
    label: golang
    inheritFrom: default
    containers:
      - name: golang
        image: "192.168.122.156:30000/jenkins/golang:1.24-alpine"
        command: "sleep"
        args: "99d"
        ttyEnabled: true
        resourceRequestCpu: "250m"
        resourceRequestMemory: "512Mi"
        resourceLimitCpu: "1"
        resourceLimitMemory: "1Gi"
        envVars:
          - envVar:
              key: GOPROXY
              value: "https://goproxy.cn,direct"
          - envVar:
              key: GOSUMDB
              value: "sum.golang.google.cn"
    volumes:
      - configMapVolume:
          configMapName: jenkins-examples
          mountPath: /examples

node21(Node.js 前端构建)

yaml
node21: |
  - name: node21
    label: node21
    inheritFrom: default
    containers:
      - name: node
        image: "192.168.122.156:30000/jenkins/node:21-alpine"
        command: "sleep"
        args: "99d"
        ttyEnabled: true
        resourceRequestCpu: "250m"
        resourceRequestMemory: "512Mi"
        resourceLimitCpu: "1"
        resourceLimitMemory: "1Gi"
        envVars:
          - envVar:
              key: NPM_CONFIG_REGISTRY
              value: "https://registry.npmmirror.com"
    volumes:
      - configMapVolume:
          configMapName: jenkins-examples
          mountPath: /examples

maven8(Java 8 构建)

yaml
maven8: |
  - name: maven8
    label: maven8
    inheritFrom: default
    containers:
      - name: maven
        image: "192.168.122.156:30000/jenkins/maven:3.9-eclipse-temurin-8"
        command: "sleep"
        args: "99d"
        ttyEnabled: true
        resourceRequestCpu: "500m"
        resourceRequestMemory: "1Gi"
        resourceLimitCpu: "2"
        resourceLimitMemory: "2Gi"
    volumes:
      - configMapVolume:
          configMapName: jenkins-examples
          mountPath: /examples
      - configMapVolume:
          configMapName: maven-settings
          mountPath: /root/.m2

6.4 完整 Agent Helm Values

yaml
# Helm values: agent
agent:
  enabled: true
  containerCap: 200                    # 最大 200 个并发 Agent Pod
  idleMinutes: 5                       # 空闲 5 分钟后自动销毁
  maxRequestsPerHostStr: "50"          # 每个 K8s Node 最多 50 个 Pod
  image:
    registry: 192.168.122.156:30000    # Harbor 私有仓库
    repository: jenkins/inbound-agent
    tag: latest-jdk21
  podTemplates:
    maven8: |
      ...    # 见 6.3 各模板详细配置
    maven21: |
      ...
    node21: |
      ...
    golang: |
      ...
    python: |
      ...

关键参数解释

参数说明
containerCap200同时运行的最大 Agent Pod 数
idleMinutes5Pod 空闲多久后自动销毁(节省资源)
maxRequestsPerHostStr50单个 K8s Node 上的 Pod 上限

七、第四步:Shared Library(共享流水线函数)

7.1 配置方式

Shared Library 存储在 GitLab 仓库中,通过 JCasC 自动加载:

yaml
# ConfigMap: jenkins-jenkins-config-shared-libraries
unclassified:
  globalLibraries:
    libraries:
      - name: "ai-pipeline-lib"
        defaultVersion: "main"
        implicit: false              # 需要显式 @Library 引入
        allowVersionOverride: true   # 允许指定其他分支/tag
        includeInChangesets: false   # Library 变更不触发构建
        retriever:
          legacySCM:
            scm:
              git:
                userRemoteConfigs:
                  - url: "http://gitlab-webservice-default.gitlab.svc.cluster.local:8181/root/ai-pipeline-lib.git"
                    credentialsId: "gitlab-git-user"
                branches:
                  - name: "*/main"

配置解释

参数说明
implicitfalse需要在 Pipeline 中显式写 @Library('ai-pipeline-lib') _
allowVersionOverridetrue可以用 @Library('ai-pipeline-lib@v2') 指定版本
includeInChangesetsfalseLibrary 代码变更不会触发引用它的 Job 重新构建
credentialsIdgitlab-git-user使用 JCasC 中定义的 Git 凭证

7.2 在 Pipeline 中使用

groovy
// 方式一:文件顶部引入(推荐)
@Library('ai-pipeline-lib') _
pipeline { ... }

// 方式二:指定版本
@Library('ai-pipeline-lib@v2') _

// 方式三:在 Job DSL 中内嵌
definition { cps { sandbox(true); script('''
    @Library('ai-pipeline-lib') _
    pipeline { ... }
''') } }

Library 提供的函数列表

函数用途在哪个 Job 中使用
aiCodeReview()调用 Ollama 进行 AI 代码审查ai-assisted-build, gitlab-mr-trigger
aiTestGeneration()AI 自动生成单元测试ai-assisted-build
aiTestReport()AI 生成测试报告integration-suite
aiFailureAnalysis()AI 分析构建失败原因ai-assisted-build, gitlab-mr-trigger
aiOpsAnalysis()AI 分析运维指标infra-health-check

八、第五步:凭证管理(Secrets)

多租户环境中的凭证分层管理:

┌─────────────────────────────────────────────────────┐
│  Helm values: additionalSecrets                     │
│  (明文写在 values 中,部署时注入 K8s Secret)        │
│                                                     │
│  - name: gitlab-token                               │
│    value: glpat-xxx              │
│  - name: gitlab-oauth-client-id                     │
│    value: a6b688a0e26bb974...                       │
│  - name: gitlab-oauth-client-secret                 │
│    value: 41171c364bd1f5d7...                       │
│  - existingSecret: sonar-credentials (预创建的)     │
└─────────────────────────────────────────────────────┘
          │ Helm Chart 自动创建 K8s Secret
          │ 挂载到 Controller Pod:
          │   /run/secrets/additional/gitlab-token

┌─────────────────────────────────────────────────────┐
│  JCasC ConfigScripts (引用 Secret)                  │
│  secret: "${readFile:/run/secrets/additional/...}"  │
│                                                     │
│  创建的 Jenkins 凭证:                               │
│    ID: gitlab-api-token  → GitLab Root PAT          │
│    ID: gitlab-git-user   → Git 克隆凭证             │
│    ID: sonarqube-token   → SonarQube Token          │
└─────────────────────────────────────────────────────┘
          │ Pipeline 中通过 credentialsId 引用

┌─────────────────────────────────────────────────────┐
│  Pipeline / Job DSL                                 │
│  credentialsId('gitlab-git-user')  → checkout scm   │
│  credentialsId('sonarqube-token')  → SonarQube 扫描 │
│  apiTokenId: "gitlab-api-token"    → Commit Status  │
└─────────────────────────────────────────────────────┘

Helm values 中的凭证配置

yaml
controller:
  additionalSecrets:
    - name: gitlab-token
      value: glpat-xxx
    - name: gitlab-oauth-client-id
      value: xxx
    - name: gitlab-oauth-client-secret
      value: xxx
  existingSecret: sonar-credentials
  admin:
    username: xxx
    password: xxx

九、完整数据流:一个 dev 团队的构建流程

dev/gitlab-cicd-demo (Build #12) 为例:

T+0s    ┌─ 触发 ─────────────────────────────────────────────────────┐
        │ GitLab Push Event → Jenkins Webhook                        │
        │ (anonymous 用户, webhook-trigger 角色允许)                 │
        └────────────────────────────────────────────────────────────┘

T+1s    ┌─ RBAC 检查 ────────────────────────────────────────────────┐
        │ 1. anonymous 有 Overall/Read? ✓ (webhook-trigger)          │
        │ 2. anonymous 有 Job/Build on dev/gitlab-cicd-demo? ✓       │
        │ 3. → 允许触发构建                                          │
        └────────────────────────────────────────────────────────────┘

T+2s    ┌─ Agent Pod 调度 ───────────────────────────────────────────┐
        │ Jenkins 请求 K8s API 创建 Pod:                             │
        │   Pod: maven21-2zbcs (label: maven21)                      │
        │   Namespace: jenkins                                       │
        │   Containers:                                              │
        │     jnlp (inbound-agent:jdk21)                             │
        │     maven (maven:3.9-temurin-21, 2Gi mem)                  │
        │   Volumes: /examples, /root/.m2, workspace                 │
        └────────────────────────────────────────────────────────────┘

T+5s    ┌─ Stage: Checkout ──────────────────────────────────────────┐
        │ checkout scm                                               │
        │   URL: http://gitlab-...svc.cluster.local:8181/root/       │
        │        demo-app-v2.git                                     │
        │   Credentials: gitlab-git-user (JCasC 定义)                │
        │   Branch: origin/main                                      │
        └────────────────────────────────────────────────────────────┘

T+10s   ┌─ Stage: Build & Test (并行) ───────────────────────────────┐
        │                                                            │
        │  Java (maven21 Pod):  mvn test → 4/4 ✓                    │
        │  Python (python Pod): pytest → 36/36 ✓                     │
        │                                                            │
        │  * Python Stage 分配新的 python Pod (独立于 maven21 Pod)   │
        └────────────────────────────────────────────────────────────┘

T+36s   ┌─ Stage: AI Code Review ────────────────────────────────────┐
        │ Agent: python Pod                                          │
        │ ai-code-review.sh → Ollama API → 审查报告                  │
        └────────────────────────────────────────────────────────────┘

T+102s  ┌─ Post: GitLab 回写 ────────────────────────────────────────┐
        │ updateGitlabCommitStatus('jenkins', 'success')             │
        │ updateGitlabCommitStatus('ai-review', 'success')           │
        │   → 使用 gitlab-api-token 凭证                             │
        │   → 调用 GitLab API (K8s 内部地址)                         │
        └────────────────────────────────────────────────────────────┘

T+102s  ┌─ 清理 ─────────────────────────────────────────────────────┐
        │ Agent Pods 进入 idle 状态                                  │
        │ 5 分钟后 K8s 自动销毁 (idleMinutes: 5)                     │
        └────────────────────────────────────────────────────────────┘

十、验证与测试

10.1 验证 RBAC 权限隔离

bash
# 1. 验证 admin 可以看到所有文件夹
curl -s -u 'admin:xxx' \
    "https://ai-ear.cn:9010/api/json?tree=jobs[name]" | python3 -c "
import json, sys
d = json.load(sys.stdin)
for j in d.get('jobs',[]): print(f'  {j[\"name\"]}')"
# 预期输出: dev, test, ops, java-demo, sonarqube-demo, toolchain-check

# 2. 验证 dev/ 文件夹下的 Jobs
curl -s -u 'admin:xxx' \
    "https://ai-ear.cn:9010/job/dev/api/json?tree=jobs[name,color]" | python3 -c "
import json, sys
for j in json.load(sys.stdin).get('jobs',[]):
    print(f'  {j[\"name\"]:25s} [{j.get(\"color\",\"?\")}]')"
# 预期: ai-assisted-build, gitlab-cicd-demo, java-demo, sonarqube-scan...

# 3. 验证 test/ 和 ops/ 文件夹
curl -s -u 'admin:xxx' \
    "https://ai-ear.cn:9010/job/test/api/json?tree=jobs[name]" | \
    python3 -c "import json,sys; [print(f'  {j[\"name\"]}') for j in json.load(sys.stdin).get('jobs',[])]"
# 预期: integration-suite

curl -s -u 'admin:xxx' \
    "https://ai-ear.cn:9010/job/ops/api/json?tree=jobs[name]" | \
    python3 -c "import json,sys; [print(f'  {j[\"name\"]}') for j in json.load(sys.stdin).get('jobs',[])]"
# 预期: infra-health-check

10.2 验证 Agent Pod 调度

bash
export KUBECONFIG=~/.kube/config-122.31

# 触发 toolchain-check (会创建 5 种 Agent Pod)
curl -s -X POST -u 'admin:xxx' \
    "https://ai-ear.cn:9010/job/dev/job/toolchain-check/build"

# 观察 Pod 创建过程
watch -n 2 'kubectl get pods -n jenkins -l jenkins/jenkins-jenkins-agent=true \
    -o custom-columns="NAME:.metadata.name,STATUS:.status.phase,CONTAINERS:.spec.containers[*].name"'

10.3 验证 Job 自动创建

bash
# 验证 JCasC ConfigMap 存在
kubectl get configmap -n jenkins -o name | grep "jenkins-config"
# 预期: jenkins-config-gitlab-integration, jobs, rbac, shared-libraries, sonar, system

# 验证 ConfigMap 自动重载 (sidecar)
kubectl logs -n jenkins jenkins-0 -c config-reload --tail=20

# 验证凭证
curl -s -u 'admin:xxx' \
    "https://ai-ear.cn:9010/credentials/store/system/domain/_/api/json?tree=credentials[id,description]" | \
    python3 -c "import json,sys
for c in json.load(sys.stdin).get('credentials',[]):
    print(f'  {c[\"id\"]:25s} {c.get(\"description\",\"\")}')"
# 预期: gitlab-api-token, gitlab-git-user, sonarqube-token

十一、Helm values 完整配置参考

yaml
# ===== Agent 配置 =====
agent:
  enabled: true
  containerCap: 200
  idleMinutes: 5
  maxRequestsPerHostStr: "50"
  image:
    registry: 192.168.122.156:30000
    repository: jenkins/inbound-agent
    tag: latest-jdk21
  podTemplates:
    maven8: | ...    # Java 8 (见 6.3)
    maven21: | ...   # Java 21
    node21: | ...    # Node.js 21
    golang: | ...    # Go 1.24
    python: | ...    # Python 3.12

# ===== Controller 配置 =====
controller:
  resources:
    requests: { cpu: "2", memory: 6Gi }
    limits:   { cpu: "4", memory: 10Gi }
  javaOpts: >-
    -Xms4g -Xmx6g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
    -XX:+ParallelRefProcEnabled -XX:+ExplicitGCInvokesConcurrent
    -Djava.awt.headless=true -Djenkins.model.Jenkins.slaveAgentPort=50000
  numExecutors: 0
  image:
    registry: 192.168.122.156:30000
    repository: jenkins/jenkins
    tag: lts-jdk21
  jenkinsUrl: https://ai-ear.cn:9010/
  serviceType: NodePort
  nodePort: 30880
  admin:
    username: xxx
    password: xxx

  # --- 凭证 ---
  additionalSecrets:
    - { name: gitlab-token, value: glpat-xxx }
    - { name: gitlab-oauth-client-id, value: a6b688a0... }
    - { name: gitlab-oauth-client-secret, value: 41171c36... }
  existingSecret: sonar-credentials

  # --- 插件 ---
  additionalPlugins:
    - sonar
    - job-dsl              # ← Job 自动创建
    - junit
    - timestamper
    - gitlab-plugin        # ← GitLab 集成
    - role-strategy        # ← 多租户核心
    - generic-webhook-trigger
    - pipeline-utility-steps
    - oic-auth             # ← SSO 登录
    - matrix-auth

  # --- JCasC 配置脚本 ---
  JCasC:
    defaultConfig: true
    configScripts:
      rbac: |              # RBAC 权限 (见第四章)
      jobs: |              # Job DSL (见第五章)
      gitlab-integration: |  # GitLab 集成
      shared-libraries: |    # Shared Library (见第七章)
      sonar: |               # SonarQube
      system: |              # 系统信息

  # --- 高可用 ---
  podDisruptionBudget: { enabled: true, apiVersion: policy/v1, maxUnavailable: 0 }
  probes:
    startupProbe:   { failureThreshold: 60, periodSeconds: 10 }
    livenessProbe:  { failureThreshold: 12, periodSeconds: 30, timeoutSeconds: 15 }
    readinessProbe: { failureThreshold: 12, periodSeconds: 30, timeoutSeconds: 15 }
  sidecars:
    configAutoReload:
      enabled: true
      image: { registry: 192.168.122.156:30000, repository: jenkins/k8s-sidecar, tag: 2.10.1 }

# ===== 持久化存储 =====
persistence:
  enabled: true
  size: 100Gi
  accessMode: ReadWriteMany
  storageClass: nfs-nvme

十二、常见问题 & 解决方案

Q1: 用户登录后看不到任何 Job

原因:用户没有 Item Role,或者 Group 名称不匹配。

排查步骤

bash
# 1. 检查 RBAC 配置
kubectl get configmap jenkins-jenkins-config-rbac -n jenkins -o yaml

# 2. 确认用户的 Group 名称
# Jenkins → Manage Jenkins → People → 点击用户 → Groups

# 3. 确认 Pattern 匹配
# 如果 Job 路径是 "dev/my-job",Pattern 必须是 "dev/.*" 而不是 "dev/*"

解决:确保用户的 Group 在 RBAC entries 中有对应的 Item Role。

Q2: dev 团队能看到 test/ 文件夹

原因:Global Role 的 readonly 给了 authenticatedOverall/Read,这只允许登录,不会让看到具体 Job。但如果 Jenkins 的视图配置不当,可能会显示所有文件夹名。

解决:确保每个团队有自己的 View,或者使用 "My Views" 过滤。Item Role 的 Pattern 会阻止用户进入不属于他们的文件夹,但文件夹名可能在全局视图中可见。

Q3: Agent Pod 创建失败 (Pending)

现象Agent pod maven21-xxxxx is pending for 600s

bash
export KUBECONFIG=~/.kube/config-122.31

# 1. 检查 Pod 状态
kubectl get pods -n jenkins -l jenkins/jenkins-jenkins-agent=true

# 2. 查看 Pod 事件
kubectl describe pod maven21-xxxxx -n jenkins

# 3. 检查 Node 资源
kubectl top nodes

常见原因

  • Node 资源不足 → 减小 resourceLimitMemory 或增加 Node
  • 镜像拉取失败 → 检查 Harbor 仓库是否可访问
  • containerCap 达到上限 → 增大 containerCap 或等待空闲 Pod 销毁

Q4: 如何添加新团队?

以添加 staging 团队为例,需要修改 3 个地方:

1. RBAC(添加 Item Roles)

yaml
# 在 jenkins-jenkins-config-rbac 的 items 中添加:
- name: "staging-developer"
  description: "staging 团队完整权限"
  pattern: "staging/.*"
  permissions:
    - "Job/Build"
    - "Job/Cancel"
    - "Job/Read"
    - "Job/Workspace"
  entries:
    - group: "staging-team"

- name: "staging-folder"
  description: "staging 文件夹管理权限"
  pattern: "^staging$"
  permissions:
    - "Job/Configure"
    - "Job/Create"
    - "Job/Delete"
    - "Job/Build"
    - "Job/Read"
  entries:
    - group: "staging-team"

2. Job DSL(创建文件夹和 Jobs)

yaml
# 在 jenkins-jenkins-config-jobs 中添加:
- script: |
    folder('staging') { description('预发布环境工作区') }

- script: |
    pipelineJob('staging/deploy-check') {
      description('预发布部署检查')
      definition { cps { sandbox(true); script('''
        pipeline { agent { label 'python' }; options { timestamps() }
          stages {
            stage('检查') { steps { container('python') {
              sh 'echo "Staging deployment check"' } } } } }
      ''') } }
    }

3. 更新 Helm values 并重新部署

bash
helm upgrade jenkins charts/jenkins -n jenkins -f jenkins-values.yaml

ConfigMap sidecar 会自动检测变更并重新加载 JCasC 配置。

Q5: 如何限制某个团队只能读不能写?

yaml
# 创建一个只读的 Item Role
- name: "qa-readonly"
  description: "QA 团队只读权限"
  pattern: "dev/.*"
  permissions:
    - "Job/Read"              # 只能查看
    - "Job/Workspace"         # 只能查看工作区
  entries:
    - group: "qa-team"

Q6: 如何添加新的 Agent Pod 模板?

以添加 rust 模板为例,在 Helm values 中添加:

yaml
agent:
  podTemplates:
    rust: |
      - name: rust
        label: rust
        inheritFrom: default
        containers:
          - name: rust
            image: "192.168.122.156:30000/jenkins/rust:1.80-alpine"
            command: "sleep"
            args: "99d"
            ttyEnabled: true
            resourceRequestCpu: "500m"
            resourceRequestMemory: "1Gi"
            resourceLimitCpu: "2"
            resourceLimitMemory: "2Gi"
        volumes:
          - configMapVolume:
              configMapName: jenkins-examples
              mountPath: /examples

然后 helm upgrade jenkins charts/jenkins -n jenkins -f jenkins-values.yaml

Q7: JCasC 配置变更后不生效

bash
# 1. 检查 ConfigMap 是否更新
kubectl get configmap jenkins-jenkins-config-rbac -n jenkins -o yaml | head -20

# 2. 检查 sidecar 日志
kubectl logs -n jenkins jenkins-0 -c config-reload --tail=30

# 3. 手动触发 JCasC 重载
# Jenkins → Manage Jenkins → Configuration as Code → Reload existing configuration

常见原因

  • YAML 语法错误 → sidecar 会报错但不重载
  • Secret 引用不存在 → ${readFile:...} 路径无效
  • 插件未安装 → JCasC 配置引用了未安装的插件

Q8: containerCap 满了怎么办?

现象:新的构建请求排队等待,Agent Pod 不创建。

bash
# 1. 检查当前运行中的 Agent Pod 数量
kubectl get pods -n jenkins -l jenkins/jenkins-jenkins-agent=true | wc -l

# 2. 增大 containerCap (Helm values)
agent:
  containerCap: 300    # 从 200 增到 300

# 3. 减小 idleMinutes (更快释放空闲 Pod)
agent:
  idleMinutes: 3       # 从 5 减到 3

附录 A:RBAC 权限速查表

权限 ID 参考

权限 ID含义适用场景
Overall/Administer超级管理员admin
Overall/Read登录 + 查看全局所有用户
Job/Build触发构建开发者, Webhook
Job/Cancel取消构建开发者
Job/Read查看 Job 配置和构建历史开发者
Job/Workspace查看构建工作区文件开发者
Job/Configure修改 Job 配置高级开发者
Job/Create创建新 Job高级开发者
Job/Delete删除 Job高级开发者
Run/Delete删除构建记录高级开发者
Run/Replay重放构建(修改脚本后重跑)高级开发者

用户/组映射表

Jenkins 用户/组来源全局角色项目角色
admin本地账户 (Helm)admin
jenkins-admins (组)GitLab OAuthadmin
authenticated (组)Jenkins 内置readonly
anonymousWebhook Basic Authwebhook-trigger
dev-team (组)GitLab OAuthreadonlydev-developer, dev-folder
dev01 (用户)GitLab OAuthreadonlydev-developer, dev-folder
test-team (组)GitLab OAuthreadonlytest-developer, test-folder
ops-team (组)GitLab OAuthreadonlyops-developer, ops-folder

附录 B:Agent Pod 资源清单

资源汇总表

Label容器名镜像CPU ReqCPU LimitMem ReqMem Limit特殊配置
defaultjnlpinbound-agent:jdk21512MiAgent 通信
maven8mavenmaven:3.9-temurin-8500m21Gi2Gi/examples, /root/.m2
maven21mavenmaven:3.9-temurin-21500m21Gi2Gi/examples, /root/.m2
node21nodenode:21-alpine250m1512Mi1GiNPM 镜像
golanggolanggolang:1.24-alpine250m1512Mi1GiGOPROXY
pythonpythonpython:3.12-alpine250m1512Mi1GiPIP 镜像

单 Pod 资源消耗(以 maven21 为例)

Pod: maven21-xxxxx
┌─────────────────────────────────────────────┐
│ Container: jnlp                              │
│   Image: inbound-agent:latest-jdk21          │
│   Memory: 512Mi                              │
│   (Agent 通信, 不执行构建命令)              │
├─────────────────────────────────────────────┤
│ Container: maven                             │
│   Image: maven:3.9-eclipse-temurin-21        │
│   CPU Request: 500m    CPU Limit: 2 cores    │
│   Mem Request: 1Gi     Mem Limit: 2Gi        │
│   (执行 mvn compile / test / package)       │
├─────────────────────────────────────────────┤
│ Volumes:                                     │
│   /examples ← ConfigMap: jenkins-examples    │
│   /root/.m2 ← ConfigMap: maven-settings      │
│   /home/jenkins/agent ← PVC: workspace       │
└─────────────────────────────────────────────┘
总计: 2 containers, ~500m CPU, ~1.5Gi Memory

最大并发能力

containerCap: 200
├── maven21 Pods:  最多 200 个 (200 × 2Gi = 400Gi 内存)
├── python Pods:   最多 200 个 (200 × 1Gi = 200Gi 内存)
├── 混合:          受 Node 资源限制

│ 实际受限于 K8s 集群资源:
│   3 Worker Nodes × 16Gi = 48Gi 可用
│   → 实际并发: ~20-30 个 Agent Pod

📝 文档说明:本教程基于实际生产环境 (2026-08-26) 编写,所有 RBAC 配置、Job DSL、Agent Pod 模板均来自 K8s 集群中的真实 ConfigMap 和 Helm values。如有更新请修改版本号并通知团队。