Jenkins 构建流水线

在 Linux 系统上安装 Jenkins 服务,以及配置自动化构建项目

前置准备环境:docker、docker-compose、jdk、maven

一、环境搭建

1. Jenkins 安装

(1)拉取镜像

powershell 复制代码
# 安装镜像包,默认安装最新版本
docker pull jenkins/jenkins
# 查看是否安装成功
docker images

(2)启动并创建 Jenkins 容器

Jenkins工作空间目录:每新建一个项目都会在该目录下创建对应文件夹,拉取的代码等文件均在该路径下。

若是需要推送文件到目标服务器,默认从该项目文件夹下加载。例如:

  • 工作空间目录为:/var/jenkins_home/workspace
  • 项目名称为:demo

那么推送文件时所在路径为:/var/jenkins_home/workspace/demo,只需在脚本中维护后续路径即可

启动容器
powershell 复制代码
docker run -u root -d \
-p 8080:8080 -p 50000:50000 \
-v /var/jenkins_home/workspace/:/var/jenkins_home/workspace \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
-v /usr/local/java:/usr/local/java \
-v /usr/local/maven/apache-maven-3.9.9:/usr/local/maven \
-e JAVA_OPTS="-Dorg.apache.commons.jelly.tags.fmt.timeZone='Asia/Shanghai" \
--restart=unless-stopped \
--name jenkins-server jenkins/jenkins:2.426.2-lts
启动命令解释
powershell 复制代码
docker run -u root -d \
-p 80:8080 -p 81:50000 \                    				      # 镜像8080端口映射到宿主机80端口
-v /var/jenkins_home/workspace/:/var/jenkins_home/workspace \     # 挂载 jenkins 工作空间目录
-v /var/run/docker.sock:/var/run/docker.sock \                    # 挂载 docker
-v /usr/bin/docker:/usr/bin/docker \                              # 挂载 docker
-v /usr/local/java:/usr/local/java \                              # 挂载 jdk
-v /usr/local/maven/apache-maven-3.9.9:/usr/local/maven \         # 挂载 maven
-e JAVA_OPTS="-Dorg.apache.commons.jelly.tags.fmt.timeZone='Asia/Shanghai" \  # 同步时间
--restart=unless-stopped \                                                    # 重启策略
--name jenkins-server jenkins/jenkins:2.426.2-lts                              # jenkins-serve(自定义容器名称)  jenkins/jenkins:2.426.2-lts(镜像名称及版本)
安装并创建用户

浏览器打开 http://127.0.0.1:8080,输入超级管理密码进行登录

powershell 复制代码
# 进入容器,查看管理员密码
docker exec -it jenkins-server bash
cat /var/jenkins_home/secrets/initialAdminPassword
  1. 选择安装推荐的插件,安装完成后创建管理员用户

2. Harbor 镜像仓库安装

(1)下载在线安装包

powershell 复制代码
mkdir -p /root/software/harbor
cd /home/software/harbor
wget https://all-share-public.oss-cn-shanghai.aliyuncs.com/install-harbor/harbor-online-installer-v2.10.1.tgz
tar -zxvf harbor-online-installer-v2.10.1.tgz
cd harbor

(2)配置 harbor.yml 文件

powershell 复制代码
cp harbor.yml.tmpl harbor.yml

编辑 harbor.yml,并在对应位置写入以下内容

powershell 复制代码
hostname: 192.168.1.1 # 设置为指定部署机器IP
......
http:
port: 8081 # 从80修改为指定端口(可选)
https: # 注释掉 https 相关(无证书必须注释掉)
......
harbor_admin_password: Harbor12345 # admin用户指定密码 (可选)
......
data_volume: /root/software/harbor/data # 数据存储目录(可选)
......
log:
......
local:
......
location: /root/software/harbor/logs # 日志目录(可选)

(3)编译安装

powershell 复制代码
./prepare
./install.sh

浏览器打开 http://192.168.1.1:8081(admin/Harbor12345),新建镜像仓库

(4)修改 docker 配置

配置 docker 镜像源,添加 Harbor 镜像仓库地址,需重启 docker 生效

powershell 复制代码
vim /etc/docker/daemon.json
powershell 复制代码
{
......
"insecure-registries":["192.168.1.1:8081"]
.....
}

重启 docker

