基于Jenkins实现的CI/CD方案

基于Jenkins实现的CI/CD方案

前言

最近基于Jenkins的基座,搭建了一套适用于我们项目小组的持续集成环境。现在把流程整理分享出来,希望可以给大家提供一些帮助和思路。

使用到的组件和版本

组件名称组件版本作用
Harbor2.7.3镜像仓库
Jenkins2.319.2持续集成工具
Pipeline2.6Jenkins插件,编排流水线脚本
SSH Pipeline Steps2.0.0Jenkins插件,提供远程执行ssh能力
Git4.10.1Jenkins插件,提供拉取git代码仓库的能力
Httpd2.4.18HTTP服务器,用于归档编译后的软件包,镜像包
Maven3.6.3后端代码构建工具
Node8.17.0前端代码构建工具
Docker20.10.0容器版本
Docker Composev2.18.1容器编排

我这边是基于Jenkins的Pipeline+Docker的方式进行的任务编排,Jenkins是找的一个别人做好的,内置了绝大多数插件的容器版本,链接地址:https://hub.docker.com/r/h1kkan/jenkins-docker。这个做好的镜像里面没有SSH Pipeline Steps这个插件,需要自己额外下载一下,这边需要注意一下插件和Jenkins的对应版本。

基本流程图


这边有几个需要注意的地方,简单说明一下

  1. 首先需要配置代码仓库的webhook,这个网上有很多资料,可以自行参考配置一下

  2. dockerfile,docker-compose.yml这些文件需要内置在代码仓库中或者服务器内(我们是dockerfile文件内置在代码仓库,docker-compose.yml文件放在服务器里面固定目录)

  3. 在第五步,执行远端ssh时,需要去更改docker-compose.yml中的image节点,一开始准备用shell去做的,但是实现有点难度,然后就内置了一个python脚本,用yaml这个库去实现的,具体脚本updateImageLabel.py参考:

    import yaml
    import sysfilename = sys.argv[1]
    # 加载docker-compose.yml文件
    with open(filename,'r') as f:data = yaml.load(f)
    # 更新镜像标签
    data['services'][sys.argv[2]]['image'] = sys.argv[3]
    with open(filename, 'w') as yaml_file:yaml_file.write(yaml.dump(data, default_flow_style=False))
    

    使用时,传入三个参数,分别是docker-compose.yml文件路径,需要更新的服务,更新后的镜像标签

    python3 updateImageLabel.py ${dockerComposePath}  ${service}  ${image}
    
  4. Harbor的安装可以参考我之前的博客,安装完成如果是http的话,还需要配置一下insecure-registries仓库信息,并且执行docker login命令登录镜像仓库,用于拉取Harbor仓库镜像

    {"insecure-registries": ["harbor服务器地址"]
    }
    
  5. 第七步是可选的,做这个是为了方便每一个版本的归档,这边可以归档软件包或者save之后的镜像包

具体实现步骤

下面具体写一下实现的步骤,因为涉及的东西很多,有一些能找到的通用的步骤我就先不写了,大家可以自行去百度或者Google。

基础中间件部署

这边只讲Jenkins和Httpd的部署,Harbor部署可以参考我之前的文档。

Jenkins部署

通过docker的方式拉起Jenkins

docker run -u root -e TZ=Asia/Shanghai --name=jenkins -d -e TZ="Asia/Shanghai" -p 8080:8080 -p 50000:50000 -v /data/jenkins:/var/jenkins_home -v /run/docker.sock:/var/run/docker.sock -v /data/archive:/data/archive h1kkan/jenkins-docker:2.319.2

容器起来之后,需要进入到容器内部执行一下docker login的命令,在Jenkins容器内部也生成一套Harbor的凭证。

第三个挂载目录是用来开给Httpd服务器的,用于归档软件包和镜像包。

Httpd服务器部署

通过docker拉起Httpd服务器

docker run -p 8001:80 -v /data/archive:/usr/local/apache2/htdocs/ -d --name httpd httpd:2.4.18 

这边挂载目录就是Jenkins开出来的目录

Maven、Node、JDK等基础镜像

可以先从外网拉取对应版本,然后本地打成tar包之后上传到服务器解压,再tag之后推送到自己的Harbor仓库。

在Jenkins配置Git凭证

这个网上也很多,就不细致展开了,可以自己查一下

Pipeline流水线编排

