1. Jenkins 概述与核心特性
🔄 持续集成
- 自动化构建与测试
- 代码质量检查
- 单元测试覆盖率
- 集成测试验证
- 构建产物管理
🚀 持续交付
- 自动化部署流程
- 多环境管理(Dev/Test/Prod)
- 蓝绿部署支持
- 金丝雀发布
- 回滚机制
📦 插件生态
- 1800+ 官方插件
- Git/SVN 版本控制
- Docker/K8s 容器化
- SonarQube 代码质量
- Harbor 镜像仓库
📊 可视化监控
- 构建历史与趋势
- 测试报告展示
- 代码覆盖率统计
- 部署状态追踪
- 告警通知集成
1.1 Jenkins 架构组成
┌─────────────────────────────────────────────────────────────────┐
│ Jenkins CI/CD Architecture │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Jenkins Controller │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Web UI │ │ Pipeline │ │ Plugin │ │ │
│ │ │ (Dashboard) │ │ Engine │ │ Manager │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Job │ │ Credentials │ │ Config │ │ │
│ │ │ Queue │ │ Store │ │ Files │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ │ │ │ │
│ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │
│ │ Static │ │ Docker │ │ Kubernetes │ │
│ │ Agent │ │ Agent │ │ Pod │ │
│ │ (VM/BM) │ │ Container │ │ (Dynamic) │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ Git │ │ │ │ Docker │ │ │ │ Helm │ │ │
│ │ │ Maven │ │ │ │ Make │ │ │ │ Kubectl│ │ │
│ │ │ Node │ │ │ │ Python │ │ │ │ Python │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ External Integrations: │
│ • GitLab/GitHub/Bitbucket (Source Code) │
│ • SonarQube (Code Quality) │
│ • Harbor/Nexus/Artifactory (Artifact Repository) │
│ • Kubernetes/Docker Swarm (Deployment Target) │
│ • Slack/Email/DingTalk (Notifications) │
│ │
└─────────────────────────────────────────────────────────────────┘
2. 系统要求与环境准备
2.1 硬件配置要求
| 规模 | CPU | 内存 | 磁盘 | 并发构建数 |
|---|---|---|---|---|
| 小型团队 | 2-4 Core | 4-8 GB | 50 GB SSD | 5-10 |
| 中型团队 | 4-8 Core | 8-16 GB | 100 GB SSD | 10-30 |
| 大型企业 | 8-16 Core | 16-32 GB | 200GB+ SSD | 30-100+ |
2.2 软件依赖
基础环境
- JDK 17 或 JDK 21(推荐)
- Docker 20.10+(容器化部署)
- Kubernetes 1.20+(K8s 部署)
- Helm 3.2.0+(Helm 部署)
- Git 2.30+(版本控制)
构建工具
- Maven 3.8+(Java 项目)
- Gradle 8.0+(Java/Kotlin)
- Node.js 18+(前端项目)
- Python 3.9+(Python 项目)
- Go 1.20+(Go 项目)
外部服务
- GitLab/GitHub(代码仓库)
- SonarQube(代码质量)
- Harbor(镜像仓库)
- Kubernetes(部署目标)
- SMTP/LDAP(邮件/认证)
2.3 端口要求
| 端口 | 协议 | 用途 | 可修改 |
|---|---|---|---|
| 8080 | HTTP | Jenkins Web 界面 | 是 |
| 443 | HTTPS | 加密 Web 访问 | 是 |
| 50000 | TCP | JNLP Agent 连接 | 是 |
| 22 | SSH | SSH Agent 连接 | 是 |
2.4 环境诊断命令
# ===== 系统检查 =====
# 1. 检查 CPU 和内存
lscpu | grep "CPU(s)"
free -h
# 2. 检查磁盘空间
df -h /
df -h /var/lib/docker
# 3. 检查 Java 版本
java -version
javac -version
# 4. 检查 Docker
docker --version
docker compose version
# 5. 检查 Kubernetes
kubectl version --client
helm version
# 6. 检查网络连接
curl -I https://github.com
curl -I https://plugins.jenkins.io
curl -I https://repo.maven.apache.org
# 7. 检查端口占用
netstat -tlnp | grep -E ':(8080|50000)'
ss -tlnp | grep -E ':(8080|50000)'
3. 部署方式选择与对比
| 部署方式 | 适用场景 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|---|
| Docker 容器 | 快速部署/开发测试 | 简单快速、易于迁移 | 数据持久化需配置 | ⭐⭐⭐⭐⭐ |
| Kubernetes | 生产环境/大规模 | 高可用、易扩展、自愈 | 复杂度高、需要 K8s | ⭐⭐⭐⭐⭐ |
| WAR 包部署 | 传统 Tomcat 环境 | 灵活可控、兼容性好 | 手动配置多、维护复杂 | ⭐⭐⭐ |
| 原生安装包 | 专用服务器 | 性能最优、完全掌控 | 安装繁琐、升级麻烦 | ⭐⭐⭐ |
💡 推荐方案:
- 开发测试/中小团队:Docker Compose 部署(简单快速)
- 生产环境/大规模:Kubernetes Helm 部署(高可用、弹性伸缩)
- 已有 Tomcat 环境:WAR 包部署(兼容现有架构)
4. Docker 容器化部署
步骤 1:拉取 Jenkins 官方镜像
# 拉取最新 LTS 版本(JDK 21)
docker pull jenkins/jenkins:lts-jdk21
# 或者指定具体版本
docker pull jenkins/jenkins:2.440.1-lts-jdk21
# 查看镜像信息
docker images jenkins/jenkins
# 国内加速镜像(可选)
docker pull registry.cn-hangzhou.aliyuncs.com/jenkinsci/jenkins:lts-jdk21
步骤 2:创建数据持久化目录
# 创建 Jenkins 主目录
mkdir -p /data/jenkins/{home,plugins,workspace,backup}
chmod -R 777 /data/jenkins
# 创建 Docker Socket 映射(用于 Docker in Docker)
ls -la /var/run/docker.sock
# 确保当前用户可以访问 docker.sock
sudo usermod -aG docker $USER
# 创建插件列表文件
cat > /data/jenkins/plugins.txt << 'EOF'
jenkins:lts-jdk21
git:latest
gitlab:latest
github:latest
kubernetes:latest
kubernetes-cli:latest
docker-plugin:latest
docker-workflow:latest
sonar:latest
pipeline:latest
pipeline-stage-view:latest
workflow-aggregator:latest
blueocean:latest
configuration-as-code:latest
credentials-binding:latest
ssh-agent:latest
nexus-artifact-uploader:latest
harbor:latest
EOF
步骤 3:编写 Docker Compose 配置
# docker-compose.yml
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts-jdk21
container_name: jenkins-master
hostname: jenkins-master
privileged: true
user: root
ports:
- "8080:8080"
- "50000:50000"
environment:
- JAVA_OPTS=-Duser.timezone=Asia/Shanghai -Xmx2g -Xms1g
- JENKINS_OPTS=--prefix=/jenkins
- TZ=Asia/Shanghai
volumes:
- /data/jenkins/home:/var/jenkins_home
- /data/jenkins/plugins:/usr/share/jenkins/ref/plugins
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
- /etc/docker:/etc/docker
networks:
- jenkins-network
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
jenkins-network:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
步骤 4:启动 Jenkins 容器
# 启动容器
cd /data/jenkins
docker compose up -d
# 查看容器状态
docker compose ps
# 查看启动日志
docker compose logs -f jenkins
# 等待 Jenkins 完全启动(约 1-2 分钟)
sleep 60
# 获取初始管理员密码
docker exec jenkins-master cat /var/jenkins_home/secrets/initialAdminPassword
# 输出类似:a1b2c3d4e5f6g7h8i9j0
# 访问 Jenkins Web 界面
echo "访问地址:http://localhost:8080/jenkins"
echo "初始密码:$(docker exec jenkins-master cat /var/jenkins_home/secrets/initialAdminPassword)"
步骤 5:初始化配置
🔧 首次登录后的配置步骤:
- 输入初始管理员密码登录
- 选择「安装推荐的插件」或「自定义插件」
- 创建第一个管理员账户
- 配置 Jenkins URL(如:http://jenkins.yourcompany.com)
- 点击「保存并完成」
- 进入「系统管理」→「全局工具配置」配置 JDK/Maven/Git 等
4.2 预装插件脚本
#!/bin/bash
# install-jenkins-plugins.sh - 批量安装 Jenkins 插件
JENKINS_URL="http://localhost:8080/jenkins"
ADMIN_USER="admin"
ADMIN_PASSWORD="your_password"
# 核心插件列表
PLUGINS=(
"git"
"gitlab"
"github"
"kubernetes"
"kubernetes-cli"
"docker-plugin"
"docker-workflow"
"sonar"
"pipeline"
"pipeline-stage-view"
"workflow-aggregator"
"blueocean"
"configuration-as-code"
"credentials-binding"
"ssh-agent"
"nexus-artifact-uploader"
"harbor"
"email-ext"
"slack"
"build-timeout"
)
# 使用 Jenkins CLI 安装插件
for plugin in "${PLUGINS[@]}"; do
echo "Installing plugin: $plugin"
java -jar jenkins-cli.jar -s $JENKINS_URL -auth $ADMIN_USER:$ADMIN_PASSWORD \
install-plugin $plugin -deploy
done
echo "✅ 所有插件安装完成!"
echo "请重启 Jenkins 使插件生效:docker restart jenkins-master"
5. Kubernetes Helm 部署
5.1 添加 Helm Chart 仓库
# 添加 Jenkins Helm Chart 仓库
helm repo add jenkins https://charts.jenkins.io
helm repo update
# 搜索可用的 Chart 版本
helm search repo jenkins --versions
# 下载 Chart 到本地
helm pull jenkins/jenkins --version 5.8.139 --untar
cd jenkins
5.2 配置 values.yaml
# values.yaml 关键配置项
jenkins:
enabled: true
controller:
replicaCount: 1
imagePullPolicy: Always
image:
registry: docker.io
repository: jenkins/jenkins
tag: lts-jdk21
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
serviceType: NodePort
servicePort: 8080
nodePort: 30080
agentListenerPort: 50000
ingress:
enabled: true
hostName: jenkins.yourcompany.com
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
tls:
- secretName: jenkins-tls
hosts:
- jenkins.yourcompany.com
persistence:
enabled: true
storageClass: nfs-client
size: 50Gi
accessMode: ReadWriteOnce
javaOpts: >-
-Duser.timezone=Asia/Shanghai
-Xmx2g
-Xms1g
-XX:+UseG1GC
installPlugins:
- kubernetes:4423.vb_59f230b_ce53
- workflow-aggregator:600.vb_57cdd26fdd7
- git:5.2.1
- gitlab:1.9.6
- github:1.38.0
- docker-plugin:1.5.0
- docker-workflow:580.vc0c340686b_54
- sonar:2.17.3
- pipeline:2.8.0
- blueocean:1.27.9
- configuration-as-code:1810.v9b_c30a_249a_4c
- credentials-binding:657.v2b_19db_7d6e6d
- ssh-agent:346.vda_a_c4f2c8e50
- email-ext:1806.v856a_01a_fa_39a_
- slack:734.v7f9ec8b_66975
agent:
enabled: true
defaultsProviderTemplate: jnlp
namespace: jenkins-agents
privileged: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
volumes:
- type: PersistentVolumeClaim
claimName: jenkins-agent-pvc
mountPath: /home/jenkins/agent
envVars:
- name: DOCKER_HOST
value: tcp://localhost:2375
sideContainers:
- name: dind
image: docker:24-dind
imagePullPolicy: Always
securityContext:
privileged: true
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
rbac:
create: true
readSecrets: true
serviceAccount:
create: true
name: jenkins
annotations: {}
5.3 创建 RBAC 权限
# 创建命名空间
kubectl create namespace jenkins
kubectl create namespace jenkins-agents
# 创建 ServiceAccount 和 RBAC
cat > jenkins-rbac.yaml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jenkins-cluster-role
rules:
- apiGroups: [""]
resources: ["pods", "pods/exec", "pods/log", "persistentvolumeclaims", "events"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["secrets", "configmaps", "services", "endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jenkins-cluster-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins-cluster-role
subjects:
- kind: ServiceAccount
name: jenkins
namespace: jenkins
EOF
kubectl apply -f jenkins-rbac.yaml
5.4 安装 Jenkins
# 使用 Helm 安装
helm install jenkins jenkins/jenkins \
--namespace jenkins \
--values values.yaml \
--version 5.8.139
# 查看安装状态
helm status jenkins -n jenkins
helm list -n jenkins
# 等待所有 Pod 就绪
kubectl get pods -n jenkins -w
# 查看 Service
kubectl get svc -n jenkins
# 获取初始管理员密码
kubectl get secret jenkins -n jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode
# 访问 Jenkins(通过 Ingress 或 NodePort)
echo "访问地址:http://jenkins.yourcompany.com"
echo "或:http://:30080"
5.5 升级与卸载
# 升级 Jenkins
helm upgrade jenkins jenkins/jenkins \
--namespace jenkins \
--values values.yaml \
--version 5.8.140
# 回滚到上一个版本
helm rollback jenkins -n jenkins
# 查看发布历史
helm history jenkins -n jenkins
# 卸载 Jenkins
helm uninstall jenkins -n jenkins
# 清理 PVC(谨慎操作,会删除数据)
kubectl delete pvc -n jenkins -l app.kubernetes.io/name=jenkins
6. 核心插件安装配置
6.1 必备核心插件清单
📦 版本控制
Git Plugin
GitLab Plugin
GitHub Plugin
Bitbucket Plugin
支持主流 Git 代码仓库,实现代码拉取、Webhook 触发、分支构建等功能。
🐳 容器化
Kubernetes Plugin
Docker Plugin
Docker Pipeline
动态 provision Jenkins Agent,实现弹性构建资源调度。
📊 代码质量
SonarQube Scanner
Checkstyle
FindBugs
JaCoCo
集成 SonarQube 进行代码质量扫描、技术债务分析、漏洞检测。
🔄 流水线
Pipeline
Pipeline Stage View
Blue Ocean
支持 Pipeline as Code,可视化编排 CI/CD 流程。
🔐 凭证管理
Credentials Binding
SSH Agent
HashiCorp Vault
安全存储和管理敏感凭证,支持密钥、用户名密码、Token 等类型。
📢 通知告警
Email Extension
Slack Notification
DingTalk
WeCom
构建结果通知,支持邮件、Slack、钉钉、企业微信等渠道。
6.2 插件管理最佳实践
💡 插件管理建议:
- 最小化原则:只安装必需的插件,减少安全风险和维护成本
- 定期更新:每月检查并更新插件,修复安全漏洞
- 版本锁定:生产环境锁定插件版本,避免自动升级导致的不兼容
- 备份配置:使用 Configuration as Code 插件备份 Jenkins 配置
- 测试环境先行:新插件先在测试环境验证,再部署到生产
7. Git 与代码仓库集成
7.1 GitLab 集成配置
# ===== Jenkins 系统配置 =====
路径:系统管理 → 系统配置 → GitLab
# 1. 添加 GitLab 服务器
Name: gitlab-prod
Server URL: https://gitlab.yourcompany.com
Credentials: 添加 GitLab API Token
Connection Timeout: 10
Read Timeout: 10
# 2. 生成 GitLab API Token
GitLab → Settings → Access Tokens
Name: jenkins-integration
Scopes: api, read_user, read_repository, write_repository
Expires at: 2027-12-31
# 3. 在 Jenkins 中添加凭证
路径:凭证 → 系统 → 全局凭证 → 添加凭证
Kind: Secret text
Secret: glpat-xxxxxxxxxxxxxxxxxxxx
ID: gitlab-api-token
Description: GitLab API Token for Jenkins
7.2 GitHub 集成配置
# ===== GitHub App 认证(推荐)=====
1. 创建 GitHub App
GitHub → Settings → Developer settings → GitHub Apps → New GitHub App
App name: jenkins-ci
Homepage URL: http://jenkins.yourcompany.com
Webhook URL: http://jenkins.yourcompany.com/github-webhook/
Permissions:
- Contents: Read & Write
- Pull requests: Read & Write
- Issues: Read & Write
- Commit statuses: Read & Write
- Repository hooks: Read & Write
2. 在 Jenkins 中配置
路径:凭证 → 添加凭证 → GitHub App
App ID: 123456
Owner: your-organization
Private Key: 上传下载的私钥文件
ID: github-app-credentials
3. 配置 Webhook
GitHub 仓库 → Settings → Webhooks → Add webhook
Payload URL: http://jenkins.yourcompany.com/github-webhook/
Content type: application/json
Secret: your-webhook-secret
Events: Push, Pull Request
7.3 多分支流水线配置
# Jenkinsfile 示例(声明式 Pipeline)
pipeline {
agent any
triggers {
pollSCM('*/5 * * * *') // 每 5 分钟检查代码变更
}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
timeout(time: 1, unit: 'HOURS')
disableConcurrentBuilds()
}
environment {
GIT_CREDENTIALS = credentials('gitlab-api-token')
SONAR_TOKEN = credentials('sonarqube-token')
}
stages {
stage('Checkout') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
env.GIT_BRANCH_NAME = env.BRANCH_NAME.replace('/', '-')
}
}
}
stage('Install Dependencies') {
steps {
sh 'npm ci || mvn dependency:resolve || pip install -r requirements.txt'
}
}
stage('Code Quality') {
steps {
script {
if (fileExists('pom.xml')) {
sh 'mvn sonar:sonar -Dsonar.projectKey=${JOB_NAME} -Dsonar.host.url=${SONAR_HOST_URL}'
} else if (fileExists('package.json')) {
sh 'npx eslint . || true'
}
}
}
}
stage('Build') {
steps {
sh 'npm run build || mvn clean package -DskipTests || python setup.py build'
}
}
stage('Test') {
steps {
sh 'npm test || mvn test || pytest tests/'
}
post {
always {
junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml,**/test-results/**/*.xml'
}
}
}
}
post {
success {
echo '✅ Build succeeded!'
}
failure {
echo '❌ Build failed!'
mail to: 'team@yourcompany.com',
subject: "Build Failed: ${env.JOB_NAME} [${env.BUILD_NUMBER}]",
body: "Please check: ${env.BUILD_URL}"
}
}
}
8. Docker 与 Harbor 集成
8.1 Docker 插件配置
# ===== 系统管理 → 系统配置 → Docker Builder =====
# 1. 配置 Docker Host
Docker Host URI: unix:///var/run/docker.sock
Docker API version: 1.41
# 2. 测试连接
点击「Test Connection」应显示成功
# 3. 添加 Docker Registry 凭证
路径:凭证 → 添加凭证 → Username with password
Username: admin
Password: Harbor12345
ID: harbor-credentials
Description: Harbor Registry Credentials
8.2 Harbor 集成配置
# ===== 系统管理 → 系统配置 → Harbor =====
# 1. 添加 Harbor 服务器
Name: harbor-prod
Server URL: https://harbor.yourcompany.com
Credentials: harbor-credentials
Skip TLS Verification: false # 生产环境不要跳过证书验证
# 2. 测试连接
点击「Test Connection」应显示成功
# 3. 在 Pipeline 中使用 Harbor
8.3 Docker 构建与推送 Pipeline
pipeline {
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: docker
image: docker:24-dind
securityContext:
privileged: true
volumeMounts:
- name: docker-sock
mountPath: /var/run
volumes:
- name: docker-sock
emptyDir: {}
'''
}
}
environment {
DOCKER_REGISTRY = 'harbor.yourcompany.com'
PROJECT_NAME = 'my-project'
IMAGE_NAME = 'backend-service'
HARBOR_CREDENTIALS_ID = 'harbor-credentials'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build Docker Image') {
steps {
script {
def imageTag = "${DOCKER_REGISTRY}/${PROJECT_NAME}/${IMAGE_NAME}:${env.BUILD_NUMBER}-${GIT_COMMIT_SHORT}"
def latestTag = "${DOCKER_REGISTRY}/${PROJECT_NAME}/${IMAGE_NAME}:latest"
sh """
docker build -t ${imageTag} .
docker tag ${imageTag} ${latestTag}
"""
env.DOCKER_IMAGE_TAG = imageTag
env.DOCKER_LATEST_TAG = latestTag
}
}
}
stage('Push to Harbor') {
steps {
withCredentials([usernamePassword(credentialsId: HARBOR_CREDENTIALS_ID,
usernameVariable: 'HARBOR_USER',
passwordVariable: 'HARBOR_PASS')]) {
sh """
echo \${HARBOR_PASS} | docker login ${DOCKER_REGISTRY} -u \${HARBOR_USER} --password-stdin
docker push ${DOCKER_IMAGE_TAG}
docker push ${DOCKER_LATEST_TAG}
"""
}
}
}
stage('Vulnerability Scan') {
steps {
script {
sh """
curl -k -X POST \\
-u admin:Harbor12345 \\
"${DOCKER_REGISTRY}/api/v2.0/projects/${PROJECT_NAME}/repositories/${IMAGE_NAME}/artifacts/latest/scan"
"""
}
}
}
}
post {
success {
echo "✅ Docker image pushed: ${DOCKER_IMAGE_TAG}"
}
cleanup {
sh """
docker logout ${DOCKER_REGISTRY}
docker rmi ${DOCKER_IMAGE_TAG} ${DOCKER_LATEST_TAG} || true
"""
}
}
}
9. Kubernetes 云配置
9.1 添加 Kubernetes 云
# ===== 系统管理 → Manage Nodes and Clouds → Configure Clouds =====
# 1. 添加新的云 → Kubernetes
Name: kubernetes-prod
Kubernetes URL: https://kubernetes.default.svc.cluster.local
Kubernetes Namespace: jenkins-agents
# 2. 配置认证
Credentials: Kubernetes service account credentials
# 选择之前创建的 jenkins ServiceAccount
# 3. 测试连接
点击「Test Connection」应显示成功
# 4. 配置 Pod 模板
Name: default
Namespace: jenkins-agents
Label: jenkins-agent
Usage: Use this node for jobs which specify the label
9.2 Pod 模板配置
# Pod Template YAML 配置
apiVersion: v1
kind: Pod
metadata:
labels:
app: jenkins-agent
spec:
serviceAccountName: jenkins
containers:
- name: jnlp
image: jenkins/inbound-agent:jdk21
args:
- '${computer.jnlpmac}'
- '${computer.name}'
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: docker-sock
mountPath: /var/run/docker.sock
- name: docker
image: docker:24-dind
securityContext:
privileged: true
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
- name: maven
image: maven:3.9.9-eclipse-temurin-21
command:
- cat
tty: true
- name: nodejs
image: node:20-alpine
command:
- cat
tty: true
volumes:
- name: workspace-volume
emptyDir: {}
- name: docker-sock
emptyDir: {}
9.3 动态 Agent 示例
pipeline {
agent {
kubernetes {
label 'jenkins-agent'
defaultContainer 'maven'
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.9.9-eclipse-temurin-21
command:
- cat
tty: true
- name: nodejs
image: node:20-alpine
command:
- cat
tty: true
- name: docker
image: docker:24-dind
securityContext:
privileged: true
'''
}
}
stages {
stage('Maven Build') {
steps {
container('maven') {
sh 'mvn -version'
sh 'mvn clean package -DskipTests'
}
}
}
stage('Node.js Build') {
steps {
container('nodejs') {
sh 'node --version'
sh 'npm --version'
sh 'npm ci && npm run build'
}
}
}
stage('Docker Build') {
steps {
container('docker') {
sh 'docker --version'
sh 'docker build -t myapp:latest .'
}
}
}
}
}
10. SonarQube 代码质量集成
10.1 SonarQube 服务器配置
# ===== 系统管理 → 系统配置 → SonarQube servers =====
# 1. 添加 SonarQube 服务器
Name: sonarqube-prod
Server URL: http://sonarqube.yourcompany.com:9000
Server authentication token: 添加 Token 凭证
# 2. 生成 SonarQube Token
SonarQube → My Account → Security → Generate Tokens
Type: User Token
Name: jenkins-integration
Expires in: 30 days
# 3. 在 Jenkins 中添加凭证
Kind: Secret text
Secret: sqp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ID: sonarqube-token
Description: SonarQube Authentication Token
10.2 Java 项目 Sonar 扫描
pipeline {
agent any
environment {
SONAR_HOST_URL = 'http://sonarqube.yourcompany.com:9000'
SONAR_TOKEN = credentials('sonarqube-token')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Compile') {
steps {
sh 'mvn clean compile'
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('sonarqube-prod') {
sh '''
mvn sonar:sonar \\
-Dsonar.projectKey=${JOB_NAME} \\
-Dsonar.projectName=${JOB_NAME} \\
-Dsonar.sources=src/main/java \\
-Dsonar.tests=src/test/java \\
-Dsonar.java.binaries=target/classes \\
-Dsonar.junit.reportsPath=target/surefire-reports \\
-Dsonar.jacoco.reportPath=target/jacoco.exec \\
-Dsonar.sourceEncoding=UTF-8
'''
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 1, unit: 'HOURS') {
waitForQualityGate abortPipeline: true
}
}
}
}
}
10.3 前端项目 Sonar 扫描
pipeline {
agent any
tools {
nodejs 'Node.js 20'
}
environment {
SONAR_HOST_URL = 'http://sonarqube.yourcompany.com:9000'
SONAR_TOKEN = credentials('sonarqube-token')
}
stages {
stage('Install Dependencies') {
steps {
sh 'npm ci'
}
}
stage('Lint & Test') {
steps {
sh 'npm run lint'
sh 'npm test -- --coverage'
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('sonarqube-prod') {
sh '''
npx sonar-scanner \\
-Dsonar.projectKey=${JOB_NAME} \\
-Dsonar.projectName=${JOB_NAME} \\
-Dsonar.sources=src \\
-Dsonar.tests=tests \\
-Dsonar.javascript.lcov.reportPaths=coverage/lcov.info \\
-Dsonar.sourceEncoding=UTF-8
'''
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 1, unit: 'HOURS') {
waitForQualityGate abortPipeline: true
}
}
}
}
}
11. Pipeline 流水线设计
11.1 完整 CI/CD Pipeline 示例
pipeline {
agent {
kubernetes {
label 'jenkins-agent'
defaultContainer 'maven'
yaml '''
apiVersion: v1
kind: Pod
spec:
serviceAccountName: jenkins
containers:
- name: maven
image: maven:3.9.9-eclipse-temurin-21
command: ["cat"]
tty: true
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
- name: docker
image: docker:24-dind
securityContext:
privileged: true
resources:
requests:
cpu: 500m
memory: 512Mi
volumes:
- name: docker-sock
emptyDir: {}
'''
}
}
parameters {
string(name: 'DEPLOY_ENV', defaultValue: 'dev', description: '部署环境:dev/test/prod')
booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: '是否跳过测试')
}
options {
buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '10'))
timeout(time: 2, unit: 'HOURS')
disableConcurrentBuilds()
timestamps()
}
environment {
DOCKER_REGISTRY = 'harbor.yourcompany.com'
PROJECT_NAME = 'backend-service'
IMAGE_NAME = 'app'
SONAR_HOST_URL = 'http://sonarqube.yourcompany.com:9000'
KUBECONFIG_CREDENTIALS_ID = 'kubeconfig-prod'
}
triggers {
pollSCM('H/5 * * * *')
cron('H 2 * * 1-5') // 工作日凌晨 2 点执行定时构建
}
stages {
stage('Checkout') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
env.BUILD_VERSION = "${env.BUILD_NUMBER}-${GIT_COMMIT_SHORT}"
}
}
}
stage('Install Dependencies') {
steps {
container('maven') {
sh 'mvn dependency:resolve'
}
}
}
stage('Code Quality') {
when {
expression { return !params.SKIP_TESTS }
}
steps {
container('maven') {
withSonarQubeEnv('sonarqube-prod') {
sh """
mvn sonar:sonar \\
-Dsonar.projectKey=${PROJECT_NAME} \\
-Dsonar.sources=src/main/java \\
-Dsonar.tests=src/test/java \\
-Dsonar.java.binaries=target/classes
"""
}
}
}
}
stage('Unit Test') {
when {
expression { return !params.SKIP_TESTS }
}
steps {
container('maven') {
sh 'mvn test'
}
}
post {
always {
junit allowEmptyResults: true, testResults: 'target/surefire-reports/*.xml'
jacoco execPattern: 'target/jacoco.exec'
}
}
}
stage('Build Package') {
steps {
container('maven') {
sh 'mvn clean package -DskipTests'
}
}
post {
success {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
stage('Build Docker Image') {
steps {
container('docker') {
script {
env.DOCKER_IMAGE = "${DOCKER_REGISTRY}/${PROJECT_NAME}/${IMAGE_NAME}:${BUILD_VERSION}"
env.DOCKER_LATEST = "${DOCKER_REGISTRY}/${PROJECT_NAME}/${IMAGE_NAME}:latest"
}
sh """
docker build -t ${DOCKER_IMAGE} -t ${DOCKER_LATEST} .
"""
}
}
}
stage('Push to Harbor') {
steps {
container('docker') {
withCredentials([usernamePassword(credentialsId: 'harbor-credentials',
usernameVariable: 'HARBOR_USER',
passwordVariable: 'HARBOR_PASS')]) {
sh """
echo \${HARBOR_PASS} | docker login ${DOCKER_REGISTRY} -u \${HARBOR_USER} --password-stdin
docker push ${DOCKER_IMAGE}
docker push ${DOCKER_LATEST}
"""
}
}
}
}
stage('Deploy to Kubernetes') {
when {
expression { return params.DEPLOY_ENV != 'none' }
}
steps {
container('maven') {
withKubeConfig([credentialsId: KUBECONFIG_CREDENTIALS_ID]) {
sh """
kubectl set image deployment/${PROJECT_NAME} \\
${PROJECT_NAME}=${DOCKER_IMAGE} \\
-n ${DEPLOY_ENV}
kubectl rollout status deployment/${PROJECT_NAME} -n ${DEPLOY_ENV} --timeout=300s
kubectl get pods -l app=${PROJECT_NAME} -n ${DEPLOY_ENV}
"""
}
}
}
}
stage('Smoke Test') {
when {
expression { return params.DEPLOY_ENV == 'prod' }
}
steps {
sh """
curl -f http://${PROJECT_NAME}.${DEPLOY_ENV}.yourcompany.com/health || exit 1
"""
}
}
}
post {
always {
cleanWs()
container('docker') {
sh """
docker logout ${DOCKER_REGISTRY} || true
docker rmi ${DOCKER_IMAGE} ${DOCKER_LATEST} || true
"""
}
}
success {
echo "✅ Build #${BUILD_NUMBER} succeeded!"
slackSend(color: 'good', message: "Build #${BUILD_NUMBER} succeeded: ${BUILD_URL}")
}
failure {
echo "❌ Build #${BUILD_NUMBER} failed!"
slackSend(color: 'danger', message: "Build #${BUILD_NUMBER} failed: ${BUILD_URL}")
emailext(
to: 'team@yourcompany.com',
subject: "Build Failed: ${JOB_NAME} [${BUILD_NUMBER}]",
body: "Please check: ${BUILD_URL}\n\nCommit: ${GIT_COMMIT_SHORT}\nAuthor: ${GIT_AUTHOR_NAME}"
)
}
unstable {
echo "⚠️ Build #${BUILD_NUMBER} is unstable!"
}
}
}
12. 安全加固与运维管理
12.1 安全加固措施
🔐 访问控制
- 启用矩阵授权策略
- 配置 LDAP/AD 集成
- 强制 HTTPS 访问
- 启用 CSRF 保护
- 配置会话超时
🛡️ 凭证安全
- 使用 HashiCorp Vault
- 启用凭证加密存储
- 定期轮换密钥
- 限制凭证访问范围
- 审计凭证使用记录
🔒 网络安全
- 配置防火墙规则
- 限制 Agent 连接 IP
- 启用 Script Security
- 禁用 Groovy 沙箱逃逸
- 配置 CSP 策略
📝 审计日志
- 启用审计跟踪插件
- 记录所有配置变更
- 监控异常登录行为
- 定期审查操作日志
- 配置日志归档策略
12.2 备份与恢复
#!/bin/bash
# backup-jenkins.sh - Jenkins 备份脚本
JENKINS_HOME="/data/jenkins/home"
BACKUP_DIR="/backup/jenkins"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
# 创建备份目录
mkdir -p ${BACKUP_DIR}/{config,plugins,jobs}
# 1. 停止 Jenkins(可选,确保数据一致性)
curl -X POST http://admin:token@localhost:8080/jenkins/exit
sleep 10
# 2. 备份 JENKINS_HOME
tar -czf ${BACKUP_DIR}/jenkins_home_${DATE}.tar.gz \\
--exclude='*.log' \\
--exclude='logs/*' \\
--exclude='war/*' \\
${JENKINS_HOME}
# 3. 导出配置(使用 Configuration as Code)
curl -u admin:token \\
http://localhost:8080/jenkins/configuration-as-code/export \\
> ${BACKUP_DIR}/config/jenkins-casc-${DATE}.yaml
# 4. 备份 Job 配置
find ${JENKINS_HOME}/jobs -name config.xml \\
-exec cp --parents {} ${BACKUP_DIR}/jobs/ \\;
# 5. 启动 Jenkins
docker start jenkins-master
sleep 30
# 6. 删除旧备份
find ${BACKUP_DIR} -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete
echo "✅ Backup completed: ${DATE}"
echo "Backup file: ${BACKUP_DIR}/jenkins_home_${DATE}.tar.gz"
12.3 监控与告警
# Prometheus 监控指标端点
curl http://admin:token@localhost:8080/jenkins/prometheus
# 主要监控指标:
• default_jvm_threads_current: JVM 当前线程数
• default_jvm_memory_used_bytes: JVM 内存使用量
• jenkins_queue_size_value: 构建队列长度
• jenkins_runs_success_total: 成功构建总数
• jenkins_runs_failure_total: 失败构建总数
• jenkins_builds_duration_milliseconds_summary: 构建耗时
# Grafana 告警规则示例
groups:
- name: jenkins-alerts
rules:
- alert: JenkinsDown
expr: up{job="jenkins"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Jenkins 实例宕机"
- alert: JenkinsQueueTooLong
expr: jenkins_queue_size_value > 50
for: 5m
labels:
severity: warning
annotations:
summary: "Jenkins 构建队列过长"
- alert: JenkinsHighFailureRate
expr: rate(jenkins_runs_failure_total[1h]) / rate(jenkins_runs_success_total[1h]) > 0.3
for: 15m
labels:
severity: warning
annotations:
summary: "Jenkins 构建失败率过高"
12.4 性能优化建议
⚡ 性能优化技巧:
- JVM 调优:根据负载调整-Xmx/-Xms 参数,使用 G1 GC
- 并行构建:增加 Executor 数量,使用分布式 Agent
- 缓存优化:配置 Maven/NPM 本地仓库缓存,使用 S3 存储构建产物
- 数据库优化:对于大型实例,考虑将构建历史迁移到外部数据库
- 插件精简:禁用不使用的插件,减少内存占用
- 日志轮转:配置日志大小限制和保留策略,避免磁盘爆满