前言

CI/CD是持续化继承和持续化部署的简称。目的是在开发的过程中,尽可能的降低人工成本,来完成部署操作。通过Jenkins自动流水线工作可以省去很多时间,对于程序开发者而言,将部署jar包、修改环境、日志记录等一系列操作集成到Jenkins任务内,省时又省力,本次将以Jenkins为核心进行从0到1的搭建与使用,并提供了Java单体项目与微服务的通用shell脚本供于使用。

环境说明

本文通过两种方式进行演示,第一种是基于Docker完成Jenkins的安装与应用,Docker使用版本为25.0.3;第二种是直接在本机上安装Jenkins(本人主机为Mac,所以使用Mac来安装,Linux基本也是一样的)

基于Docker的Jenkins更多适合训练,因为所有的操作都在容器内、方便后续转移以及迁移。但缺点是Jenkins与宿主机的环境不互通,如在容器打完的jar包只能放在挂载的目录里。而且Java项目需要连接的中间件也非常多、且因为jar包是跑在Jenkins容器内的,所以配置容器间通信又是一个复杂点。(推荐初上手的同学使用,先用docker搭建一个完成的任务进行测试)

而直接部署在本机上更适合生产环境,更加的灵活方便,shell脚本的操作空间更大,并且可以直接访问各种中间件,省去了容器间通信的配置调试时间

安装Jenkins(Docker)

基于Docker安装Jenkins大致分为拉取镜像与脚本编辑

拉取镜像

这里拉取镜像的时候我推荐直接去官网指定版本下载,我一开始通过后缀跟latest下载最新版导致很多插件都下不下来。最后去官网指定了一个版本才行 Jenkins-Docker镜像官网

1
2
3
4
# 修改前
jenkins/jenkins:latest
# 修改后(因为我本地开发环境用的是17,所以直接下载了一个内置17的jenkins,当然也可以不指定,后通过jenkins内部下载对应的Java版本,不过还是更推荐前者,而且在内部下载Java也比较麻烦。本文以前者进行!!)
jenkins/jenkins:2.448-jdk17

编写安装脚本

1
vim startJenkins.sh

这里简单介绍一下每个参数,其中**-u**需要特别注意!

-d:后台运行

-p:将容器的8080端口映射到宿主机的8081端口上

-u:使用 UID 为 0 的用户身份运行 Jenkins 容器(这里如果不指定-u 后面如果想要通过jenkins操作SHELL脚本会导致没有权限,所以需要使用root的身份运行容器)

一般情况下0为管理员角色,也可以使用id 0来检测是否是root用户

image-20240311155842435

-v:挂载目录,将jenkins的工作目录挂在到宿主机内,这样使用jenkins操作目录时,我们本地也会有相同的反馈

–restart:在容器退出时自动重启容器

–name:配置容器名字

1
2
3
4
5
6
7
docker run -d \
-p 8081:8080 \
-u 0 \
-v /Users/sora33/docker/jenkins/data:/var/jenkins_home \
--restart=always \
--name jenkins \
jenkins/jenkins:2.448-jdk17

创建完成后,使用chmod -R赋值脚本权限并执行

1
2
3
4
# 赋值权限
chmod -R 755 startJenkins.sh
# 执行脚本
./startJenkins.sh

输入IP:8081进入Jenkins主页面,首次进入页面会要求我们输入密码

image-20240311162221114

密码会在容器内部打印出来

1
2
# docker logs 容器名
docker logs jenkins

将密码复制并进入下一级页面

image-20240311162328443

安装Jenkins(非Docker)

Mac平台:

使用homebrew安装Jenkins,如未安装homebrew请先安装homebrew!!!

1
2
3
4
# 安装jenkins
brew install jenkins
# 注意,mac端安装完成后最后去/opt/homebrew/Cellar/jenkins/2.448/bin目录下看一下jenkins的环境变量是否正确!这里注意替换版本号!该目录下有jenkins
sudo vim jenkins

如果JAVA_HOME不是如图完整的路径而是@@HOMEBREW……什么的请使用下面命令重新安装

1
brew reinstall jenkins

image-20240313095649414

之后去/opt/homebrew/Cellar/jenkins/2.448目录下修改局域网连接与端口号,默认只允许本机连接,改为0.0.0.0所有人可连接,下面端口号默认是8080,这里我改为了8081

image-20240313095949249

修改完成后,我们需要重启Jenkins

1
brew services restart jenkins

Linux平台:

Linux平台本人暂时未实践,不过只要成功安装Jenkins就没问题,区别在于文件的存放路径位置的不同,配置本质是一样的

1
2
3
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
sudo yum install jenkins

这里放出Linux下的Jenkins默认目录

/usr/lib/jenkins/:jenkins安装目录

/etc/sysconfig/jenkins:Jenkins配置文件目录

/var/lib/jenkins/:工作目录

/var/log/jenkins/jenkins.log:日志等

Jenkins配置

