5.1 自由风格项目
项目创建和基本配置
创建自由风格项目:
步骤:
1. 点击"新建任务"
2. 输入项目名称
3. 选择"构建一个自由风格的软件项目"
4. 点击"确定"
基本配置选项:
项目配置页面结构:
├── 常规
├── 源码管理
├── 构建触发器
├── 构建环境
├── 构建
└── 构建后操作
源码管理配置
Git配置示例:
仓库URL:https://github.com/company/myapp.git
凭据:选择已配置的Git凭据
分支:*/main
高级选项:
✓ 浅克隆
✓ 克隆深度:1
✓ 构建前清理工作空间
✓ 检出到子目录:src
SVN配置示例:
仓库URL:https://svn.company.com/repos/myapp/trunk
凭据:SVN用户名密码
本地模块目录:.
高级选项:
✓ 使用svn update
✓ 排除区域:target/, *.log
✓ 包含区域:src/, pom.xml
多仓库配置:
主仓库:
- URL: https://github.com/company/myapp.git
- 分支: */main
- 目录: app
依赖仓库:
- URL: https://github.com/company/shared-lib.git
- 分支: */v1.0
- 目录: lib
配置仓库:
- URL: https://github.com/company/config.git
- 分支: */production
- 目录: config
构建触发器
定时构建配置:
# Cron表达式示例
# 每天凌晨2点构建
0 2 * * *
# 工作日每小时构建
0 * * * 1-5
# 每15分钟构建一次
H/15 * * * *
# 每周日凌晨3点构建
0 3 * * 0
# 每月1号凌晨1点构建
0 1 1 * *
SCM轮询配置:
# 轮询策略
# 每5分钟检查一次
H/5 * * * *
# 工作时间每分钟检查
* 9-17 * * 1-5
# 忽略提交消息包含[skip ci]的提交
# 在高级选项中配置排除策略
Webhook触发配置:
# GitHub Webhook URL
http://jenkins-server:8080/github-webhook/
# GitLab Webhook URL
http://jenkins-server:8080/project/myapp-build
# 通用Webhook URL
http://jenkins-server:8080/generic-webhook-trigger/invoke?token=myapp-token
构建步骤配置
Shell脚本构建:
#!/bin/bash
set -e # 遇到错误立即退出
echo "=== 开始构建 ==="
echo "构建时间: $(date)"
echo "构建编号: ${BUILD_NUMBER}"
echo "工作空间: ${WORKSPACE}"
# 环境检查
echo "=== 环境检查 ==="
java -version
mvn -version
node --version
npm --version
# 依赖安装
echo "=== 安装依赖 ==="
if [ -f "package.json" ]; then
npm install
fi
if [ -f "pom.xml" ]; then
mvn dependency:resolve
fi
# 代码检查
echo "=== 代码检查 ==="
if [ -f "package.json" ]; then
npm run lint || echo "Lint检查失败,但继续构建"
fi
# 单元测试
echo "=== 运行测试 ==="
if [ -f "pom.xml" ]; then
mvn test
elif [ -f "package.json" ]; then
npm test
fi
# 构建应用
echo "=== 构建应用 ==="
if [ -f "pom.xml" ]; then
mvn clean package -DskipTests
elif [ -f "package.json" ]; then
npm run build
fi
# 构建Docker镜像
echo "=== 构建Docker镜像 ==="
if [ -f "Dockerfile" ]; then
docker build -t myapp:${BUILD_NUMBER} .
docker tag myapp:${BUILD_NUMBER} myapp:latest
fi
echo "=== 构建完成 ==="
Windows批处理构建:
@echo off
setlocal enabledelayedexpansion
echo === 开始构建 ===
echo 构建时间: %date% %time%
echo 构建编号: %BUILD_NUMBER%
echo 工作空间: %WORKSPACE%
REM 环境检查
echo === 环境检查 ===
java -version
if errorlevel 1 (
echo Java未安装或未配置PATH
exit /b 1
)
mvn -version
if errorlevel 1 (
echo Maven未安装或未配置PATH
exit /b 1
)
REM 清理旧文件
echo === 清理环境 ===
if exist target rmdir /s /q target
if exist node_modules rmdir /s /q node_modules
REM 依赖安装
echo === 安装依赖 ===
if exist package.json (
npm install
if errorlevel 1 (
echo npm install失败
exit /b 1
)
)
if exist pom.xml (
mvn dependency:resolve
if errorlevel 1 (
echo Maven依赖解析失败
exit /b 1
)
)
REM 运行测试
echo === 运行测试 ===
if exist pom.xml (
mvn test
if errorlevel 1 (
echo 测试失败
exit /b 1
)
) else if exist package.json (
npm test
if errorlevel 1 (
echo 测试失败
exit /b 1
)
)
REM 构建应用
echo === 构建应用 ===
if exist pom.xml (
mvn clean package -DskipTests
if errorlevel 1 (
echo Maven构建失败
exit /b 1
)
) else if exist package.json (
npm run build
if errorlevel 1 (
echo npm构建失败
exit /b 1
)
)
echo === 构建完成 ===
Maven构建配置:
<!-- Maven构建步骤配置 -->
<maven>
<goals>clean compile test package</goals>
<pom>pom.xml</pom>
<properties>
<maven.test.failure.ignore>false</maven.test.failure.ignore>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<settings>
<globalSettings>/var/lib/jenkins/maven-settings.xml</globalSettings>
</settings>
<jvmOptions>-Xmx2048m -XX:MaxPermSize=512m</jvmOptions>
</maven>
构建后操作
归档产物配置:
要归档的文件:
- target/*.jar
- target/*.war
- dist/**/*
- build/libs/*.jar
- *.zip
- docs/**/*.pdf
高级选项:
✓ 仅当构建成功时归档
✓ 指纹识别归档文件
✓ 允许空归档
测试结果发布:
<!-- JUnit测试结果 -->
<testResults>
<pattern>target/surefire-reports/*.xml</pattern>
<pattern>target/failsafe-reports/*.xml</pattern>
<keepLongStdio>true</keepLongStdio>
<testDataPublishers>
<attachments>true</attachments>
</testDataPublishers>
</testResults>
<!-- TestNG测试结果 -->
<testNGResults>
<pattern>target/surefire-reports/testng-results.xml</pattern>
<escapeTestDescp>true</escapeTestDescp>
<escapeExceptionMsg>true</escapeExceptionMsg>
</testNGResults>
邮件通知配置:
邮件通知设置:
收件人:$DEFAULT_RECIPIENTS, dev-team@company.com
主题:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!
内容:
构建项目:$PROJECT_NAME
构建编号:$BUILD_NUMBER
构建状态:$BUILD_STATUS
构建URL:$BUILD_URL
变更集:$CHANGES
触发条件:
✓ 构建失败
✓ 构建不稳定
✓ 构建恢复正常
✓ 首次失败
5.2 Pipeline项目
Pipeline基础概念
Pipeline类型:
声明式Pipeline (Declarative):
- 结构化语法
- 易于理解和维护
- 内置验证
- 推荐使用
脚本式Pipeline (Scripted):
- 基于Groovy
- 更灵活
- 适合复杂逻辑
- 需要更多经验
Pipeline结构:
// 声明式Pipeline结构
pipeline {
agent any
environment {
// 环境变量
}
parameters {
// 构建参数
}
triggers {
// 触发器
}
tools {
// 工具配置
}
stages {
stage('Stage Name') {
steps {
// 构建步骤
}
}
}
post {
// 构建后操作
}
}
声明式Pipeline示例
基础Java项目Pipeline:
pipeline {
agent any
environment {
MAVEN_OPTS = '-Xmx2048m'
JAVA_HOME = '/usr/lib/jvm/java-11-openjdk'
}
parameters {
choice(
name: 'ENVIRONMENT',
choices: ['dev', 'test', 'staging', 'prod'],
description: '部署环境'
)
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: '跳过测试'
)
string(
name: 'BRANCH_NAME',
defaultValue: 'main',
description: '构建分支'
)
}
triggers {
cron('H 2 * * *') // 每天凌晨2点
pollSCM('H/5 * * * *') // 每5分钟检查SCM
}
tools {
maven 'Maven-3.8.6'
jdk 'JDK-11'
}
stages {
stage('Checkout') {
steps {
echo "检出代码分支: ${params.BRANCH_NAME}"
git branch: "${params.BRANCH_NAME}",
url: 'https://github.com/company/myapp.git',
credentialsId: 'github-credentials'
}
}
stage('Build') {
steps {
echo '开始构建...'
sh 'mvn clean compile'
}
}
stage('Test') {
when {
not { params.SKIP_TESTS }
}
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Integration Tests') {
steps {
sh 'mvn verify -Dskip.unit.tests=true'
}
post {
always {
junit 'target/failsafe-reports/*.xml'
}
}
}
}
}
stage('Code Quality') {
parallel {
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Security Scan') {
steps {
sh 'mvn org.owasp:dependency-check-maven:check'
}
post {
always {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target/dependency-check-report',
reportFiles: 'dependency-check-report.html',
reportName: 'Security Report'
])
}
}
}
}
}
stage('Package') {
steps {
sh 'mvn package -DskipTests'
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
stage('Docker Build') {
steps {
script {
def image = docker.build("myapp:${env.BUILD_NUMBER}")
image.tag("latest")
if (params.ENVIRONMENT == 'prod') {
image.tag("stable")
}
}
}
}
stage('Deploy') {
when {
anyOf {
branch 'main'
expression { params.ENVIRONMENT != 'dev' }
}
}
steps {
script {
switch(params.ENVIRONMENT) {
case 'dev':
deployToDev()
break
case 'test':
deployToTest()
break
case 'staging':
deployToStaging()
break
case 'prod':
deployToProduction()
break
}
}
}
}
}
post {
always {
echo '清理工作空间...'
cleanWs()
}
success {
echo '构建成功!'
emailext (
subject: "✅ 构建成功: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: """构建成功完成!
项目: ${env.JOB_NAME}
构建号: ${env.BUILD_NUMBER}
环境: ${params.ENVIRONMENT}
构建URL: ${env.BUILD_URL}
""",
to: "${env.CHANGE_AUTHOR_EMAIL}, dev-team@company.com"
)
}
failure {
echo '构建失败!'
emailext (
subject: "❌ 构建失败: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: """构建失败!
项目: ${env.JOB_NAME}
构建号: ${env.BUILD_NUMBER}
失败阶段: ${env.STAGE_NAME}
构建URL: ${env.BUILD_URL}
控制台: ${env.BUILD_URL}console
""",
to: "${env.CHANGE_AUTHOR_EMAIL}, dev-team@company.com"
)
}
unstable {
echo '构建不稳定!'
}
changed {
echo '构建状态发生变化!'
}
}
}
// 部署函数定义
def deployToDev() {
echo '部署到开发环境...'
sh '''
kubectl config use-context dev-cluster
kubectl set image deployment/myapp myapp=myapp:${BUILD_NUMBER}
kubectl rollout status deployment/myapp
'''
}
def deployToTest() {
echo '部署到测试环境...'
input message: '确认部署到测试环境?', ok: '部署',
submitterParameter: 'DEPLOYER'
sh '''
kubectl config use-context test-cluster
kubectl set image deployment/myapp myapp=myapp:${BUILD_NUMBER}
kubectl rollout status deployment/myapp
'''
}
def deployToStaging() {
echo '部署到预发布环境...'
input message: '确认部署到预发布环境?', ok: '部署',
submitterParameter: 'DEPLOYER'
sh '''
kubectl config use-context staging-cluster
kubectl set image deployment/myapp myapp=myapp:${BUILD_NUMBER}
kubectl rollout status deployment/myapp
'''
}
def deployToProduction() {
echo '部署到生产环境...'
timeout(time: 5, unit: 'MINUTES') {
input message: '确认部署到生产环境?这是一个重要操作!', ok: '部署到生产',
submitterParameter: 'DEPLOYER',
submitter: 'admin,release-manager'
}
// 蓝绿部署
sh '''
kubectl config use-context prod-cluster
# 创建新版本部署
kubectl create deployment myapp-green --image=myapp:${BUILD_NUMBER}
kubectl scale deployment myapp-green --replicas=3
# 等待新版本就绪
kubectl rollout status deployment/myapp-green
# 切换流量
kubectl patch service myapp -p '{"spec":{"selector":{"version":"green"}}}'
# 验证部署
sleep 30
# 删除旧版本
kubectl delete deployment myapp-blue || true
kubectl label deployment myapp-green version=blue
'''
}
脚本式Pipeline示例
复杂逻辑Pipeline:
node {
def mvnHome
def dockerImage
def buildVersion
try {
stage('Preparation') {
// 获取Maven工具
mvnHome = tool 'Maven-3.8.6'
// 生成构建版本号
buildVersion = "${env.BUILD_NUMBER}-${env.GIT_COMMIT.take(7)}"
echo "构建版本: ${buildVersion}"
}
stage('Checkout') {
// 检出代码
checkout scm
// 获取Git信息
def gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
def gitBranch = sh(returnStdout: true, script: 'git rev-parse --abbrev-ref HEAD').trim()
def gitAuthor = sh(returnStdout: true, script: 'git log -1 --pretty=format:"%an"').trim()
echo "Git提交: ${gitCommit}"
echo "Git分支: ${gitBranch}"
echo "提交作者: ${gitAuthor}"
// 设置构建描述
currentBuild.description = "${gitBranch} - ${gitCommit.take(7)}"
}
stage('Build') {
// 设置Maven环境
withEnv(["MVN_HOME=${mvnHome}", "PATH+MAVEN=${mvnHome}/bin"]) {
// 检查项目类型
if (fileExists('pom.xml')) {
echo '检测到Maven项目'
sh 'mvn clean compile'
} else if (fileExists('build.gradle')) {
echo '检测到Gradle项目'
sh './gradlew clean build'
} else if (fileExists('package.json')) {
echo '检测到Node.js项目'
sh 'npm install && npm run build'
} else {
error '未识别的项目类型'
}
}
}
stage('Test') {
parallel (
"Unit Tests": {
try {
if (fileExists('pom.xml')) {
sh "${mvnHome}/bin/mvn test"
} else if (fileExists('build.gradle')) {
sh './gradlew test'
} else if (fileExists('package.json')) {
sh 'npm test'
}
} catch (Exception e) {
currentBuild.result = 'UNSTABLE'
echo "单元测试失败: ${e.getMessage()}"
} finally {
// 发布测试结果
if (fileExists('target/surefire-reports/*.xml')) {
junit 'target/surefire-reports/*.xml'
}
}
},
"Code Coverage": {
try {
if (fileExists('pom.xml')) {
sh "${mvnHome}/bin/mvn jacoco:report"
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target/site/jacoco',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
} catch (Exception e) {
echo "代码覆盖率报告生成失败: ${e.getMessage()}"
}
}
)
}
stage('Quality Gate') {
// SonarQube质量门禁
withSonarQubeEnv('SonarQube') {
if (fileExists('pom.xml')) {
sh "${mvnHome}/bin/mvn sonar:sonar"
}
}
// 等待质量门禁结果
timeout(time: 10, unit: 'MINUTES') {
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "质量门禁失败: ${qg.status}"
}
}
}
stage('Package') {
if (fileExists('pom.xml')) {
sh "${mvnHome}/bin/mvn package -DskipTests"
// 归档产物
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
// 构建Docker镜像
if (fileExists('Dockerfile')) {
dockerImage = docker.build("myapp:${buildVersion}")
dockerImage.tag('latest')
}
}
}
stage('Security Scan') {
// 依赖安全扫描
try {
sh "${mvnHome}/bin/mvn org.owasp:dependency-check-maven:check"
} catch (Exception e) {
echo "安全扫描警告: ${e.getMessage()}"
currentBuild.result = 'UNSTABLE'
}
// Docker镜像安全扫描
if (dockerImage) {
try {
sh "trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:${buildVersion}"
} catch (Exception e) {
echo "Docker镜像安全扫描发现高危漏洞: ${e.getMessage()}"
currentBuild.result = 'UNSTABLE'
}
}
}
stage('Deploy') {
// 根据分支决定部署策略
def gitBranch = env.GIT_BRANCH ?: 'unknown'
switch(gitBranch) {
case 'origin/main':
case 'main':
echo '部署到生产环境'
deployToProduction(dockerImage, buildVersion)
break
case 'origin/develop':
case 'develop':
echo '部署到开发环境'
deployToDevelopment(dockerImage, buildVersion)
break
case ~/origin\/feature\/.*/':
echo '功能分支,部署到测试环境'
deployToTest(dockerImage, buildVersion)
break
default:
echo "跳过部署,分支: ${gitBranch}"
}
}
} catch (Exception e) {
currentBuild.result = 'FAILURE'
throw e
} finally {
stage('Cleanup') {
// 清理Docker镜像
if (dockerImage) {
sh "docker rmi myapp:${buildVersion} || true"
sh "docker rmi myapp:latest || true"
}
// 清理工作空间
cleanWs()
}
stage('Notification') {
// 发送通知
def status = currentBuild.result ?: 'SUCCESS'
def color = status == 'SUCCESS' ? 'good' : 'danger'
slackSend(
channel: '#ci-cd',
color: color,
message: "构建 ${status}: ${env.JOB_NAME} - ${env.BUILD_NUMBER} (<${env.BUILD_URL}|查看详情>)"
)
}
}
}
// 部署函数
def deployToProduction(dockerImage, version) {
input message: '确认部署到生产环境?', ok: '部署',
submitterParameter: 'DEPLOYER'
echo "部署版本 ${version} 到生产环境"
// 生产环境部署逻辑
}
def deployToDevelopment(dockerImage, version) {
echo "部署版本 ${version} 到开发环境"
// 开发环境部署逻辑
}
def deployToTest(dockerImage, version) {
echo "部署版本 ${version} 到测试环境"
// 测试环境部署逻辑
}
5.3 多配置项目
矩阵构建配置
基本矩阵配置:
配置矩阵:
轴1 - 操作系统:
- linux
- windows
- macos
轴2 - Java版本:
- jdk8
- jdk11
- jdk17
轴3 - 数据库:
- mysql
- postgresql
- h2
总构建数:3 × 3 × 3 = 27个构建
矩阵过滤:
// 排除不兼容的组合
!(os == "windows" && database == "postgresql")
// 只在Linux上测试JDK17
!(javaVersion == "jdk17" && os != "linux")
// 复杂过滤条件
(os == "linux" && javaVersion == "jdk11") ||
(os == "windows" && javaVersion == "jdk8") ||
(os == "macos" && database == "h2")
矩阵构建脚本:
#!/bin/bash
echo "=== 矩阵构建信息 ==="
echo "操作系统: ${os}"
echo "Java版本: ${javaVersion}"
echo "数据库: ${database}"
echo "构建组合: ${os}-${javaVersion}-${database}"
# 设置Java环境
case ${javaVersion} in
"jdk8")
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk
;;
"jdk11")
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
;;
"jdk17")
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
;;
esac
# 配置数据库连接
case ${database} in
"mysql")
export DB_URL="jdbc:mysql://localhost:3306/testdb"
export DB_DRIVER="com.mysql.cj.jdbc.Driver"
;;
"postgresql")
export DB_URL="jdbc:postgresql://localhost:5432/testdb"
export DB_DRIVER="org.postgresql.Driver"
;;
"h2")
export DB_URL="jdbc:h2:mem:testdb"
export DB_DRIVER="org.h2.Driver"
;;
esac
# 运行测试
echo "=== 开始测试 ==="
mvn clean test -Ddb.url="${DB_URL}" -Ddb.driver="${DB_DRIVER}"
# 生成报告
echo "=== 生成报告 ==="
mvn surefire-report:report
# 归档结果
echo "=== 归档结果 ==="
mkdir -p "reports/${os}-${javaVersion}-${database}"
cp -r target/site/surefire-report.html "reports/${os}-${javaVersion}-${database}/"
cp target/surefire-reports/*.xml "reports/${os}-${javaVersion}-${database}/"
并行执行优化
节点标签配置:
节点标签策略:
linux-node1: linux && jdk8 && mysql
linux-node2: linux && jdk11 && postgresql
windows-node1: windows && jdk8 && mysql
macos-node1: macos && jdk11 && h2
标签表达式:
${os} && ${javaVersion} && ${database}
构建优先级:
高优先级组合:
- linux + jdk11 + mysql (主要生产环境)
- linux + jdk8 + postgresql (遗留系统)
中优先级组合:
- windows + jdk11 + mysql
- linux + jdk17 + mysql
低优先级组合:
- 其他测试组合
5.4 文件夹项目
项目组织结构
按团队组织:
Jenkins项目结构:
├── Frontend Team/
│ ├── webapp-build
│ ├── mobile-app-build
│ └── component-library-build
├── Backend Team/
│ ├── user-service-build
│ ├── order-service-build
│ └── payment-service-build
├── DevOps Team/
│ ├── infrastructure-deploy
│ ├── monitoring-setup
│ └── backup-jobs
└── QA Team/
├── integration-tests
├── performance-tests
└── security-tests
按环境组织:
Jenkins项目结构:
├── Development/
│ ├── myapp-dev-build
│ ├── myapp-dev-deploy
│ └── myapp-dev-test
├── Testing/
│ ├── myapp-test-build
│ ├── myapp-test-deploy
│ └── myapp-test-integration
├── Staging/
│ ├── myapp-staging-build
│ ├── myapp-staging-deploy
│ └── myapp-staging-smoke-test
└── Production/
├── myapp-prod-deploy
├── myapp-prod-rollback
└── myapp-prod-monitoring
文件夹权限管理
权限配置示例:
Frontend Team文件夹权限:
- frontend-developers: Read, Build, Configure
- frontend-lead: All permissions
- qa-team: Read, Build
- devops-team: Read
Production文件夹权限:
- release-managers: All permissions
- senior-developers: Read, Build
- junior-developers: Read only
- auditors: Read only
权限继承配置:
// 文件夹权限脚本
folder('Frontend Team') {
description('前端团队项目')
authorization {
permission('hudson.model.Item.Read', 'frontend-developers')
permission('hudson.model.Item.Build', 'frontend-developers')
permission('hudson.model.Item.Configure', 'frontend-lead')
permission('hudson.model.Item.Delete', 'frontend-lead')
}
properties {
folderCredentialsProperty {
domainCredentials {
domainCredentials {
domain {
name('frontend-domain')
description('前端团队凭据域')
}
credentials {
usernamePassword {
scope('GLOBAL')
id('frontend-git-credentials')
username('frontend-bot')
password('${FRONTEND_BOT_PASSWORD}')
description('前端Git访问凭据')
}
}
}
}
}
}
}
5.5 任务模板和最佳实践
项目模板设计
通用构建模板:
// 通用Pipeline模板
@Library('jenkins-shared-library') _
pipeline {
agent {
label params.BUILD_NODE ?: 'linux'
}
parameters {
string(
name: 'GIT_REPO',
description: 'Git仓库URL'
)
string(
name: 'GIT_BRANCH',
defaultValue: 'main',
description: 'Git分支'
)
choice(
name: 'BUILD_TYPE',
choices: ['maven', 'gradle', 'npm', 'docker'],
description: '构建类型'
)
choice(
name: 'DEPLOY_ENV',
choices: ['none', 'dev', 'test', 'staging', 'prod'],
description: '部署环境'
)
booleanParam(
name: 'RUN_TESTS',
defaultValue: true,
description: '运行测试'
)
booleanParam(
name: 'RUN_SECURITY_SCAN',
defaultValue: false,
description: '运行安全扫描'
)
}
environment {
BUILD_VERSION = "${env.BUILD_NUMBER}-${env.GIT_COMMIT?.take(7) ?: 'unknown'}"
ARTIFACT_NAME = "${env.JOB_BASE_NAME}-${BUILD_VERSION}"
}
stages {
stage('Checkout') {
steps {
script {
checkout([
$class: 'GitSCM',
branches: [[name: params.GIT_BRANCH]],
userRemoteConfigs: [[url: params.GIT_REPO]]
])
}
}
}
stage('Build') {
steps {
script {
switch(params.BUILD_TYPE) {
case 'maven':
mavenBuild()
break
case 'gradle':
gradleBuild()
break
case 'npm':
npmBuild()
break
case 'docker':
dockerBuild()
break
default:
error "不支持的构建类型: ${params.BUILD_TYPE}"
}
}
}
}
stage('Test') {
when {
expression { params.RUN_TESTS }
}
steps {
script {
runTests(params.BUILD_TYPE)
}
}
post {
always {
publishTestResults testResultsPattern: 'target/surefire-reports/*.xml, build/test-results/**/*.xml, test-results.xml'
}
}
}
stage('Security Scan') {
when {
expression { params.RUN_SECURITY_SCAN }
}
steps {
script {
runSecurityScan(params.BUILD_TYPE)
}
}
}
stage('Package') {
steps {
script {
packageArtifacts(params.BUILD_TYPE)
}
}
}
stage('Deploy') {
when {
expression { params.DEPLOY_ENV != 'none' }
}
steps {
script {
deployToEnvironment(params.DEPLOY_ENV)
}
}
}
}
post {
always {
cleanWs()
}
success {
script {
sendNotification('success')
}
}
failure {
script {
sendNotification('failure')
}
}
}
}
共享库使用
共享库结构:
jenkins-shared-library/
├── vars/
│ ├── mavenBuild.groovy
│ ├── gradleBuild.groovy
│ ├── npmBuild.groovy
│ ├── dockerBuild.groovy
│ ├── runTests.groovy
│ ├── runSecurityScan.groovy
│ ├── packageArtifacts.groovy
│ ├── deployToEnvironment.groovy
│ └── sendNotification.groovy
├── src/
│ └── com/
│ └── company/
│ └── jenkins/
│ ├── BuildUtils.groovy
│ ├── DeployUtils.groovy
│ └── NotificationUtils.groovy
└── resources/
├── templates/
│ ├── Dockerfile.template
│ └── k8s-deployment.yaml
└── scripts/
├── security-scan.sh
└── deploy.sh
共享库函数示例:
// vars/mavenBuild.groovy
def call(Map config = [:]) {
def goals = config.goals ?: 'clean compile'
def profiles = config.profiles ?: ''
def javaVersion = config.javaVersion ?: '11'
echo "Maven构建: goals=${goals}, profiles=${profiles}, java=${javaVersion}"
withEnv(["JAVA_HOME=/usr/lib/jvm/java-${javaVersion}-openjdk"]) {
sh "mvn ${goals} ${profiles ? '-P' + profiles : ''}"
}
}
// vars/deployToEnvironment.groovy
def call(String environment) {
def config = readYaml file: "deploy-config/${environment}.yaml"
echo "部署到环境: ${environment}"
switch(environment) {
case 'dev':
deployToDev(config)
break
case 'test':
deployToTest(config)
break
case 'staging':
deployToStaging(config)
break
case 'prod':
deployToProduction(config)
break
default:
error "不支持的环境: ${environment}"
}
}
def deployToDev(config) {
sh """
kubectl config use-context ${config.cluster}
kubectl apply -f k8s/dev/
kubectl set image deployment/${config.appName} ${config.appName}=${config.image}:${env.BUILD_VERSION}
kubectl rollout status deployment/${config.appName}
"""
}
def deployToProduction(config) {
input message: "确认部署到生产环境?", ok: "部署",
submitterParameter: 'DEPLOYER'
// 蓝绿部署逻辑
sh """
kubectl config use-context ${config.cluster}
# 创建绿色环境
sed 's/{{VERSION}}/${env.BUILD_VERSION}/g' k8s/prod/deployment.yaml | kubectl apply -f -
# 等待就绪
kubectl rollout status deployment/${config.appName}-green
# 切换流量
kubectl patch service ${config.appName} -p '{"spec":{"selector":{"version":"green"}}}'
# 健康检查
sleep 30
# 清理蓝色环境
kubectl delete deployment ${config.appName}-blue || true
"""
}
构建优化策略
缓存策略:
// Maven依赖缓存
pipeline {
agent any
stages {
stage('Build') {
steps {
// 使用本地Maven仓库缓存
sh '''
# 创建缓存目录
mkdir -p ${WORKSPACE}/.m2/repository
# 使用缓存的Maven仓库
mvn clean compile -Dmaven.repo.local=${WORKSPACE}/.m2/repository
'''
}
}
}
post {
always {
// 缓存Maven依赖
stash includes: '.m2/repository/**', name: 'maven-cache'
}
}
}
// Docker层缓存
stage('Docker Build') {
steps {
script {
// 使用多阶段构建和缓存
def image = docker.build("myapp:${env.BUILD_NUMBER}",
"--cache-from myapp:latest --build-arg BUILDKIT_INLINE_CACHE=1 .")
}
}
}
并行构建优化:
stage('Parallel Tasks') {
parallel {
stage('Unit Tests') {
agent { label 'test-runner' }
steps {
sh 'mvn test'
}
}
stage('Integration Tests') {
agent { label 'integration-test' }
steps {
sh 'mvn verify -Dskip.unit.tests=true'
}
}
stage('Code Quality') {
agent { label 'sonar-scanner' }
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Security Scan') {
agent { label 'security-scanner' }
steps {
sh 'mvn org.owasp:dependency-check-maven:check'
}
}
}
}
5.6 本章小结
本章全面介绍了Jenkins构建任务管理的各个方面:
项目类型掌握: 1. 自由风格项目:传统构建任务的配置和管理 2. Pipeline项目:现代化的代码化构建流程 3. 多配置项目:矩阵构建和跨平台测试 4. 文件夹项目:项目组织和权限管理
核心技能: 1. 配置管理:源码管理、触发器、构建步骤 2. Pipeline开发:声明式和脚本式Pipeline 3. 并行优化:提高构建效率和资源利用 4. 模板设计:标准化和可重用的构建模板
最佳实践: - 选择合适的项目类型 - 使用Pipeline实现代码化 - 合理设计项目组织结构 - 优化构建性能和资源使用 - 建立标准化的构建模板
下一章预告: 下一章将介绍Jenkins插件系统,包括插件的安装、配置和开发。
5.7 练习与思考
实践练习
自由风格项目
- 创建一个Java项目的自由风格构建
- 配置Git源码管理和Maven构建
- 设置测试结果发布和邮件通知
Pipeline项目
- 将自由风格项目转换为Pipeline
- 实现并行测试和部署阶段
- 添加质量门禁和安全扫描
多配置项目
- 创建跨平台测试的矩阵构建
- 配置不同Java版本和数据库的组合
- 优化构建时间和资源使用
项目组织
- 设计团队项目的文件夹结构
- 配置权限和凭据管理
- 创建项目模板和共享库
思考题
- 在什么情况下选择自由风格项目而不是Pipeline?
- 如何设计一个既灵活又标准化的Pipeline模板?
- 多配置项目的矩阵构建如何平衡覆盖率和效率?
- 大型组织中如何有效管理数百个Jenkins项目?
- 如何实现构建任务的版本控制和变更管理?