powershell 复制代码
systemctl daemon-reload
systemctl restart docker

(5)设置开机自启动

powershell 复制代码
vim /usr/lib/systemd/system/harbor.service
powershell 复制代码
[Unit]
Description=Harbor service with docker-compose
Requires=docker.service
After=docker.service
[Service]
Restart=always
#Type=oneshot
RemainAfterExit=yes
StandardError=null
StandardOutput=null
# Harbor实际安装路径
WorkingDirectory=/home/software/harbor/harbor
# Remove old containers
ExecStartPre=/usr/local/bin/docker-compose -f /home/software/harbor/harbor/dockercompose.yml down -v
# Compose up
ExecStart=/usr/local/bin/docker-compose -f /home/software/harbor/harbor/dockercompose.yml up -d
# Compose down, remove containers
ExecStop=/usr/local/bin/docker-compose -f /home/software/harbor/harbor/dockercompose.yml down -v
[Install]
WantedBy=multi-user.target

设置自启动

powershell 复制代码
systemctl daemon-reload
systemctl enable harbor

3. Sonarqube 代码检测工具安装

(1)下载在线安装包

powershell 复制代码
mkdir -p /home/software/sonarqube
cd /home/software/sonarqube
wget https://all-share-public.oss-cn-shanghai.aliyuncs.com/install-sonarqube/sonarqube.tar
tar -zxvf sonarqube.tar
cd sonarqube

若是需要修改端口、挂载文件路径,编辑当前目录下 docker-compose.yml 文件即可

powershell 复制代码
# 执行安装程序
./install.sh

(2)创建 Token 令牌

浏览器打开 http://192.168.1.1:8021,账号:admin/admin

创建 Token 令牌:生成的 Token 值要记录下来,配置 Jenkins 流水线时需要使用

二、Jenkins配置

1. 插件安装

需要安装以下插件:
Publish Over SSH :用于Jenkins 发送文件到远程服务器
Maven Integration :Maven 插件,打包项目
GitLab :Gitlab 插件,拉取代码
DingTalk:钉钉插件,用于推送项目构建状态等通知

系统管理 -> 插件管理,安装完成后重启 Jenkins



2. 配置 JDK 和 Maven

点击:系统管理 -> 全局工具配置


3. 配置 SSH 连接

点击:系统管理 -> 系统配置 -> 找到SSH

4. 配置全局凭据

点击:系统管理 -> 凭据管理 -> System/全局 -> Add Credentials

根据合适的认证方式创建凭据(示例为用户名&密码)



5. 配置钉钉通知

此配置为构建项目时钉钉推送通知,若是不需要可忽略

(1)生成钉钉 webhook 地址和密钥

打开钉钉 选择要推送的群 -> 群设置 -> 机器人 -> 添加机器人 -> 自定义 -> 添加 打开如下页面


(2)Jenkins中配置钉钉信息



三、Jenkins 构建项目

Jenkins中构建项目的类型有很多,实际上每种类型的构建都可以完成一样的构建过程与结果,只是在操作方式、灵活度等方面有所区别,在实际开发中可以根据自己的需求和习惯来选择。从灵活度上来说,流水线类型是最高的。常用的有以下三种:

  • 自由风格软件项目(FreeStyle Project)(推荐)
  • 流水线项目(Pipeline Project)(推荐)
  • Maven项目(Maven Project)

1. 新建任务(选择流水线)

2. 配置构建参数

用于在构建项目时动态维护的参数(例如 构建的代码分支、构建环境等)

3. 构建流水线(Pipeline)【重点】

Jenkins Pipeline Doc

tools :工具定义。可定义在脚本中使用的工具等;需在 系统管理 -> 全局配置管理 中维护,此处填写对应的 maven 和 jdk 名称即可
environment :变量定义。可将代码仓库地址,项目部署路径等信息在该模块下定义,方便维护
stages :Pipeline 各阶段定义。是必须出现的指令,包含一个或多个 stage,Pipeline 的大部分工作在此执行。可以在此处进行项目代码拉取、打包、推送仓库、部署等一系列操作
post:post 是在 Pipeline 或者 stages 执行结束后的操作,不是必须出现的指令。例如发送项目构建成功、失败等通知

以下为示例 Pipeline 脚本,可根据实际情况进行修改。

