本文主要讲解Jenkins在Linux环境下实现自动化部署项目(提供一种思路)
持续集成与持续部署(CI/CD)流程的实现,需要依赖一系列先进的工具和技术。这些工具不仅提高了开发效率,还确保了代码质量和发布的可靠性。以下是构建CI/CD流程所需的关键工具列表及其作用概述:
-
Jenkins - 作为自动化服务器,Jenkins是CI/CD流程的核心,支持各种插件,能够自动化几乎所有与软件开发相关的任务。
-
Docker - 容器化技术使得应用的打包和部署变得简单、高效。通过创建容器镜像,Docker为应用提供了一致的运行环境。
-
Node.js - 对于前端项目而言,Node.js是不可或缺的。它不仅可以作为运行环境,还可以通过诸如npm之类的包管理器,轻松管理前端项目的依赖和打包。
-
Maven - 这是一个项目管理和自动构建工具,特别适用于使用Java语言开发的项目。Maven能够处理项目的构建、依赖管理以及文档生成等任务。
-
GitLab - 作为一个版本控制系统,GitLab不仅提供代码存储功能,还内置了CI/CD的功能,使得代码管理和自动化流程建设可以在同一个平台上完成。
-
Docker Harbor - 这是一个企业级的容器镜像仓库,用于存储、签名、保护你的Docker镜像,并使之易于分发。
-
Nexus - 作为一款强大的软件制品管理器,Nexus可以帮助团队存储、整理和管理项目中使用的各种依赖库,支持包括Maven、npm等多种包管理器。
通过整合上述工具,可以构建一个高效、可靠的CI/CD流程,从而加快开发速度,提高软件质量,确保快速且安全的代码部署。
(CI/CD)流程图:
(CI/CD)流程概述
-
代码提交 - 开发团队首先将编写好的代码提交至GitLab,这是一个版本控制系统,同时提供代码审查、项目管理等多种功能。
-
自动化代码拉取 - Jenkins,作为自动化服务器,负责监听GitLab上的代码库。一旦检测到新的代码提交,它会自动将代码从GitLab拉取到Jenkins服务器上,准备进行构建。
-
项目构建 - 接下来,Jenkins使用Maven或nodejs,一个专门用于管理Java项目的构建或前端打包的工具,来编译代码并打包成一个可执行的JAR文件或前端项目。这一步骤包括运行测试、打包以及任何其他定义的构建步骤。
-
容器化部署 - 构建完成后,通过一个预先定义的Dockerfile,Jenkins能够创建一个包含应用及其依赖的Docker镜像。随后,这个Docker镜像会被推送到Docker Harbor,一个安全的注册服务器,用于存储和管理Docker镜像。
-
镜像部署 - 最后,Jenkins负责将这些Docker镜像从仓库中拉取到目标服务器,并在该服务器上启动对应的Docker容器。这确保了应用能够在不同的环境中以一致的方式运行,极大地简化了部署过程。
通过这一系列精细协调的步骤,CI/CD流程不仅加快了从代码提交到部署的整个过程,还确保了软件的质量、一致性和快速迭代能力。这样的流程为现代软件开发提供了坚实的基础设施,使得团队能够更加专注于产品的开发和优化。
Jenkins前端项目创建(nodejs构建)
在Jenkins中妥善管理项目对于实现高效的持续集成和持续部署(CI/CD)流程至关重要。为此,建议在启动新项目前,在Jenkins内创建一个新的视图(View),这有助于对前端和后端项目进行清晰的分类和组织。通过点击Jenkins界面上的“+”号,即可轻松创建新视图,这不仅有助于保持构建过程的透明性,也使得团队能够更加直观地监控和管理不同部分的开发进程。此举确保了项目的结构化管理,进而提升了整个开发周期的效率和效果。
输入视图名称:就叫mytest吧,点击list view按钮然后再点击OK ,下一个页面按保存按钮完成视图的创建
点击之前创建好的视图,页面左上角点击新建按钮创建需要项目
输入项目名并选择构建一个自由风格项目
点击ok进入到项目配置页面
点击丢弃旧构建,输入需要保存的构建记录(按公司需求)
点击参数化构建过程并选择参数
选择Choice Parameter参数,设置平台环境的选择
选择String Parameter参数,设置默认分支、端口、cpu和内存
注:CPU 1000为1核
源码管理中选择git 然后填写该服务的git地址和git账号
构建环境中选择该选项,意思是每次服务构建前把之前的删除
构建的相关命令(主要是shell命令):
以下是shell脚本内容,经供参考
# 切换到Jenkins工作目录,该目录为Jenkins拉取git代码到Jenkins服务器的位置 cd $WORKSPACE# 使用cnpm安装依赖 cnpm install# 运行构建命令 cnpm run build# 获取当前UTC-8时区的日期时间,并格式化为年月日时分的形式 current_date=`TZ='UTC-8' date +'%Y%m%d%H%M'`# 拼接版本号,格式为:dev-日期时间-Git提交的前8位 Version=dev-$current_date-${GIT_COMMIT:0:8}# 切换到/opt/$JOB_NAME目录,需要在Jenkins服务器上创建与此项目同名的目录 cd /opt/$JOB_NAME# 删除h5/$JOB_NAME目录下的所有文件 rm -rf h5/$JOB_NAME/*# 将Jenkins工作空间中的dist目录下(前端打包好的项目)的文件同步到h5/$JOB_NAME目录下,排除.tar.gz和.map文件 rsync -r $WORKSPACE/dist/* h5/$JOB_NAME/ --exclude="*.tar.gz" --exclude="*.map"# 使用Dockerfile构建镜像,命名为公司harbor仓库:端口/dev/$JOB_NAME:$Version docker build -t 公司harbor仓库:端口/dev/$JOB_NAME:$Version .# 将镜像推送到公司harbor仓库:端口/dev/$JOB_NAME:$Version docker push 公司harbor仓库:端口/dev/$JOB_NAME:$Version# 将上面定义好的镜像版本信息通过ssh的方式写入到目标服务器的ServiceVersion-$JOB_NAME文件中并执行update.sh脚本并传入JOB_NAME参数进行容器更新 ssh 目标服务器IP echo $JOB_NAME:$Version \> /root/docker-compose/ServiceVersion-$JOB_NAME \&\& /root/docker-compose/update.sh $JOB_NAME
将此脚本贴入到上图command框中即可
至此,通过Jenkins将前端服务编译打包并制作成docker镜像,传入到harbor仓库,由目标服务器下载docker镜像并启动容器完成发版的过程已经全部完成
备注:
1.$WORKSPACE 该环境变量为Jenkins内置环境变量,是Jenkins拉取git代码到Jenkins服务器的位置,可以在Jenkins中点击系统管理--系统设置中查看
2.$JOB_NAME 该变量为Jenkins内置变量,为此项目的项目名
3./opt/$JOB_NAME 需要在Jenkins服务器上创建与项目同名目录,该目录下有Dockerfile,nginx配置文件等,为前端项目制作成docker镜像做准备
/opt/$JOB_NAME目录内容如下图:
Dockerfile内容如下,仅供参考:
FROM 公司harbor仓库:端口/devops/nginx:0.9 COPY nginx.conf /etc/nginx/nginx.conf COPY testweb.conf /etc/nginx/conf.d/default.conf COPY h5 /data/ env TZ=Asia/Shanghai EXPOSE 8080 STOPSIGNAL SIGTERM CMD ["nginx", "-g", "daemon off;"]
nginx配置文件testweb.conf的内容如下,仅供参考:
map $http_upgrade $connection_upgrade {default upgrade;'' close;}
server {listen 8080;root "/data/";charset utf-8;server_name testweb-com;access_log /opt/nginx/testweb.log access;location / {root "/data/testweb";}error_page 500 502 503 504 /50x.html;location = /50x.html {#root html;}
}
4.docker-compose是一个用于定义和运行多容器Docker应用程序的工具,通过使用YAML文件来配置应用程序的服务、网络和卷,然后使用一个命令来创建并启动所有服务
需要在目标服务器安装docker环境,并下载docker-compse程序
curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
然后再创建一个名为docker-compose.yml
的文件,其中包含您的应用程序的配置信息。一旦配置完成,您可以使用docker-compose up
命令来启动所有服务。
以下是目标服务器docker-compose.yml文件内容,仅供参考:
version: '2.4'
services:testweb-com:container_name: testweb-commem_limit: 768Mimage: 公司harbor仓库:端口/dev/$JOB_NAME:$Versionrestart: alwaysvolumes:- /opt/nginx:/opt/nginxports:- 8080:8080networks:- testnet
networks:testnet:external: false
5.目标服务器update.sh发布脚本内容,仅供参考:
#!/bin/bash # 设置环境变量 PATH=/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin # 获取传入的服务名称参数 ServiceName=$1 # 输出提示信息 echo -e "\033[30;33m如果新增加服务,需要修改脚本的 ProjectList \033[0m" # 切换到docker-compose目录 cd /root/docker-compose # 获取当前脚本所在的目录路径 base_dir=$(dirname $0) # 检查是否存在 ServiceVersion-$ServiceName 文件,如果不存在则退出 if [ ! -f ServiceVersion-$ServiceName ];then echo ServiceVersion-$ServiceName file is not find;exit 1;fi # 从 ServiceVersion-$ServiceName 文件中获取服务的版本号 ProjectVersion=`grep -w "$ServiceName" $base_dir/ServiceVersion-$ServiceName|awk -F':' '{print $2}'` # 从 docker-compose.yml 文件中获取服务的旧版本号 OldVersion=`grep -w "$ServiceName" $base_dir/docker-compose.yml|grep "image:"|awk -F':' '{print $4}'` # 如果旧版本号为空,则提示用户输入一个版本号并退出 if [[ ! -n $OldVersion ]];then echo $ServiceName version is null, please write casual, like 1234 ;exit 1;fi # 如果新旧版本号不同,则更新 docker-compose.yml 文件中的服务镜像版本 if [[ -n $ProjectVersion && $ProjectVersion != $OldVersion ]];then# 获取需要更新的服务所在行号ChangeLine=`grep -wn "$ServiceName" $base_dir/docker-compose.yml|grep image:|awk -F':' '{print $1}'`# 使用sed命令替换指定行中的旧版本号为新版本号sed -i "${ChangeLine}s/$OldVersion/$ProjectVersion/" $base_dir/docker-compose.yml# 输出更新前后的版本号信息echo -e "\033[30;33m$ServiceName old_version:\033[0m" $OldVersion, "\033[30;32mnow_version:\033[0m" $ProjectVersion# 重新启动服务docker-compose up -d ${ServiceName}-com fi
同样点击之前创建好的视图,页面左上角点击新建按钮创建需要项目
选择构建一个maven项目,如果没有这个选项的同学是因为Jenkins没有安装Maven Integration的插件,请到系统管理--管理插件页面去安装,如下图:
同前端项目一样,设置好服务的分支,发版环境,cpu,内存和git地址后,进入构建前的操作,这里主要是设置Dockerfile参数等
shell命令如下,仅供参考:
# 使用sed命令将/opt/Dockerfile中的9999替换为变量$port的值,并将结果输出到$WORKSPACE/Dockerfile sed "s/9999/$port/" /opt/Dockerfile > $WORKSPACE/Dockerfile# 判断变量$memory是否不等于2048 if [ "$memory" != 2048 ];then# 如果$memory不等于2048,则使用sed命令将$WORKSPACE/Dockerfile中的2g替换为${memory}Msed -i "s/2g/${memory}M/g" $WORKSPACE/Dockerfile fi
将以上命令贴入上图command框中
设置build参数,就是设置mvn打包命令
Goals and options中输入clean package -e -U -Dmaven.test.skip=true
设置build后的操作
maven打包成功后就需要将jar包通过Dockerfile制作成docker镜像并上传到harbor中并发布到目标服务器
以下是shell脚本内容,仅供参考:
current_date=`TZ='UTC-8' date +'%Y%m%d%H%M'` Version=dev-$current_date-${GIT_COMMIT:0:8}cd $WORKSPACE sed -i '3s/target/$JOB_NAME-service\/target/' Dockerfile if [ ! -f $JOB_NAME-service/target/*.jar ];thenfind $JOB_NAME-service/target/ -name \*.jar|xargs -i mv {} $JOB_NAME-service/target/ fidocker build -t 公司harbor仓库:端口/dev/$JOB_NAME:$Version . docker push 公司harbor仓库:端口/dev/$JobName:$Versionssh 目标服务器IP echo $JOB_NAME:$Version \> /root/docker-compose/ServiceVersion-$JOB_NAME \&\& /root/docker-compose/update.sh $JOB_NAME
将上述脚本贴入到上图command框中
附上后端服务的Dockerfile文件内容,仅供参考:
FROM 公司harbor仓库:端口/devops/openjdk:8-alpine-0.2 WORKDIR / ADD ./target/*.jar app.jar EXPOSE 9999 CMD ["java","-server","-Duser.timezone=GMT+08","-jar","-Xmx2048m","-Xms2048m","/app.jar"]
最后附上目标服务器后端应用在docker-compose.yml文件中的定义(需要和之前前端应用写在同一个docker-compose文件中),内容仅供参考:
testapp-com:container_name: testapp-commem_limit: 768M #设置容器最大内存,并非jar包堆内存image: 公司harbor仓库:端口/dev/$JOB_NAME:$Versionrestart: alwaysvolumes:- /opt/log:/opt/log #主机映射目录:容器目录(具体容器内的目录需要和开发人员沟通)ports:- 9021:9021 #主机暴露端口:服务端口networks:- testnet
前后端服务完整docker-compose.yml内容:
version: '2.4'
services:
testweb-com:
container_name: testweb-com
mem_limit: 768M #设置容器最大内存,并非jar包堆内存
image: 公司harbor仓库:端口/dev/$JOB_NAME:$Version
restart: always
volumes:
- /opt/nginx:/opt/nginx #主机映射目录:容器目录(具体容器内的目录需要和开发人员沟通)
ports:
- 8080:8080 #主机暴露端口:服务端口
networks:
- testnet
testapp-com:
container_name: testapp-com
mem_limit: 768M #设置容器最大内存,并非jar包堆内存
image: 公司harbor仓库:端口/dev/$JOB_NAME:$Version
restart: always
volumes:
- /opt/log:/opt/log #主机映射目录:容器目录(具体容器内的目录需要和开发人员沟通)
ports:
- 9021:9021 #主机暴露端口:服务端口
networks:
- testnet
networks:
testnet:
external: false
至此,通过Jenkins将后端服务编译打包并制作成docker镜像,传入到harbor仓库,由目标服务器下载docker镜像并启动容器完成发版的过程已经全部完成
结语:本文介绍了Jenkins的自动发布功能,该过程仍需要人工在Jenkins界面上手动点击以启动发布。若希望实现在开发人员提交或合并代码时自动触发发布,需配置相应的触发机制。例如,在GitLab中可以设置Webhooks,而在Jenkins中则需要安装对应的插件。具体的配置需求会因公司而异。Jenkins支持多种发布方式,后续我将整理关于Pipeline发布方式的文档分享给大家。同时,我也会逐步分享将应用发布到Kubernetes集群的方法。感谢您的支持!!