后端流水线pipeline脚本
import java.text.SimpleDateFormat
import java.util.TimeZone// 构建版本
def createVersion() {def simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss")simpleDateFormat.timeZone = TimeZone.getTimeZone("Asia/Shanghai")return simpleDateFormat.format(new Date()) + "_${env.branch}"
}def getTime() {def simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss")simpleDateFormat.timeZone = TimeZone.getTimeZone("Asia/Shanghai")return simpleDateFormat.format(new Date())
}// 获取远端服务器信息 
def GetRemoteServer(ip, username, password) {def remote = [:]remote.name = ipremote.host = ipremote.user = usernameremote.password = passwordremote.allowAnyHosts = truereturn remote
}pipeline {agent noneenvironment {_version = createVersion()_time = getTime()}stages {stage('Git Checkout') {agent anysteps {checkout([$class: 'GitSCM', branches: [[name: "${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], gitTool: 'Default', submoduleCfg: [], userRemoteConfigs: [[url: '{{git_url}}',credentialsId: '{{credentialsId}}',]]])}}stage('Source Package') {agent {docker { image 'local-maven:3.6.3-openjdk-8' args '-v maven-repo:/usr/share/maven/ref'}}steps {sh 'mvn clean install -Dmaven.test.skip=true'}}stage('Build Image') {agent anysteps {sh 'docker build -f $WORKSPACE/CI/dockerfile --build-arg JARNAME=backend.jar -t 127.0.0.1:18080/library/backend:${_version} $WORKSPACE/backend/target/'sh 'docker push 127.0.0.1:18080/library/backend:${_version}'sh 'docker rmi 127.0.0.1:18080/library/backend:${_version}'}}stage('Publish To Env') {agent anysteps {script {def remote = [:]remote = GetRemoteServer('127.0.0.1', 'username', 'password')sshCommand remote: remote, command: "python3 updateImageLabel.py docker-compose.yml backend 127.0.0.1:18080/library/backend:${_version}"sshCommand remote: remote, command: "docker-compose -f docker-compose.yml up -d --build backend"}}}stage('Archive Package') {agent anysteps {sh 'mkdir -p /data/archive/backend/${branch}/${_time}'sh 'cp $WORKSPACE/backend/backend.jar /data/archive/backend/${branch}/${_time}'}}}
}

解释一下这个脚本

  • 首选镜像的版本是时间戳+分支的格式,类似20231026095511_dev,可以根据项目组的要求进行生成。

  • GetRemoteServer方法主要是提供获取远端服务器的信息,主要使用了SSH Pipeline Steps这个插件的能力,传入ip,username,password三个参数,这边密码是明文写死在脚本里面的,这个插件也支持密码加密保存,如果安全性要求比较高的可以换成加密的方式。

  • Git Checkout 这个stage主要是进行代码的下载,根据${branch}这个参数来指定代码仓库的版本,参数的具体配置可以看下Jenkins参数化构建的相关指导和文章。

  • Source Package就是代码仓库的打包,这边指定使用Docker镜像作为执行的Agent,只要指定镜像和编译命令就可以。这边我还挂载了一个maven-repo的volume,主要是为了缓存Jar包,不用每次都去下载。

  • Build Image步骤进行代码的构建,通过docker-build命令去生成镜像,这边的dockerfile文件是内置在我们代码库中的,参考如下:

    FROM 127.0.0.1:18080/library/java:8.0
    ARG JARNAME
    COPY ${JARNAME} /data/
    
  • Publish To Env 推送到环境,这边核心就是连接到远程服务器,通过修改镜像标签的脚本去更新docker-compose.yml文件中的镜像标签,然后重新构建容器

  • Archive Package 是否归档,演示的脚本里面只是归档了编译后的文件,还可以归档镜像等等。归档的路径为分支名/时间戳
    在这里插入图片描述

前端流水线pipeline脚本
import java.text.SimpleDateFormat
import java.util.TimeZone// 构建版本
def createVersion() {def simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss")simpleDateFormat.timeZone = TimeZone.getTimeZone("Asia/Shanghai")return simpleDateFormat.format(new Date()) + "_${env.branch}"
}def getTime() {def simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss")simpleDateFormat.timeZone = TimeZone.getTimeZone("Asia/Shanghai")return simpleDateFormat.format(new Date())
}// 获取远端服务器信息 
def GetRemoteServer(ip, username, password) {def remote = [:]remote.name = ipremote.host = ipremote.user = usernameremote.password = passwordremote.allowAnyHosts = truereturn remote
}pipeline {agent noneenvironment {_version = createVersion()_time = getTime()}stages {stage('Git Checkout') {agent anysteps {checkout([$class: 'GitSCM', branches: [[name: "${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], gitTool: 'Default', submoduleCfg: [], userRemoteConfigs: [[url: '{{git_url}}',credentialsId: '{{credentialsId}}',]]])}}stage('Source Package') {agent {docker { image 'node:8.17.0' }}steps {script {sh 'npm install --registry=http://registry.npm.taobao.org'}}}stage('Image Build') {agent anysteps {sh 'docker build -f $WORKSPACE/CI/dockerfile -t 127.0.0.1:18080/library/frontend:${_version} $WORKSPACE/target/'sh 'docker push 127.0.0.1:18080/library/frontend:${_version}'sh 'docker rmi 127.0.0.1:18080/library/frontend:${_version}'}}stage('Publish To Env') {agent anysteps {script {def remote = [:]remote = GetRemoteServer('127.0.0.1', 'username', 'password')// 更新docker-compose.yml文件,修改镜像sshCommand remote: remote, command: "python3 updateImageLabel.py docker-compose.yml frontend 127.0.0.1:18080/library/frontend:${_version}"sshCommand remote: remote, command: "docker-compose -f docker-compose.yml up -d --build frontend"}}}stage('Archive Package') {agent anysteps {sh 'mkdir -p /data/archive/frontend/${branch}/${environment}/${_time}'sh 'cd $WORKSPACE/target/dist/ && zip -r dist.zip *'sh 'cp $WORKSPACE/target/dist/dist.zip /data/archive/frontend/${branch}/${environment}/${_time}'}}}
}

前端和后端除了构建方式不一样,其他基本都相同。

结语

参考地址:

https://www.jenkins.io/doc/book/pipeline/

https://www.jenkins.io/doc/pipeline/steps/ssh-steps/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/693637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fastApi笔记03-请求体

请求体是客户端发送给API的数据,fastApi使用 Pydantic 模型来声明请求体 不能使用 GET操作(HTTP 方法)发送请求体。 要发送数据,必须使用下列方法之一:POST(较常见)、PUT、DELETE 或 PATCH 创…

zabbix5.0利用percona监控MySQL

具体来说包括: Percona Monitoring Plugins 这是一组用于收集MySQL实例各种性能指标和状态的插件脚本,包括: mysqld_stats.pl - 收集服务器状态计数器mysqld_statement_replay.pl - 进行负载模拟测试pt-status - 收集InnoDB资源使用情况等 Percona Templates 基于这些插件收集…

博途PLC PID仿真(单容水箱液位高度控制)

单容水箱和双荣水箱的微分方程和数值求解,可以参考下面文章链接: https://rxxw-control.blog.csdn.net/article/details/131139432https://rxxw-control.blog.csdn.net/article/details/131139432这篇博客我们利用欧拉求解器在PLC里完成单容水箱的数学建模。PLC也可以和MATL…

一次平平无奇的 Oracle 注入

在某次项目中,首先是发现注入点,数据库是Oracle,利用方式是时间盲注: 因为需要具体数据,所以要深入利用,手工肯定不方便,所以直接上 Sqlmap: Sqlmap也可以扫出该注入点,但想要进一步…

C++数组实战——考试成绩统计

成绩一成绩二成绩三同学一100100100同学二607999同学三1009587 代码&#xff1a; #include <iostream> #include<string> using namespace std;int main() { int score[3][3] {{100,100,100},{60,79,99},{100,95,87},}; #定义分数二维数组string names[3]{&qu…

软件实际应用,物流运输货运单打印,打印样式模板可以定制

软件实际应用&#xff0c;物流运输货运单打印&#xff0c;打印样式模板可以定制 一、前言 以下软件程序教程以 佳易王物流单打印查询系统V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、 物流单起始站可以设置直接选择&#xff0c;到达…

ARM 之十六 详解 CMSIS 版本变迁、各组件使用示例

目前,CMSIS 已经发展到了第六版,其目录结构也发生了重大的变化。在不断发展中,很多原来 CMSIS 的组件被不断独立出去,并因此成立了很多开源社区,今天就来学习一下! 由于 CMSIS 已经包含了相当丰富的文档,因此,本文重点学习版本之间的变化以及一些实际使用示例。 什么是…

2024云服务器ECS_云主机_服务器托管_e实例-阿里云

阿里云服务器ECS英文全程Elastic Compute Service&#xff0c;云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务&#xff0c;阿里云提供多种云服务器ECS实例规格&#xff0c;如ECS经济型e实例、通用算力型u1、ECS计算型c7、通用型g7、GPU实例等&#xff0c;阿里云服务器网al…

SpringBoot---集成MybatisPlus

介绍 使用SpringBoot集成MybatisPlus框架。 第一步&#xff1a;添加MybatisPlus依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.2</version> </depende…

雷卯有多种5V低压ESD防静电元器件供您选择

一、5V单路ESD产品推荐 二、5V多路产品推荐 三、多路特色ESD内部结构图展示 四、方案推荐 USB3.0/TYPE-C 静电滤波保护方案 方案优点&#xff1a;USB3.0提供5.0Gbps的传输速度&#xff0c;本方案采用多路集成器件防护, 可节约空间&#xff0c;可保证信号完整性&#xff0c;可…

将 mixamo 中的动画重定向到 UE 的小白人中

动画网站 https://www.mixamo.com/ 导入网格和动画 导入网格 为了方便可以在 Content 目录下面创建一个文件夹用于放 Mixamo 导入的项目。 进入 Mixamo 的官方。 按照图片中的步骤进行下载。 将下载好的文件拖入到 UE4 项目中创建好的文件夹 Character 中。导入时设置直接…

多端开发围炉夜话

文章目录 一、多端开发 一、多端开发 uni-app 官网 UNI-APP中的UI框架&#xff1a;介绍常用的UI框架及其特点 uView UIVant WeappColor UIMint UI

Redis之缓存雪崩问题解决方案

文章目录 一、书接上文二、介绍三、解决方案1. 锁2. 不同的过期时间3. 缓存预热和定时任务 一、书接上文 Redis之缓存穿透问题解决方案实践SpringBoot3Docker 二、介绍 缓存雪崩&#xff0c;指大量的缓存失效&#xff0c;大量的请求又同时落在数据库。主要的一种诱因是key设…

jenkins的nmp install命令无法下载包

问题&#xff1a;在jenkin的流水线脚本中执行到&#xff1a;npm install命令后无法下载前端依赖包 1、进到jenkins的工作目录&#xff0c;一般在底层为/var/lib/jenkins/workspace/任务名称 cd /var/lib/jenkins/workspace/xkc处理方式&#xff1a; # 查看镜像源 npm config …

电路设计(24)——循环彩灯控制器的proteus仿真

1.设计要求 实先循环彩灯&#xff0c;功能如下&#xff1a; 8个LED从上到下依次亮&#xff0c;然后从上到下依次灭。重复以上过程 4个LED从上到下依次亮&#xff0c;然后从上到下依次灭。重复以上过程 2.设计思路 将两片74194级联&#xff0c;就可以实现八位的移位寄存器&…

最优二叉搜索树 C#实现

最优二叉搜索树 C#实现 介绍一下 上一篇博文搞半天挺烧脑&#xff0c;没搞清楚继续… 主要是练习动态规划算法。最关键的一个是这个最优二叉搜索树能干啥。我认为如果数据稳定&#xff0c;统计出概率来&#xff0c;用最优二叉树保存&#xff0c;以后搜索应该是效率比较高的。…

openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优

文章目录 openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优224.1 全局并发队列224.2 局部并发队列 openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优 数据库提供两种手段进行并发队…

教师工龄工资每一年加多少上限多少年

每当提及教师的工资&#xff0c;人们总会关心工龄工资这一部分。毕竟&#xff0c;教师作为人类灵魂的工程师&#xff0c;他们的辛勤付出和岁月沉淀都应当得到应有的回报。那么&#xff0c;教师的工龄工资每一年会增加多少&#xff1f;又是否存在一个上限呢&#xff1f; 我们先…

第五篇【传奇开心果系列】Python文本和语音相互转换库技术点案例示例:详细解读pyttsx3的`preprocess_text`函数文本预处理。

传奇开心果短博文系列 系列短博文目录Python文本和语音相互转换库技术点案例示例系列 短博文目录前言一、pyttsx3的preprocess_text函数文本预处理基本用法示例代码二、实现更复杂的文本预处理逻辑示例代码三、去除停用词、词干提取示例代码四、词形还原、拼写纠正示例代码五、…

代码随想录算法训练营第57天 | 1143.最长公共子序列 1035.不相交的线 53.最大子序和

最长公共子序列 dp[i][j] 表示字符串1中 [0, i-1] 子串与字符串2中 [0, j-1] 子串之间的最长公共子序列长度。注意这里并不要求公共子序列一定以下标 i-1 或 j-1 结尾。因为这里的公共子序列不必须连续&#xff0c;这样定义可以使得递推方便一些。 当进行遍历递推时&#xff0c…