主题
Jenkins 多租户保姆级教程
版本: 1.0 | 日期: 2026-08-26
基于真实生产环境编写(K8s + JCasC + role-strategy + Job DSL)
技术栈: Jenkins LTS JDK21 (Helm) + GitLab v19.2 + RKE2 K8s
📋 目录
- 一、总览:Jenkins 多租户架构
- 二、前置条件
- 三、核心概念:三层隔离模型
- 四、第一步:RBAC 权限配置(角色 + 权限 + 用户)
- 五、第二步:文件夹 + Job 自动创建(Job DSL)
- 六、第三步:Agent Pod 模板(多语言构建环境)
- 七、第四步:Shared Library(共享流水线函数)
- 八、第五步:凭证管理(Secrets)
- 九、完整数据流:一个 dev 团队的构建流程
- 十、验证与测试
- 十一、Helm values 完整配置参考
- 十二、常见问题 & 解决方案
- 附录 A:RBAC 权限速查表
- 附录 B:Agent Pod 资源清单
一、总览: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 |
| Jenkins | LTS JDK21 (Helm) | CI/CD 引擎 |
| Harbor | v2.12 | Agent 镜像私有仓库 |
| GitLab | v19.2 | 代码仓库 + OAuth SSO |
2.2 必需的 Jenkins 插件
在 Helm values 的 controller.additionalPlugins 中安装:
| 插件 | 版本 | 用途 |
|---|---|---|
role-strategy | 898.v | 多租户核心:基于角色的权限控制 |
job-dsl | 1.91 | 自动创建 Job:声明式定义文件夹和流水线 |
cloudbees-folder | 6.1106 | 文件夹:组织 Job 到团队空间 |
workflow-multibranch | 841.v | 多分支:Git 分支自动创建 Pipeline |
git | 5.10.1 | Git 操作:checkout scm |
gitlab-plugin | 1.9.16 | GitLab 集成:Commit Status 回写 |
pipeline-utility-steps | 3.810 | 工具步骤:readJSON, writeJSON |
oic-auth | — | SSO 登录:OpenID Connect (GitLab OAuth) |
matrix-auth | — | 辅助:矩阵权限视图 |
generic-webhook-trigger | 2.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.global | admin, readonly, webhook-trigger |
| Item Roles | 特定 Job/文件夹 | roles.items | dev-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 将其识别为 anonymous。webhook-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/Configure、Job/Create、Job/Delete、Run/Delete、Run/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 权限矩阵总览
| 角色 | 类型 | 匹配模式 | 绑定对象 | Build | Cancel | Read | Workspace | Configure | Create | Delete | Run/Delete | Run/Replay |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| admin | Global | — | admin, jenkins-admins | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| readonly | Global | — | authenticated | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| webhook-trigger | Global | — | anonymous | ✓ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| dev-developer | Item | dev/.* | dev-team, dev01 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| dev-folder | Item | ^dev$ | dev-team, dev01 | ✓ | ✗ | ✓ | ✗ | ✓ | ✓ | ✓ | ✗ | ✗ |
| test-developer | Item | test/.* | test-team | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
| test-folder | Item | ^test$ | test-team | ✓ | ✗ | ✓ | ✗ | ✓ | ✓ | ✓ | ✗ | ✗ |
| ops-developer | Item | ops/.* | ops-team | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| ops-folder | Item | ^ops$ | ops-team | ✓ | ✗ | ✓ | ✗ | ✓ | ✓ | ✓ | ✗ | ✗ |
4.5 Pattern 匹配规则详解
Item Role 的 pattern 字段使用正则表达式匹配 Job 全路径:
| Pattern | 匹配 | 不匹配 | 说明 |
|---|---|---|---|
dev/.* | dev/toolchain-check | dev | .* 匹配 / 后的所有内容 |
^dev$ | dev | dev/toolchain-check | ^...$ 精确匹配文件夹名 |
test/.* | test/integration-suite | test | 同上 |
ops/.* | ops/infra-health-check | ops | 同上 |
为什么要两个 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从哪来? ConfigMapjenkins-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/Limit | Mem Req/Limit | 用途 |
|---|---|---|---|---|
default | inbound-agent:latest-jdk21 | — | — | 基础模板(jnlp 容器) |
maven8 | maven:3.9-eclipse-temurin-8 | 500m / 2 | 1Gi / 2Gi | Java 8 构建 |
maven21 | maven:3.9-eclipse-temurin-21 | 500m / 2 | 1Gi / 2Gi | Java 21 构建 |
node21 | node:21-alpine | 250m / 1 | 512Mi / 1Gi | Node.js 前端构建 |
golang | golang:1.24-alpine | 250m / 1 | 512Mi / 1Gi | Go 语言构建 |
python | python:3.12-alpine | 250m / 1 | 512Mi / 1Gi | Python 测试 + 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/.m2 | Maven 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镜像没有bash、curl、git、jq。所有脚本必须用#!/bin/sh,HTTP 请求用 Pythonurllib。
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: /examplesnode21(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: /examplesmaven8(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/.m26.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: |
...关键参数解释:
| 参数 | 值 | 说明 |
|---|---|---|
containerCap | 200 | 同时运行的最大 Agent Pod 数 |
idleMinutes | 5 | Pod 空闲多久后自动销毁(节省资源) |
maxRequestsPerHostStr | 50 | 单个 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"配置解释:
| 参数 | 值 | 说明 |
|---|---|---|
implicit | false | 需要在 Pipeline 中显式写 @Library('ai-pipeline-lib') _ |
allowVersionOverride | true | 可以用 @Library('ai-pipeline-lib@v2') 指定版本 |
includeInChangesets | false | Library 代码变更不会触发引用它的 Job 重新构建 |
credentialsId | gitlab-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-check10.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 给了 authenticated 组 Overall/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.yamlConfigMap 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 OAuth | admin | — |
authenticated (组) | Jenkins 内置 | readonly | — |
anonymous | Webhook Basic Auth | webhook-trigger | — |
dev-team (组) | GitLab OAuth | readonly | dev-developer, dev-folder |
dev01 (用户) | GitLab OAuth | readonly | dev-developer, dev-folder |
test-team (组) | GitLab OAuth | readonly | test-developer, test-folder |
ops-team (组) | GitLab OAuth | readonly | ops-developer, ops-folder |
附录 B:Agent Pod 资源清单
资源汇总表
| Label | 容器名 | 镜像 | CPU Req | CPU Limit | Mem Req | Mem Limit | 特殊配置 |
|---|---|---|---|---|---|---|---|
| default | jnlp | inbound-agent:jdk21 | — | — | 512Mi | — | Agent 通信 |
| maven8 | maven | maven:3.9-temurin-8 | 500m | 2 | 1Gi | 2Gi | /examples, /root/.m2 |
| maven21 | maven | maven:3.9-temurin-21 | 500m | 2 | 1Gi | 2Gi | /examples, /root/.m2 |
| node21 | node | node:21-alpine | 250m | 1 | 512Mi | 1Gi | NPM 镜像 |
| golang | golang | golang:1.24-alpine | 250m | 1 | 512Mi | 1Gi | GOPROXY |
| python | python | python:3.12-alpine | 250m | 1 | 512Mi | 1Gi | PIP 镜像 |
单 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。如有更新请修改版本号并通知团队。