输入127.0.0.1:8081进入Jenkins主页面,按照提示去对应目录拿到密码,下面我们需要安装常用的插件

安装插件

进入到该页面后,我们选择安装推荐的插件

PS:这里每个人的网络环境都不同,所以有可能导致一些插件无法正确下载下来

可以尝试改为清华大学的下载站,具体方法是进入刚刚我们挂载的工作目录内,也就是刚刚启动脚本-v所指定的目录,找到 hudson.model.UpdateCenter.xml文件。将里面的url改为https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

非Docker端可以先不配置镜像,一会直接通过页面配置

image-20240311162849418

image-20240311162519763

创建用户

这个账号相当于管理员账户,创建完成后后面URL一般也不需要改动

image-20240311163706839

下面是配置Java与Maven,我们需要用到toolsplugins这两个模块

image-20240311163854811

配置Maven

首先点击plugins,继续点击Available plugins,输入maven,下载Maven Integration,安装完成后我们

image-20240311164026093

接着我们回到管理页面点击tools

Docker版配置

如果是Docker安装的话,我们直接在Jenkins容器内新装一个maven。翻到最底下找到Maven,新增Maven,输入Maven的名字和版本,选择版本最好跟本地一致,然后点击保存

image-20240311164542834

Linux与Mac配置

一般mac与linux本机都已经安装完成maven了,如果没有安装请自行安装;安装完成后配置一下别名和路径即可

image-20240313100833460

之后翻到最顶上,配置一下使用的maven配置文件,路径为setting.xml的地址,这样就可以使用本地的仓库

image-20240313100928792

配置Java

Docker版配置

在同一个页面找到JDK安装部分,因为我下载的jenkins内置jdk17,所以直接进入jenkins容器内查看Java所在的目录

进入容器可以使用:docker exec -it c7c(容器id前3位) bash

image-20240311165659880

配置别名,将路径输入,取消自动安装安装,点击保存

image-20240311165748076

Linux与Mac配置

在同一个页面找到JDK安装部分,与maven一样,我们本机大概率是已经安装好Java的,同样只需配置一下别名和路径

image-20240313101056470

页面上配置Jenkins下载源

除了通过该文件,我们也可以在插件管理中直接配置

1
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

image-20240313134732638

Jenkins使用

Maven项目自动化构建

  1. 在主页面点击新建任务,选择构建一个maven项目,输入任务名称image-20240312091326780

  2. 下面我们输入这个任务的描述、最好选择丢弃旧的构建,在下面选择对应的策略,这里我选择的是只保留最近的3次构建,方便发生意外后直接回滚

image-20240312091601261

  1. 下面我们来配置项目的Git地址,首先需要添加一个Git用户

    image-20240312091844841

以GitHub举例,像这样添加一个用户,用户名和密码就是你登陆GitHub的账号和密码

image-20240312092050180

继续输入我们的Git地址以及所需要构建的分支

image-20240312094410900

  1. 下面构建时的参数,这里的意思为执行clean package,清除再打包,跳过test阶段

    image-20240312095013918

  2. 最后需要配置构建完成后的操作,一般是通过执行shell脚本,将刚刚构建完成的项目跑起来并记录日志

image-20240312133619142

  1. 脚本完成后我们点击保存并进行手动构建,尝试执行一次

boot项目通用shell脚本

boot脚本需要配置如下5个地方,通过序号对应

1:LOG_DIR与LOG_FILE,前者为日志所需要存储的路径,后者为日志文件名

3:将buildSoraProject改为jenkins的任务名称,这里我的任务名称即为buildSoraProject

4:配置jar包的名字,如果不知道jar包的名字,可以通过进入容器内该路径查看,或者直接在pom文件的build标签内提前指定好

image-20240312134300799

6:配置buildId,只要唯一即可,一般为任务名称

7:目前只配置了字符集与时间,可以根据需求自己追加,例如常用的-Dspring.profiles.active=test

shell脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/bash

# 1.定义日志目录和日志文件的路径
LOG_DIR="$JENKINS_HOME/projectLog/buildSoraProject"
LOG_FILE="$LOG_DIR/sora_project_log.log"

# 2.确保日志目录存在,如果不存在则创建
mkdir -p $LOG_DIR

# 3.进入 Jenkins 的 workspace 目录下的 buildSoraProject/target 文件夹
cd $JENKINS_HOME/workspace/buildSoraProject/target

# 4.配置 jar包名称 sora33-0.0.1-SNAPSHOT.jar
JAR_FILE=sora33-project.jar

# 5.尝试停止已运行的 JAR 文件进程
PID=$(ps -ef | grep $JAR_FILE | awk '{print $2}')
if [ ! -z "$PID" ]; then
echo "Stopping existing Java process: $PID"
kill -9 $PID
fi

# 6.分配打包id
BUILD_ID=buildSoraProject

# 7.执行 jar 包 将日志输出到之前定义的日志文件中 如果时间异常再追加GMT+8,第一次可以先注释
nohup java -Dfile.encoding=UTF-8 \
-Duser.timezone=GMT+08 \
-jar $JAR_FILE > $LOG_FILE 2>&1 &

