Jenkins 持续集成与持续部署
Jenkins 简介
Jenkins 是一个开源的自动化服务器,用于持续集成(CI)和持续部署(CD)。它可以帮助开发团队自动化构建、测试和部署软件,提高开发效率和代码质量。
安装 Jenkins
使用 Docker 安装(推荐)
bash
# 拉取 Jenkins 镜像
docker pull jenkins/jenkins:lts
# 运行 Jenkins 容器
docker run -d -p 8080:8080 -p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
--name jenkins \
jenkins/jenkins:lts本地安装
Windows
- 下载 Jenkins Windows 安装包
- 运行安装程序
- 访问
http://localhost:8080
macOS
使用 Homebrew:
bash
brew install jenkins
brew services start jenkinsLinux (Ubuntu)
bash
# 添加 Jenkins 仓库
wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
# 安装 Jenkins
sudo apt update
sudo apt install openjdk-11-jdk
sudo apt install jenkins
# 启动 Jenkins
sudo systemctl start jenkins
sudo systemctl enable jenkins初始设置
- 打开浏览器访问
http://localhost:8080 - 获取初始密码:bash
# Docker 安装 docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword # 本地安装 sudo cat /var/lib/jenkins/secrets/initialAdminPassword - 安装推荐的插件
- 创建管理员账户
Jenkins 基本概念
任务 (Job)
Jenkins 中的任务定义了构建、测试和部署的流程。主要任务类型包括:
- Freestyle Project:自由风格项目,可以配置各种构建步骤
- Pipeline:流水线项目,使用代码定义构建流程
- Multi-configuration Project:多配置项目,可以在不同环境下构建
- GitHub Organization:GitHub 组织项目,自动管理仓库
构建触发器
构建触发器决定何时自动运行构建:
- Build periodically:定期构建
- Poll SCM:定期检查源代码变化
- GitHub hook trigger:GitHub 推送时触发
- Build after other projects are built:在其他项目构建后构建
构建环境
构建环境定义构建运行的条件:
- Delete workspace before build starts:构建前清理工作空间
- Use secret text(s) or file(s):使用密钥
- Add timestamps to the Console Output:添加时间戳
Jenkins Pipeline
Declarative Pipeline 基本结构
groovy
pipeline {
agent any
environment {
NODE_ENV = 'production'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install Dependencies') {
steps {
sh 'npm install'
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Deploy') {
steps {
sh 'npm run deploy'
}
}
}
post {
always {
echo 'Pipeline finished'
}
success {
echo 'Pipeline succeeded!'
}
failure {
echo 'Pipeline failed!'
}
}
}Scripted Pipeline 基本结构
groovy
node {
try {
stage('Checkout') {
checkout scm
}
stage('Install Dependencies') {
sh 'npm install'
}
stage('Build') {
sh 'npm run build'
}
stage('Test') {
sh 'npm test'
}
stage('Deploy') {
sh 'npm run deploy'
}
echo 'Pipeline succeeded!'
} catch (e) {
echo 'Pipeline failed!'
currentBuild.result = 'FAILED'
throw e
}
}常用插件
基础插件
- Git Plugin:Git 版本控制支持
- GitHub Integration:GitHub 集成
- Build Timeout:构建超时控制
- Workspace Cleanup:工作空间清理
构建与部署插件
- Node.js Plugin:Node.js 支持
- Docker Plugin:Docker 集成
- Deploy to container Plugin:容器部署
- Publish Over SSH:SSH 部署
通知插件
- Email Extension:邮件通知
- Slack Notification:Slack 通知
- ** DingTalk**:钉钉通知
实战案例
前端项目 CI/CD 流程
groovy
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: '*/main']],
userRemoteConfigs: [[url: 'https://github.com/username/your-project.git']]
])
}
}
stage('Setup Node.js') {
steps {
nodejs(nodeJSInstallationName: 'Node 16') {
sh 'node --version'
sh 'npm --version'
}
}
}
stage('Install Dependencies') {
steps {
sh 'npm ci'
}
}
stage('Lint') {
steps {
sh 'npm run lint'
}
}
stage('Test') {
steps {
sh 'npm test'
}
post {
always {
junit 'test-results.xml'
}
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sshPublisher(
publishers: [
sshPublisherDesc(
configName: 'production-server',
transfers: [
sshTransfer(
sourceFiles: 'dist/**',
removePrefix: 'dist',
remoteDirectory: '/var/www/html',
cleanRemote: false
)
]
)
]
)
}
}
}
post {
failure {
mail to: 'team@example.com',
subject: "Build Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "Check console output at ${env.BUILD_URL}"
}
}
}后端项目 CI/CD 流程
groovy
pipeline {
agent any
environment {
DOCKER_IMAGE = 'username/backend-app'
DOCKER_TAG = "${env.BUILD_NUMBER}"
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build Docker Image') {
steps {
script {
docker.build("${DOCKER_IMAGE}:${DOCKER_TAG}")
}
}
}
stage('Run Tests') {
steps {
sh 'docker run --rm ${DOCKER_IMAGE}:${DOCKER_TAG} npm test'
}
}
stage('Push to Registry') {
when {
branch 'main'
}
steps {
script {
docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') {
docker.image("${DOCKER_IMAGE}:${DOCKER_TAG}").push()
docker.image("${DOCKER_IMAGE}:${DOCKER_TAG}").push('latest')
}
}
}
}
stage('Deploy to Production') {
when {
branch 'main'
}
steps {
sh """
ssh production-server 'docker pull ${DOCKER_IMAGE}:${DOCKER_TAG}'
ssh production-server 'docker stop backend-app || true'
ssh production-server 'docker rm backend-app || true'
ssh production-server 'docker run -d --name backend-app -p 3000:3000 ${DOCKER_IMAGE}:${DOCKER_TAG}'
"""
}
}
}
}最佳实践
- 使用 Pipeline as Code:将 Jenkinsfile 存储在代码仓库中,版本控制构建流程
- 环境变量管理:使用 Jenkins 凭据管理敏感信息
- 并行执行:使用 parallel 关键字并行执行不相关的构建步骤
- 构建缓存:合理利用构建缓存减少构建时间
- 资源清理:确保构建完成后清理临时资源
- 监控与通知:设置适当的监控和通知机制
