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 中即可


相关推荐
soragui30 分钟前
【ChatGPT】OpenAI 如何使用流模式进行回答
linux·运维·游戏
Logintern091 小时前
Linux如何设置redis可以外网访问—执行使用指定配置文件启动redis
linux·运维·redis
娶不到胡一菲的汪大东1 小时前
Linux之ARM(MX6U)裸机篇----1.开发环境搭建
linux·运维·服务器
vvw&2 小时前
如何在 Ubuntu 22.04 上安装和使用 Composer
linux·运维·服务器·前端·ubuntu·php·composer
Hi202402172 小时前
ubuntu22.04上安装win10虚拟机,并采用noVNC+frp,让远程通过web访问桌面
运维·kvm·云桌面
几维安全2 小时前
如何通过运行时威胁洞察提升反欺诈策略
运维·网络·安全
soragui3 小时前
【Ubuntu】如何轻松设置80和443端口的防火墙
linux·运维·ubuntu
网络安全queen3 小时前
【D03】SNMP、NETBIOS和SSH
运维·网络·web安全·ssh
march of Time3 小时前
centos系统如何安装kubectl和部署kube-apiserver
linux·运维·centos
꧁༺朝花夕逝༻꧂3 小时前
nginx-代理服务
运维·服务器·nginx