echo "Application is running, and logs are being written to $LOG_FILE"

cloud项目通用shell脚本

cloud脚本需要配置如下4个地方,通过序号对应

1:LOG_DIR_BASE 配置日志的路径,这里我放在Jenkins的工作目录下的projectLog文件夹里

2:打包id,这里请务必将打包id与任务名称对应上,因为Jenkins会把该任务的结果输出在任务名称下的文件夹里

3:服务列表定义,这里需要配置项目所有的启动类,如下图是我的项目结构,可以参考shell脚本的格式对应你自己的项目结构

image-20240313112208745

6:配置Java模块的启动命令,目前只配置了字符集与时间,可以根据需求自己追加,例如常用的-Dspring.profiles.active=test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/bin/bash

# 1.定义日志目录的基本路径
LOG_DIR_BASE="$JENKINS_HOME/projectLog"

# 2. 打包id
BUILD_ID=sora

# 3.服务列表定义
SERVICES=("sora-gateway" "sora-auth" "sora-modules/sora-user/user-server" "sora-modules/sora-system/system-server" "sora-modules/sora-system/spider-server")

# 4.停止所有服务
for SERVICE in ${SERVICES[@]}; do
JAR_FILE=$(find $JENKINS_HOME/workspace/$BUILD_ID/$SERVICE/target -name "*.jar" -print -quit) # 假设每个服务目录下只有一个jar包
if [[ ! -z "$JAR_FILE" ]]; then
PID=$(ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}')
if [[ ! -z "$PID" ]]; then
echo "Stopping $SERVICE (PID: $PID)"
kill -9 $PID
fi
fi
done

# 5.启动所有服务
for SERVICE in ${SERVICES[@]}; do
JAR_FILE=$(find $JENKINS_HOME/workspace/$BUILD_ID/$SERVICE/target -name "*.jar" -print -quit) # 假设每个服务目录下只有一个jar包
if [[ ! -z "$JAR_FILE" ]]; then
# 为每个服务创建一个专门的日志目录
LOG_DIR="$LOG_DIR_BASE/$(basename $SERVICE)"
mkdir -p $LOG_DIR
LOG_FILE="$LOG_DIR/$(basename $SERVICE)_log.log"

# 6.Java启动命令行配置
nohup java -Dfile.encoding=UTF-8 -Duser.timezone=GMT+08 \
-jar $JAR_FILE > $LOG_FILE 2>&1 &

echo "$SERVICE is running, logs are being written to $LOG_FILE"
else
echo "Jar file for $SERVICE not found."
fi
done

配置Aliyun的maven镜像源(Docker版)

PS:非Docker安装如果没有配置aliyun仓库地址,把下面的仓库地址加入到maven的conf目录下的settings的mirrors标签内即可。

因为Docker的maven还没配置aliyun仓库地址,并且是第一次使用maven,会在jenkins_home下生成一个tools文件夹,我们可以到挂载的data文件夹下查看,这里我们需要在maven内加入aliyun的仓库地址,具体路径为你挂载的路径/tools/hudson.tasks.Maven_MavenInstallation/Maven-3.9.1/conf

修改settings.xml文件夹,将aliyun的仓库地址配置到mirrors标签内

1
2
3
4
5
6
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>

结果测试

Docker

以boot项目举例,打包完成后我们可以在挂载目录中看到项目的日志输出,那我们要如何访问到项目呢?

image-20240313132900782

因为我们启动jenkins容器时只指定了Jenkins的端口并没有把Jenkins内部的项目端口暴露出来,所以我们需要删除Jenkins容器,再次创建,这次加上我们的项目端口,注意因为我们删除的只是容器,挂载的data文件夹并没有删除,所以Jenkins的数据缓存还会留在我们宿主机上,当我们再次安装Jenkins时,历史数据都还在,所以千万注意不要删除挂载的目录!!

1
2
# 删除容器
docker rm -rf 容器id/容器名

修改我们的安装脚本,这次多暴露一个项目的端口1234

1
2
3
4
5
6
7
8
docker run -d \
-p 8081:8080 \
-p 1234:1234 \
-u 0 \
-v /Users/sora33/docker/jenkins/data:/var/jenkins_home \
--restart=always \
--name jenkins \
jenkins/jenkins:2.448-jdk17
1
2
# 再次启动安装脚本
./startJenkins.sh

通过查看1234端口,可以发现是docker在占用

image-20240313132628391

调用接口也可以正常返回

image-20240313132645759

非Docker

如果我们直接在宿主机部署项目,那么我们直接访问接口就可以。

直接放个日志图,项目启动成功并且接口也成功访问到

image-20240313133515417

结束语

Jenkins的初步用法到这里就结束了,当然Jenkins也还有非常多的用法,大家也可以摸索一下,如果在搭建过程中遇到问题也欢迎留言,如果觉得有用可以分享给他人~