powershell 复制代码
pipeline {
    agent any

    tools {
        // 需在 系统管理 -> 全局配置管理 中维护,此处填写对应的 maven 和 jdk 名称即可
        maven "maven3.9.9"
        jdk "java17"
    }
    
    environment {
    	// 项目名称 
        projectName = "ruoyi-cloud-plus"
        
        // projectCodeParentPath = "./ruoyi-cloud-plus"    			 // 项目父模块代码路径
        // projectCodeSubPath = "./ruoyi-cloud-plus/admin-server"    // 项目子模块代码路径(如果没有子模块,则删除此变量,下面引用此变量的地方均修改为 $projectCodeParentPath) 
        
        // 项目部署服务器路径
        serverPath = "/home/project/ruoyi-cloud-plus" 
		// git仓库的url地址
        gitUrl = 'http://192.168.1.1/gitlab/demo/ruoyi-cloud-plus.git'
        // git仓库的认证凭据ID, 可前往 系统管理-> 凭据管理 查看
        gitCredentialsId = "git-demo"
		// sonarqube 的 url 地址
        sonarquebUrl = "http://192.168.1.1:8021"
        // sonarqube 的 token 令牌                             
        sonarquebToken = "sqa_05fxxxxxxxxxxxx227b1"
        
        // harbor 镜像仓库的用户名
        harborUser = "admin"
        // harbor镜像仓库的用户密码
        harborPasswrod="Harbor12345"
        // harbor仓库的url地址
        harborUrl = "192.168.1.1:8081"
        // harbor仓库项目名称
        harborRepo = "demo-library"
        // 钉钉机器人ID
        dingTalk = "Jenkins-DingTalk"
     }
    
    stages {
        stage('=========【拉取代码】=========') {
            steps{
                git branch: params.branchName, credentialsId: env.gitCredentialsId, url: env.gitUrl
            }
        }
        
        stage('=========【编译打包】=========') {
            steps {
                sh """mvn clean package -Dmaven.test.skip=true -P ${params.active}"""
            }
        }


        // stage('=========【sonarqueb代码质量检测】=========') {            
        //     steps {
        //         sh """                     
        //             /var/jenkins_home/sonar-scanner/bin/sonar-scanner \\
        //             -Dsonar.projectKey=${env.projectName}-${params.branchName} \\                
        //             -Dsonar.projectName=${env.projectName}-${params.branchName} \\          
        //             -Dsonar.sourceEncoding=UTF-8 \\
        //             -Dsonar.sources=${env.projectCodeParentPath} \\
        //             -Dsonar.java.binaries=${env.projectCodeSubPath}/target/ \\
        //             -Dsonar.host.url=${env.sonarquebUrl} \\
        //             -Dsonar.login=${env.sonarquebToken}
        //         """
        //     }
        // }
        
        stage('=========【构建镜像到Harbor仓库】=========') {
            steps {
                sh """
                    echo "-------- 1. 构建镜像 ------------"
                    docker build -t ruoyi-nacos:${params.imageTag} -f ruoyi-nacos/Dockerfile .
                    docker build -t ruoyi-auth:${params.imageTag} -f ruoyi-auth/Dockerfile .
                    docker build -t ruoyi-gateway:${params.imageTag} -f ruoyi-gateway/Dockerfile .
                    docker build -t ruoyi-system:${params.imageTag} -f ruoyi-modules/ruoyi-system/Dockerfile .
                    
                    echo "-------- 2. 镜像打标签 ------------"
                    docker login -u ${harborUser} -p ${harborPasswrod} ${harborUrl}
                    
                    docker tag ruoyi-nacos:${params.imageTag} ${harborUrl}/${harborRepo}/ruoyi-nacos:${params.imageTag}
                    docker tag ruoyi-auth:${params.imageTag} ${harborUrl}/${harborRepo}/ruoyi-auth:${params.imageTag}
                    docker tag ruoyi-gateway:${params.imageTag} ${harborUrl}/${harborRepo}/ruoyi-gateway:${params.imageTag}
                    docker tag ruoyi-system:${params.imageTag} ${harborUrl}/${harborRepo}/ruoyi-system:${params.imageTag}
                    
                    echo "-------- 3. 推送镜像至Harbor ------------"
                    docker push ${harborUrl}/${harborRepo}/ruoyi-nacos:${params.imageTag}
                    docker push ${harborUrl}/${harborRepo}/ruoyi-auth:${params.imageTag}
                    docker push ${harborUrl}/${harborRepo}/ruoyi-gateway:${params.imageTag}
                    docker push ${harborUrl}/${harborRepo}/ruoyi-system:${params.imageTag}
                    
                    echo "-------- 4. 删除未被任何容器使用的镜像 ------------"
                    // docker image prune -f
                """
            }
        }
        
        stage('=========【拉取镜像并运行】=========') {        
            steps {   
                sshPublisher(publishers: [sshPublisherDesc(configName: 'service-160', transfers: [sshTransfer(cleanRemote: false, excludes: '', 
                execCommand: """
                    #!/bin/bash
                    cd ${env.serverPath} 
                    ./deploy.sh ${env.harborUrl} ${env.harborUser} ${env.harborPasswrod} ${env.harborRepo} ${params.imageTag}
                """, 
                execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: """${env.servePath}""", remoteDirectorySDF: false, removePrefix: 'docker', sourceFiles: 'docker/docker-compose.yml')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
            }
        }
    }
    
	// 若是不需要配置钉钉推送,则不需要下面的配置   
    post {        
        success {  
            dingtalk (                
                robot: '${dingTalk}',                
                type:'MARKDOWN',
                title: "${projectName}项目构建成功",                
                text: [                  
                    "### ${projectName}项目构建成功",                 
                    "---",
                    "- 环境: ${params.active}", 
                    "- 分支: ${params.branchName}",              
                    "- 持续时间: ${currentBuild.durationString}",              
                    "- 执行人:${currentBuild.buildCauses.shortDescription}"             
                ]
            )   
        }
        failure {            
            dingtalk (                
                robot: '${dingTalk}',                
                type:'MARKDOWN',                
                title: "${projectName}项目构建失败",                
                text: [                  
                    "### ${projectName}项目构建失败",                 
                    "---",
                    "- 环境: ${params.active}", 
                    "- 分支: ${params.branchName}",              
                    "- 持续时间: ${currentBuild.durationString}",              
                    "- 执行人:${currentBuild.buildCauses.shortDescription}"             
                ]
            )   
        } 
        unstable {            
            dingtalk (                
                robot: '${dingTalk}',                
                type:'MARKDOWN',                
                title: "${projectName}项目构建异常",                
                text: [                  
                    "### ${projectName}项目构建异常",                 
                    "---",  
                    "- 环境: ${params.active}", 
                    "- 分支: ${params.branchName}",              
                    "- 持续时间: ${currentBuild.durationString}",              
                    "- 执行人:${currentBuild.buildCauses.shortDescription}"             
                ]
            )   
        } 
    }  
}

4. 部署项目服务器上预置脚本

该步骤可忽略,需同时修改流水线脚本中【拉取镜像并运行】stage 对该脚本的引用

在需要部署应用的服务器中,然后在 environment 中 serverPath 路径下编写 deploy.sh(记得赋予执行权限)

下面是提供的 deploy.sh 示例模版(需根据自身项目修改)

powershell 复制代码
#!/bin/bash
# 接收启动时的传参
harborUrl=$1
harborUser=$2
harborPasswrod=$3
harborRepo=$4
imageTag=$5

# 拼接完整镜像地址变量,在docker-compose文件中可引用
nacos_image=$(echo "nacos_image=\"$harborUrl/$harborRepo/ruoyi-nacos:$imageTag\"")
auth_image=$(echo "auth_image=\"$harborUrl/$harborRepo/ruoyi-auth:$imageTag\"")
gateway_image=$(echo "gateway_image=\"$harborUrl/$harborRepo/ruoyi-gateway:$imageTag\"")
system_image=$(echo "system_image=\"$harborUrl/$harborRepo/ruoyi-system:$imageTag\"")

# 新建 docker-compose 环境变量文件, 并写入镜像地址
envFile=".env"
rm -f "$envFile"

echo "$nacos_image" >> "$envFile"
echo "$auth_image" >> "$envFile"
echo "$gateway_image" >> "$envFile"
echo "$system_image" >> "$envFile"

# 登录 Harbor 仓库
docker login -u ${harborUser} -p ${harborPasswrod} ${harborUrl}

# 停止并删除服务
docker-compose down

# 启动 nginx
docker-compose up -d nginx-web

# 启动 nacos            
docker-compose up -d nacos

# 启动 ruoyi-gateway ruoyi-auth ruoyi-system
docker-compose up -d ruoyi-gateway ruoyi-auth ruoyi-system

# 删除未被任何容器使用的镜像
docker image prune -f

至此配置完成,进行构建验证

四、Jenkins Pipeline语法

1. stages

Pipeline 阶段定义,是必须出现的指令,每个 Pipeline 包含一个或多个 stage,Pipeline 的大部分工作在此执行。可以在此处进行 项目代码拉取、打包、推送仓库、部署等一系列操作。其中 steps 块中可以包含script 块。

powershell 复制代码
pipeline {
    agent any
    stages {
        stage('第一阶段') {
            steps {
                echo '第一阶段 拉取代码'
            }
        }
        stage('第二阶段') {
            steps {
                echo '第二阶段 项目打包'
            }
        }
    }
}

2. post

post是在Pipeline或者 stage执行结束后的操作,不是必须出现的指令,可设置以下触发条件:

  • always:无论 Pipeline 或者 stage 运行完成的状态如何都会运行
  • changed:只有当前 Pipeline 或者 stage 运行的状态与先前运行状态不同时才能运行
  • fixed:只有当前一次构建失败或者不稳定,而当前 Pipeline 或者 stage 运行成功时运行
  • regression:前一次运行成功,而当前 Pipeline 或者 stage 运行状态为 failure, unstable 或者 aborted 时运行
  • aborted:只有当前 Pipeline 或者 stage 处于 "aborted" 状态时才能运行,通常是手动终止。
  • failure:当前 Pipeline 或者 stage 处于 "failed" 状态时才运行
  • success:当前 Pipeline 或者 stage 具有 "success" 状态时才运行
  • unstable:当前 Pipeline 或者 stage 具有 "unstable" 状态才运行
  • unsuccessful:当前 Pipeline 或者 stage 不是 "success" 状态时运行
  • cleanup:不管 Pipeline 或 stage 的状态如何,在每一个 post 条件被执行之后运行。
powershell 复制代码
pipeline {
    agent any
    stages {
        stages {
        stage('第一阶段') {
            steps {
                echo '第一阶段 拉取代码'
            }
        }
    }
    post {
        success {
            echo '代码拉取成功!'
        }
        failure {
            echo '代码拉取失败!'
        }
        always {
            echo 'goodbye'
        }
    }
}

3. 流水线语法生成

在配置流水线页面,点击流水线语法可打开语法生成器页面

(1)在此处可选择需要生成语法的类型

  • 拉取代码 :git:Git
  • 推送文件到远程服务器:sshPublisher:Send build artifacts over SSH

(2)填写对应的参数信息,此处以文件推送示例

推送文件路径配置可结合文章开头Jenkins工作空间目录描述进行配置,其中docker/docker-compose.yml就位于/var/jenkins_home/workspace/demo路径下,此处只需配置docker/docker-compose.yml即可

填写完成后,点击下方的 "生成流水线脚本" 进行生成,最后复制生成的脚本到 steps 中即可


相关推荐
周之鸥1 小时前
从零部署 Astro 静态网站到云服务器(含 HTTPS 一键配置)
运维·服务器·ubuntu·http·https·astro
noravinsc1 小时前
centos如何做的时间同步
linux·运维·centos
木亦汐丫2 小时前
Docker 镜像版本Alpine、Slim、Bookworm、Bullseye、Stretch、Jessie
运维·docker·容器·debian·alpine·slim·bullseye
李元豪3 小时前
919服务器巡检
运维·服务器·servlet
迎風吹頭髮3 小时前
Linux内核架构浅谈25-Linux实时调度器:SCHED_RR与SCHED_FIFO策略实现
linux·运维·架构
李辰洋3 小时前
STP配置
运维·服务器·网络
siriuuus4 小时前
Nginx 负载均衡调度算法
运维·nginx·负载均衡
中草药z4 小时前
【Docker】零基础上手:原理+Ubuntu/Windows GUI 安装 + 镜像源 / 目录优化
运维·ubuntu·docker·容器·gui·安装·cgroups
jerryinwuhan5 小时前
LINUX复习资料(二)
linux·运维·服务器