微服务CI/CD实践系列:
微服务CI/CD实践(一)环境准备及虚拟机创建
微服务CI/CD实践(二)服务器先决准备
微服务CI/CD实践(三)gitlab部署及nexus3部署
微服务CI/CD实践(四)Jenkins部署及环境配置
微服务CI/CD实践(五)Jenkins + Dokcer 部署微服务后端项目
微服务CI/CD实践(六)Jenkins + Dokcer 部署微服务前端VUE项目
微服务CI/CD实践(七)Minio服务器部署及应用
Jenkins是一个可持续集成、持续交互、持续部署的自动化工具。Jenkins拥有如下特点:
- 友好完善的操作界面,简单学习、简单配置,方便开发者快速上手使用
- 活跃的社区、开源且拥有众多的plugins
- 丰富的集成方式,可与gitlab-runner、k8s、argo、rancher以及公有云厂商等完美集成
- 自动化
- 支持市面主流操作系统以及多种安装方式,包括war包安装、yum安装、docker安装等
Jenkins成为众多中小型团队实施CI/CD可持续化项目交付流程的首选工具。下面开始jenkins的安装部署流程。
一、服务器环境配置
1.1 软件先决配置
使用war包安装,Jenkins不同版本对于JDK版本依赖均不相同,具体参考官网版本说明
- JDK,我们使用Jenkins 2.470版本安装,该版本最低支持JDK17。
- Maven,Java后端服务打包工具,Maven3.8.1
- node,vue项目打包工具,node 18
- docker,容器构建工具
- git,远程拉取代码工具
上述工具的安装参考微服务CI/CD实践(二)服务器先决准备
1.2 防火墙配置
需要开启Jenkins运行端口,以便浏览器可以远程访问jenkins控制台。
# 启动并启用firewalld
sudo systemctl start firewalld
sudo systemctl enable firewalld
# 关闭防火墙
sudo systemctl stop firewalld
# 放行TCP的80端口
sudo firewall-cmd --permanent --add-port=80/tcp
# 重新载入firewall规则以应用更改
sudo firewall-cmd --reload
# 查看防火墙状态
sudo firewall-cmd --state
二、Jenkins安装配置
2.1 安装Jenkins
step1 下载安装包
本地下载Jenkins 2.470.war并上传到服务器。
step2 部署
使用java命令行方式运行
nohup java -Djava.awt.headless=true -server -Xms1024m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -jar jenkins.war &
解释
在JDK17中永久代(PermGen space)已被元空间(Metaspace)所取代。因此,使用 -XX:PermSize 和 -XX:MaxPermSize 参数已不再适用。
nohup 后台方式运行命令并将日志输出到nohup.out
-Djava.awt.headless=true: 设置系统属性,告诉 JVM 运行在无头模式下。
-server: 使用 server 类型的 JVM,适用于长时间运行的应用程序。
-Xms1024m: 设置初始堆内存大小为 1024MB。
-Xmx2048m: 设置最大堆内存大小为 2048MB。
-XX:MetaspaceSize=256m: 设置元空间初始大小为 256MB。
-XX:MaxMetaspaceSize=512m: 设置元空间最大大小为 512MB。
# 验证运行结果
[root@k8s-rancher-master /]# netstat -lnp|grep 8080
tcp6 0 0 :::8080 :::* LISTEN 12448/java
注意事项:
- 确保你的系统有足够的内存来支持这些设置。
- 如果 Jenkins 启动后无法正常工作,检查日志文件以确定是否有内存相关的错误。
- 如果使用 Docker 容器启动 Jenkins,确保容器的内存限制足够大以容纳这些设置。
安装完成后访问控制台进行Jenkins初始化。
step1 浏览器访问[服务器ip]:8080,进入Jenkins初始配置界面:
根据页面提示,管理员密码设置在【/home/hka/.jenkins/secrets/initialAdminPassword】,使用cat命令查看:
[root@k8s-rancher-master /]# cat ./home/hka/.jenkins/secrets/initialAdminPassword
1154171ff706467596c01c8118df1819
step2.将密码粘贴到页面上,解锁Jenkins,并进入插件配置页面
点击【选择插件来安装】,进入插件选择页面(这里无需选择推荐插件,因为过多无用插件会对服务器本身带来压力,这里仅需要选择安装构建需要的插件)
2.2 配置Jenkins
2.2.1 升级站点源
左侧菜单树-》系统管理—》插件管理—》Advanced settings
http://updates.jenkins.io/update-center.json
或
http://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
2.2.3 插件管理
左侧菜单树-》系统管理—》插件管理—》可下载镜像(available plugins)
#需要下载的插件
Localization: Chinese (Simplified)
Publish Over SSH
Git client
Git Parameter
SSH plugin
Pipeline
NodeJS
SSH server
Workspace Cleanup Plugin
Jenkins List Git Branches
# jenkins Pipeline withMaven 构建依赖插件
Maven Integration Plugin
Pipeline Maven Integration Plugin
Maven Release Plugin
Maven Dependency Plugin
其他的插件在实际构建和部署环节可以根据构建需求进行添加。
2.2.3 用户管理
左侧菜单树-》系统管理—》用户管理
添加jenkins用户
2.2.4 全局系统配置
左侧菜单树-》系统管理—》全局系统配置
step1 maven项目配置
配置maven_opts为服务器安装地址
step2 全局环境变量配置
添加 JAVA_TOOL_OPTIONS -Dfile.encoding=UTF-8 配置,有效解决Jenkins在构建过程遇到的中文乱码问题。
step3 SSH remote hosts
jenkins需要远程连接的服务器配置
step4 SSH Servers
SSH Servers,sshPublisher流水任务需要的配置,包括上传文件的默认地址,流水线构建任务上传文件和执行shell命令必须
2.2.5 全局工具配置
左侧菜单树-》系统管理—》全局工具配置
Maven配置
配置maven,使用服务器本地maven,后续流水线构建会通过name引用当前maven
nodejs配置
配置nodejs,使用服务器本地nodejs,后续流水线构建vue项目会通过name引用当前nodejs
JDK配置
配置JDK,使用服务器本地JDK,后续流水线构建Java项目会通过name引用当前JDK
2.2.6 凭据配置
登录 Jenkins。
导航到 Manage Jenkins -> Manage Credentials -> System -> Global credentials.
2.2.6.1 配置gitlab凭据
配置gitlab用户名密码用于拉取代码:
- 创建一个新的凭证,选择 Username with password 类型。
- 输入私有仓库的用户名和密码。
- 保存凭证,并记下凭证的 ID。
2.2.6.2 配置ssh sit站点凭据
配置ssh sit站点用户名密码用于远程执行shell:
- 创建一个新的凭证,选择 Username with password 类型。
- 输入ssh sit站点的用户名和密码。
- 保存凭证,并记下凭证的 ID。
2.2.6.2 配置ssh server SSH 凭证凭据
配置ssh server SSH 凭证 用于远程执行shell和上传文件
step1 创建ssh server 站点的私钥文本
生成带有 Passphrase 的 SSH 密钥对:
- 使用 ssh-keygen 命令来生成新的 SSH 密钥对,并在提示时输入密码短语。
- 如果您已经有了一个没有密码短语的私钥,可以使用 ssh-keygen 重新设置密码短语。
使用 Passphrase: - 当您使用私钥文件时,需要输入密码短语。
- 您可以使用 ssh-agent 和 ssh-add 来暂时存储密码短语,以便在一段时间内无需重复输入。
# 生成带有 Passphrase 的 SSH 密钥对
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
# 查看私钥文本并复制私钥文本
cat ~/.ssh/id_rsa
step2 创建凭证
- 创建一个新的凭证,选择 SSH Username with private key 类型。
- 输入上一步复制的ssh server 站点的私钥文本。
- 保存凭证,并记下凭证的 ID。
2.3 Jenkins服务器运行分析及内存优化
2.3.1 查看服务器运行情况
top命令查看服务器运行时状况
free命令查看服务器内存分配
[root@k8s-rancher-master /]# free -m
total used free shared buff/cache available
Mem: 7820 2294 1905 8 3620 5218
Swap: 0 0
du命令查看指定文件目录下磁盘使用情况
[root@k8s-rancher-master /]# cd /root/.jenkins/workspace
[root@k8s-rancher-master workspace]# du -sh * | sort -hr
921M hka-web-01
731M hka-web
314M base-common-pipeline
293M projects-pipeline
286M task
254M uaa-center-pipeline
190M gateway-pipeline
177M base-common
151M gateway
96M projects-pipeline@2
df命令查看磁盘使用情况
[root@k8s-rancher-master workspace]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 9.0M 3.9G 1% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 28G 23G 55% /
/dev/sda1 1014M 154M 861M 16% /boot
/dev/mapper/centos-home 142G 147M 141G 1% /home
tmpfs 783M 0 783M 0% /run/user/1000
tmpfs 783M 0 783M 0% /run/user/0
slabtop
显示实时内核slab缓存信息,给出slab使用情况和汇总
# 按cache大小倒排
slabtop -s c
2.3.2 Jenkins优化
2.3.2.1 Jenkins内存优化
手工释放内存
当内存占用过高时,可以执行以下命令手工释放内存
# 用sync来确保文件系统的完整性
# sync 命令将所有未写的系统缓冲区写到磁盘中,包含已修改的 i-Node、已延迟的块 I/O 和读写映射文件
sync
# 清除pagecache
echo 1 > /proc/sys/vm/drop_caches
# 清除回收slab分配器中的对象(包括目录项缓存和inode缓存)
echo 2 > /proc/sys/vm/drop_caches
# 清除pagecache和slab分配器中的缓存对象
echo 3 > /proc/sys/vm/drop_caches
调整Jenkins JVM内存分配
step1 根据服务器配置合理调整Jenkins内存分配
在JDK17中永久代(PermGen space)已被元空间(Metaspace)所取代。因此,使用 -XX:PermSize 和 -XX:MaxPermSize 参数已不再适用。
nohup 后台方式运行命令并将日志输出到nohup.out
-Djava.awt.headless=true: 设置系统属性,告诉 JVM 运行在无头模式下。
-server: 使用 server 类型的 JVM,适用于长时间运行的应用程序。
-Xms1024m: 设置初始堆内存大小为 1024MB。
-Xmx2048m: 设置最大堆内存大小为 2048MB。
-XX:MetaspaceSize=256m: 设置元空间初始大小为 256MB。
-XX:MaxMetaspaceSize=512m: 设置元空间最大大小为 512MB。
step2 结束 Jenkins进程根据调整后的命令重新运行Jenkins
# 立即关闭Jenkins
java -jar jenkins-cli.jar -s http://192.168.1.105:8080/ shutdown
# 运行调整内存配置后的命令重新启动Jenkins
nohup java -Djava.awt.headless=true -server -Xms1024m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -jar jenkins.war &
2.3.2.2 Jenkins磁盘优化
Jenkins磁盘占用主要是项目构建的磁盘占用,可以通过如下方式达到磁盘空间释放:
step1 调整项目构建配置
设置构建记录的保留策略,减少历史构建记录占用的空间,在项目配置中勾选丢弃旧的构建选项
根据项目实际情况调整历史构建存储策略
step2 使用"Disk Usage" 插件
安装"Disk Usage" 插件,配置全局历史构建存储策略,设置该插件的步骤:
- 在 Jenkins 中安装 “Disk Usage” 插件。
- 在 Jenkins 配置中,找到 “Disk Usage” 相关的设置。
- 配置磁盘空间阈值,当空间不足时,系统将执行自动清理。
- 配置要保留的构建记录的数量。
- 配置要保留的每个工程的构建记录数量。
// 假设你已经安装了 Disk Usage 插件
diskUsage {
// 设置 Jenkins 实例的总磁盘配额
totalBuildDiskUsageLimit '10GB'
// 设置全局保留的构建数量
numberOfDaysToKeepBuilds '30'
// 设置每个工程保留的构建数量
numberOfBuildsToKeepPerJob '5'
// 如果启用,将保留最新和最旧的构建
useBuildsInDaysToKeep 'true'
// 如果磁盘空间不足,则在构建前进行检查
checkInSchedule '* * * * *'
// 如果启用,将在计划的时间清理构建记录
performScheduleCheck 'true'
}
step3 使用定时脚本清理磁盘空间
# 新增脚本Jenkins_disk_clenup.sh
#!/bin/bash
#jenkins 构建项目目录
DIR="/root/.jenkins/jobs"
#保留天数
OLDEST_DATE=$(date -d "$(date +%Y-%m-%d) -7 days" +%s)
#添加项目 "Product" 和 "Dev"
for DIRECTORY in $(find "$DIR" -maxdepth 1 -type d -name "task" -o -name "gateway-pipeline" | sort); do
if [ -d "$DIRECTORY/builds" ]; then
echo "Processing $DIRECTORY/builds directory..."
find "$DIRECTORY/builds" -maxdepth 1 -type d -name "[0-9]*" | while read LINE
do
MOD_DATE=$(stat -c %Y "$LINE")
if [[ $MOD_DATE -lt $OLDEST_DATE ]]; then
echo "Deleting old directory ${LINE}"
ls -ld ${LINE}
rm -rf "${LINE}"
fi
done
else
echo "Skipping $DIRECTORY/builds directory..."
fi
done
# 设置脚本可执行权限
sudo chmod +x Jenkins_disk_clenup.sh
# 设置定时任务
#crontab -e
0 23 * * * /root/.jenkins/jobs/Jenkins_disk_clenup.sh > /dev/null 2>&1 &
三、Server服务器配置
下图为基于Jenkins的持续交付的简单流程
要实现Jenkins自动化部署应用到Server服务器,Server服务器应该进行如下配置:
- 安装docker及网卡配置
- 防火墙配置
- ssh server配置
- 部署及备份目录准备
3.1 docker网卡配置
docker安装及加速源配置参考微服务CI/CD实践(二)服务器先决准备,这里主要说明下docker网络配置。
docker安装后会自动创建3种网络:bridge、host、none
docker network ls #使用以下命令查看
cd harbor/
docker-compose down ##停止容器
docker network ls ##docker的原生网络有三个
ip addr #docker安装后有一个docker0的桥接口
默认运行docker会使用Docker原生网络,此时通过宿主机的ip+应用的端口是无法正常访问应用。
3.1.1 使用桥接模式部署docker镜像
step1 创建网桥
#创建网桥指定网段,不能和本机现有网段冲突
docker network create --subnet 192.169.1.0/24 --gateway 192.169.1.1 my-network
# 查询网络
[root@k8s-rancher-node02 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
a51a3fdf5507 bridge bridge local
08184c970fdb host host local
6586a3619099 my-network bridge local
e93acf5c5cda none null local
# 查看网络详细配置
[root@k8s-rancher-node02 docker-sh]# docker network inspect my-network
[
{
"Name": "my-network",
"Id": "6586a36190999c86a70133e9521d3a86ec352abfe08bf5ddd4913b0600d23d15",
"Created": "2024-07-30T10:54:03.821607311+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.169.1.0/24",
"Gateway": "192.169.1.1"
}
]
},
// 省略...
step2 使用网桥模式运行docker
# 运行时指定网络
docker run -d --name demo1 --network my-network demo
# 查看桥接信息
[root@k8s-rancher-node02 docker-sh]# brctl show
bridge name bridge id STP enabled interfaces
br-6586a3619099 8000.0242892a3249 no veth1faec54
veth65db6be
veth825e30f
veth879b307
veth921c0ff
vethe34ab14
docker0 8000.02425f0e36f9 no veth6fa47df
# 查看容器网络
docker inspect demo
// 省略...
"Networks": {
"my-network": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "02:42:c0:a9:01:02",
"NetworkID": "6586a36190999c86a70133e9521d3a86ec352abfe08bf5ddd4913b0600d23d15",
"EndpointID": "1c3d34694592514bbd76b4639cd37551c8ab6cb5532725ca38f060ce79ee03bd",
"Gateway": "192.169.1.1",
"IPAddress": "192.169.1.2",
"IPPrefixLen": 24,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null,
"DNSNames": [
"gateway-server",
"196e455ccff9"
]
}
}
}
// 省略...
看到容器的网关为192.169.1.1
3.2 防火墙配置
需要开启ssh端口、应用的端口
# 启动并启用firewalld
sudo systemctl start firewalld
sudo systemctl enable firewalld
# 关闭防火墙
sudo systemctl stop firewalld
# 放行TCP的80端口
sudo firewall-cmd --permanent --add-port=22/tcp
sudo firewall-cmd --permanent --add-port=其他应用端口/tcp
# 重新载入firewall规则以应用更改
sudo firewall-cmd --reload
# 查看防火墙状态
sudo firewall-cmd --state
3.3 ssh server配置
centos操作系统默认是安装的 SSH client、SSH server,这里需要检查SSH client、SSH server是否可用
# 检查openssh包是否已安装
[root@k8s-rancher-node02 docker-sh]# rpm -qa | grep openssh
openssh-clients-7.4p1-21.el7.x86_64
openssh-7.4p1-21.el7.x86_64
openssh-server-7.4p1-21.el7.x86_64
# 如果已安装,检查SSH服务是否正在运行
[root@k8s-rancher-node02 docker-sh]# systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
Active: active (running) since 一 2024-08-19 17:59:50 CST; 1 weeks 2 days ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 1379 (sshd)
Tasks: 1
Memory: 6.4M
CGroup: /system.slice/sshd.service
└─1379 /usr/sbin/sshd -D
# 启动ssh
systemctl start sshd
# 设置在系统启动时自动运行
systemctl enable sshd
3.4 部署及备份目录准备
# 创建目录
mkdir -p /opt/tmp /opt/bak /usr/docker-sh /data/container/nginx/www /data/container/nginx/logs /data/container/app/logs /data/container/nginx/etc
# 赋予读写权限
chmod -R 777 /opt/tmp /opt/bak /usr/docker-sh /data/container/nginx/www /data/container/nginx/logs /data/container/app/logs /data/container/nginx/etc
解释:
- 新建 /opt/tmp 目录,用于Jenkins打包后,通过 Publish Over SSH插件将包传输到服务器的临时目录(如果前面创建过,这里无需再创建)。
- 新建 /opt/bak 目录,用于存储所有部署过的包备份,方便后续版本回滚。此目录可能会占用很大空间,所以需要选择一个磁盘空间大的挂载目录(如果前面创建过,这里无需再创建)。
- 新建 /usr/docker-sh目录,用于Jenkins将包传输完成之后,执行安装、备份操作的相关命令脚本(如果前面创建过,这里无需再创建)。
- 新建 /data/container/nginx/www,映射Nginx容器内的/var/www目录。
- 新建 /data/container/nginx/logs,映射Nginx容器内的/var/log/nginx目录,存放nginx运行日志。
- 新建 /data/container/app/logs,映射Nginx容器内的/logs目录,存放app运行日志。
- 新建 /data/container/nginx/etc,映射Nginx容器内的/etc/nginx目录
- 新建 /data/container/nginx/etc/nginx.conf,映射Nginx容器内的/etc/nginx/nginx.conf配置文件