jenkins、gitlab

发布时间 2023-07-10 15:45:13作者: areke

一、安装gitlab服务

Ubuntu20.04

1.1 安装依赖包

apt update
apt install -y iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server nfs-common \
lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev gcc openssh-server \
zlib1g-dev iotop unzip zip ipmitool

1.2 下载gitlab并安装

cd /opt
wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/focal/main/g/gitlab-ce/gitlab-ce_14.5.0-ce.0_amd64.deb
dpkg -i gitlab-ce_14.5.0-ce.0_amd64.deb

1.3 配置gitlab

[root@gitlab opt]#grep '^[a-zA-Z]' /etc/gitlab/gitlab.rb
external_url 'http://10.0.0.163'

1.4 初始化服务

# 执行配置重新设置并启动服务
gitlab-ctl reconfigure

gitlab相关目录

/etc/gitlab		# 配置文件目录
/run/gitlab		# pid目录
/opt/gitlab		# 安装目录
/var/opt/gitlab		# 数据目录
/var/log/gitlab		# 日志目录

1.5 gitlab常用命令

  1. gitlab-rails

用于启动控制台进行特殊操作,如修改管理员密码、打开数据库控制台(gitlab-rails dbconsole)等

  1. gitlab-psql

数据库命令行

示例:

[root@gitlab opt]#gitlab-psql
psql (12.7)
Type "help" for help.

gitlabhq_production=# 
gitlabhq_production=# \db
         List of tablespaces
    Name    |    Owner    | Location 
------------+-------------+----------
 pg_default | gitlab-psql | 
 pg_global  | gitlab-psql | 
(2 rows)

gitlabhq_production=# 
  1. gitlab-rake

数据备份恢复等数据操作

  1. gitlab-ctl

客户端命令行操作行

gitlab-ctl stop		#停止gitlab
gitlab-ctl start	#启动gitlab
gitlab-ctl restart	#重启gitlab
gitlab-ctl status	#查看组件运行状态
gitlab-ctl tail nginx	#查看某个组件的日志

1.6 验证gitlab启动完成

[root@gitlab ~]#gitlab-ctl status
run: alertmanager: (pid 16525) 156s; run: log: (pid 16280) 205s
run: gitaly: (pid 16539) 155s; run: log: (pid 15562) 303s
run: gitlab-exporter: (pid 16491) 158s; run: log: (pid 16191) 224s
run: gitlab-workhorse: (pid 16476) 159s; run: log: (pid 15976) 244s
run: grafana: (pid 16548) 155s; run: log: (pid 16429) 173s
run: logrotate: (pid 15478) 316s; run: log: (pid 15488) 315s
run: nginx: (pid 16015) 239s; run: log: (pid 16051) 236s
run: node-exporter: (pid 16485) 159s; run: log: (pid 16068) 232s
run: postgres-exporter: (pid 16533) 155s; run: log: (pid 16316) 200s
run: postgresql: (pid 15724) 298s; run: log: (pid 15736) 296s
run: prometheus: (pid 16504) 157s; run: log: (pid 16251) 212s
run: puma: (pid 15920) 257s; run: log: (pid 15927) 256s
run: redis: (pid 15518) 310s; run: log: (pid 15531) 309s
run: redis-exporter: (pid 16498) 158s; run: log: (pid 16218) 218s
run: sidekiq: (pid 15939) 251s; run: log: (pid 15957) 248s

1.7 验证端口及状态

默认监听tcp80端口

[root@gitlab ~]#lsof -i :80
COMMAND   PID       USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   16015       root    7u  IPv4 113086      0t0  TCP *:http (LISTEN)
nginx   16016 gitlab-www    7u  IPv4 113086      0t0  TCP *:http (LISTEN)
nginx   16017 gitlab-www    7u  IPv4 113086      0t0  TCP *:http (LISTEN)

1.8 登录gitlab web界面

默认用户名:root

密码在/etc/gitlab/initial_root_password​文件中

​​

image

1.9 设置中文

进入首页-->个人用户-->Perferences

image

Localization-->Language,选择简体中文

​​image​​

查看中文

image

1.10 gitlab使用说明

常用git命令

使用git命令下载代码和提交代码等操作

image

git config --global user.name "name" 		# 设置全局用户名
git config --global user.email xxx@xx.com 	# 设置全局邮箱
git config --global --list 			# 列出用户全局设置
git add index.html / .				# 添加指定文件、目录或当前目录下所有数据到暂存区
git commit -m "11"				# 提交文件到工作区
git status 					# 查看工作区的状态
git push 					# 提交代码到服务器
git pull 					# 获取代码到本地
git log 					# 查看操作日志
vim . gitignore 				# 定义忽略文件上传至gitlab
git reset --hard HEAD^^ 			# git版本回滚,HEAD为当前版本,加一个^为上一个版本,^^为上上一个版本
git reflog 					# 获取每次提交的 ID,可以使用--hard根据提交的ID进行版本回退
git reset --hard 5ae4b06 			# 回退到指定id的版本
git branch 					# 查看当前所处的分支
git checkout -b develop 			# 创建并切换到一个新分支
git checkout develop 				# 切换分支

工作流程

概念说明

  • 工作区

    clone的代码或者开发自己编写的代码文件所在的目录,通常是代码所在的一个服务的目录名称

  • 暂存区

    用于存储在工作区中对代码进行修改后的文件所保存的地方,使用git add​添加

  • 本地仓库

    用于提交存储在工作区和暂存区中改过的文件地方,使用git commit​提交

  • 远程仓库

    多个开发共同协作提交代码的仓库,即gitlab服务器,使用git push​推送

流程图如下

image

1.11 数据备份与恢复

1.11.1 数据备份

  1. 停止gitlab数据服务
gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq
  1. 备份数据
gitlab-rake gitlab:backup:create	# 在任意目录即可备份当前gitlab数据
  1. 启动数据服务
gitlab-ctl start
  1. 查看备份数据
/var/opt/gitlab/backups/		# 数据备份目录,需要使用命令备份
/var/opt/gitlab/nginx/conf		# nginx配置文件
/etc/gitlab/gitlab-secrets.json		# key文件
/etc/gitlab/gitlab.rb			# gitlab配置文件

备份数据

[root@gitlab data]#ll /var/opt/gitlab/backups/
total 336
drwx------  2 git  root     60 Mar 17 00:20 ./
drwxr-xr-x 21 root root   4096 Mar 17 00:08 ../
-rw-------  1 git  git  337920 Mar 17 00:20 1678994459_2023_03_17_14.5.0_gitlab_backup.tar

1.11.2 数据恢复

  1. 停止服务
#gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq
  1. 执行恢复
gitlab-rake gitlab:backup:restore BACKUP=1678994459_2023_03_17_14.5.0	# 备份文件名,无需加后缀名_gitlab_backup.tar

如果是恢复到新的机器上需要将 gitlab.rb 和 gitlab-secrets.json 手动复制到相应路径下

  1. 启动服务
gitlab-ctl start sidekiq
#gitlab-ctl start unicorn

1.12 常见代码部署方式

1.12.1 蓝绿发布

蓝绿发布指的是不停老版本代码(不影响上一个版本访问),而是在另外一套环境部署新版本然后进行测试,测试通过后将用户流量切到新版本,其特点为业务无中断,升级风险相对较小。

具体过程

  1. 当前版本业务正常访问(V1)
  2. 在另外一套环境部署新代码(V2),代码可能是增加了功能或修复了BUG
  3. 测试通过后将用户请求流量切到新版本环境
  4. 观察一段时间,如有异常直接切换旧版本
  5. 下次升级,将旧版本升级到新版本(V3)

image

蓝绿发布适用场景

  1. 不停止老版本,额外部署一套新版本,等新版本通过测试后,删除老版本
  2. 蓝绿发布时一种用于升级与更新的发布策略,部署的最小维度是容器,而发布最小维度时应用
  3. 蓝绿发布对场景升级有比较好的支持,但是对于涉及数据表结构变更等不可逆的升级,并不完全适用蓝绿发布来实现,需要结合一些业务的逻辑以及数据迁移与回滚的策略才可以完全满足需求

​​​​

1.12.2 金丝雀发布

金丝雀发布也叫灰度发布,是指在黑与白之间,能够平滑过渡的一种发布方式,灰度发布是增量发布的一种类型,灰度发布是在原版本可用的情况下,同时部署一个新版本应用作为“金丝雀/小白鼠”,测试新版本的性能和表现,以保障整体系统稳定的情况下,尽早发现、调整问题。

金丝雀/灰度发布步骤

  1. 准备好部署各个阶段的工件,包括:构建工件,测试脚本,配置文件和部署清单文件

  2. 从负载均衡列表中移除掉“金丝雀”服务器

  3. 升级“金丝雀”应用(排掉原有流量并进行部署)

  4. 对应用进行自动化测试

  5. 将“金丝雀”服务器重新添加到负载均衡列表中(连通性和健康检查)

  6. 如果“金丝雀”在线使用测试成功,升级剩余的其他服务器(否则就回滚)

灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度

KITJOLXFNYHRLLUKH6L3

金丝雀/灰度发布适用场景:

  1. 不停止老版本,额外搞一套新版本,不同版本应用共存。

  2. 灰度发布中,常常按照用户设置路由权重,例如90%的用户维持使用老版本,10%的用户尝鲜新版本。

  3. 经常与A/B测试一起使用,用于测试选择多种方案。

1.12.3 滚动发布

滚动发布一般是取出一个或者多个服务器停止服务,执行更新,并重新将其投入使用。周而复始,直到集群中所有的实例都更新成新版本。

1.12.4 A/B测试

A/B测试也是同时运行两个APP环境,但与蓝绿部署完全是两码事,A/B测试是用来测试应用功能表现的方法,例如可用性、受欢迎程度、可见性等,蓝绿部署目的是安全稳定地发布新版本应用,并在必要时回滚,即蓝绿部署是一套正式环境在线,而A/B测试是两套正式环境在线。

image

image

二、安装jenkins服务

https://www.jenkins.io/zh/

2.1 部署Jenkins

2.1.1 准备java环境,安装jdk

apt install openjdk-11-jdk -y

查看java版本

[root@jenkins ~]#java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu120.04.1)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu120.04.1, mixed mode, sharing)

2.1.2 安装Jenkins

https://mirrors.tuna.tsinghua.edu.cn/jenkins/debian-stable/

方式一:deb包方式

wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/debian-stable/jenkins_2.375.1_all.deb
dpkg -i jenkins_2.375.1_all.deb

查看配置

[root@jenkins ~]#grep "^[a-zA-Z]" /etc/default/jenkins 
NAME=jenkins
JAVA_ARGS="-Djava.awt.headless=true"
PIDFILE=/var/run/$NAME/$NAME.pid
JENKINS_USER=$NAME
JENKINS_GROUP=$NAME
JENKINS_WAR=/usr/share/java/$NAME.war
JENKINS_HOME=/var/lib/$NAME
RUN_STANDALONE=true
JENKINS_LOG=/var/log/$NAME/$NAME.log
JENKINS_ENABLE_ACCESS_LOG="no"
MAXOPENFILES=8192
HTTP_PORT=8080
PREFIX=/$NAME
JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT"

修改root启动服务

vim /lib/systemd/system/jenkins.service
...
[Service]
User=root  
Group=root

# 解决控制台输出中文为乱码问题
Environment="JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8"

systemctl daemon-reload
systemctl restart jenkins.service

启动参数

[root@jenkins ~]#cat /etc/default/jenkins |egrep -v "^#|^$"
NAME=jenkins
JAVA_ARGS="-Djava.awt.headless=true"
PIDFILE=/var/run/$NAME/$NAME.pid
JENKINS_USER=$NAME
JENKINS_GROUP=$NAME
JENKINS_WAR=/usr/share/java/$NAME.war
JENKINS_HOME=/var/lib/$NAME
RUN_STANDALONE=true
JENKINS_LOG=/var/log/$NAME/$NAME.log
JENKINS_ENABLE_ACCESS_LOG="no"
MAXOPENFILES=8192
HTTP_PORT=8080
PREFIX=/$NAME
JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT"

可选启动参数

JENKINS_JAVA_OPTIONS="--server -xms1g -Xmx1g -Xss512k -Xmn1g
-XX:CMSInitiatingOccupancyFraction=65
-XX:+UseFastAccessorMethods
-XX:+AggressiveOpts -XX:+UseBiasedLocking
-XX:+DisableExplicitGC -XX:MaxTenuringThreshold=10
-XX:NewSize=2048M -XX:MaxNewSize=2048M -XX:NewRatio=2
-XX:PermSize=128m -XX: MaxPermSize=512m -XX:CMSFullGCsBeforeCompaction=5
-XX:+ExplicitGCInvokesConcurrent -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled -Djava.awt.headless=true
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=12345
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname="10.0.0.164"

方式二:war包方式

wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/2.375.1/jenkins.war

jar包启动Jenkins

java -Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname="10.0.0.164" \
-jar jenkins.war &

2.1.3 访问Jenkins页面

image

2.1.4 安装Jenkins插件

image​​

配置国内插件地址,解决插件安装慢问题

  1. 修改/var/lib/jenkins/hudson.model.UpdateCenter.xml​配置文件国内地址
<?xml version='1.1' encoding='UTF-8'?>
<sites>
  <site>
    <id>default</id>
    <!---清华源地址-->
    <url>https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json</url>
  </site>
</sites>
  1. 重启服务
systemctl restart jenkins.service

插件下载地址:http://updates.jenkins-ci.org/download/plugins/

可将插件下载至本地/var/lib/jenkins/plugins/​目录,手动安装

说明:部分插件安装出错时可先忽略

​​image​​

2.1.5 创建用户

  1. 配置用户名信息

image

  1. 配置URL

image

  1. 配置完成

image

2.1.6 登录jenkins

image

进入首页

image

2.1.7 升级jenkins

# 下载war包
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war/2.395/jenkins.war

# 替换
\cp jenkins-2.395.war /usr/share/java/jenkins.war

# 重启服务
systemctl restart jenkins.service

验证版本

image

2.2 插件管理

2.2.1 插件安装目录

插件下载地址:http://updates.jenkins-ci.org/download/plugins/

[root@jenkins ~]#ll /var/lib/jenkins/plugins/
total 104616
drwxr-xr-x 86 jenkins jenkins     8192 Mar 18 18:10 ./
drwxr-xr-x 12 jenkins jenkins     4096 Mar 18 18:17 ../
drwxr-xr-x  4 jenkins jenkins       56 Mar 18 18:05 ant/
-rw-r--r--  1 jenkins jenkins    84600 Mar 18 18:05 ant.jpi
drwxr-xr-x  4 jenkins jenkins       56 Mar 18 18:03 antisamy-markup-formatter/
-rw-r--r--  1 jenkins jenkins   244168 Mar 18 18:03 antisamy-markup-formatter.jpi
drwxr-xr-x  4 jenkins jenkins       56 Mar 18 18:07 apache-httpcomponents-client-4-api/
-rw-r--r--  1 jenkins jenkins  1774698 Mar 18 18:07 apache-httpcomponents-client-4-api.jpi
drwxr-xr-x  6 jenkins jenkins       77 Mar 18 18:05 bootstrap5-api/
-rw-r--r--  1 jenkins jenkins   507001 Mar 18 18:05 bootstrap5-api.jpi

2.2.2 安装gitlab插件

  1. 查找gitlab、Blue Ocean插件并安装:

选择gitlab等插件

image

选择Blue Ocean

​​image​​​​

  1. 下载安装过程

image

  1. 进入Blue Ocean

image

创建流水线

image

2.3 配置jenkins权限

基于角色的权限管理,先创建角色和用户,给角色授权,然后把用户管理到角色。

2.3.1 安装Role-bases插件

基于角色的认证策略

image

2.3.2 创建新用户

Dashboard-->系统管理-->管理用户

image

​​​​

2.3.3 更改认证方式

Dashboard-->系统管理-->全局安全配置

更改授权策略为Role-Based Strategy

image

2.3.4 管理角色

  1. Dashboard-->系统管理-->Manage and Assign Roles

image

  1. Manage Roles

添加角色名称并点击add,对用户进行授权

  • 创建Global roles

image

  • 创建Item roles

image

2.3.5 将用户分配角色

Dashboard-->系统管理-->Manage and Assign Roles-->Assign Roles

image

给不同用户分配不同角色权限

image

2.3.6 普通用户登录测试

用户成功登录后,没有系统管理权限

image

三、配置jenkins和gitlab关联

3.1 gitlab配置ssh key

配置Jenkins ssh免认证拉取gitlab代码

3.1.1 Jenkins服务器生成ssh key

查看并复制Jenkins服务器公钥

[root@jenkins ~]#cat ~/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDNm5clKGRrp6H6TRF0eCwu+3VQqv4uqlzUwp7SwDHu7L2zTEEQt4
FMLjHNgq4H13snWuAcBRww3gwI1i1oUjK6HR/86GmmVd189DnyZB8UoRbCuq+OhJB6cK2TipJpr5nKc1lXuABWsjHP
R7MEFsDvxwi49MZW0SgePnHbUDPNTaFpabxQw2pASv3oCjLiEcMGcZd/ndV4gKzoZQMd2jmCrbmttaiLvss7Jfnain
Pw15XOE8fcgNMdKJJEXtHnzlfKATe2nlbBq2fcB2L2NvGKGwBAtNu86ysV6EPz2OdVaLoOuv2J+gRwyQxsKRrclYxx
AE3CY/tz+bvDzxOryeiT5m8gu0rwDRepsI9iLLkXVe6No/T5Bg9L9PHTpVrBvDRnCodnCYbVhmpY1opKK7cz6iN+B1
70Z+C5xW+J7ecBHisyuiE7Itfs13ikemqx2uKv+oMFKOVnY9dNh7IiekCTMXP5o2eRdZKXp5MmBiWe1UdCVp1s6uVc
SvlNK6Jj3xs= root@jenkins

注意:设置忽略远程访问告警

echo "StrictHostKeyChecking no" >> /etc/ssh/ssh_config

3.1.2 登录gitlab页面

image

3.1.3 粘贴Jenkins服务器公钥

image

3.1.4 测试ssh key

免密拉取gitlab代码

[root@jenkins opt]#git clone git@10.0.0.163:test-service/test-project.git
Cloning into 'test-project'...
time="2023-03-18T22:44:20+08:00" level=info msg="SSL_CERT_DIR is configured" ssl_cert_dir=/opt/gitlab/embedded/ssl/certs/
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 9 (delta 0), reused 9 (delta 0), pack-reused 0
Receiving objects: 100% (9/9), done.

3.2 Jenkins配置ssh key

Dashboard-->系统管理-->Manage Credentials-->全局-->Add Credentials

添加Jenkins server服务器私钥

image

2.2.1 查看凭据

​​image

3.3 验证Jenkins关联gitlab

3.3.1 Jenkins创建project

image

3.3.2 配置gitlab仓库

填写gitlab 仓库URL,使用ssh认证,根据实际选择分支

image

3.3.3 立即构建

image

3.3.4 Jenkins服务器验证数据

Jenkins自动下载gitlab仓库代码,存放目录为/var/lib/jenkins/workspace/

[root@jenkins opt]#tree /var/lib/jenkins/workspace/
/var/lib/jenkins/workspace/
└── test-project
    ├── README.md
    └── index.html

1 directories, 2 files

3.3.5 将代码部署至后端服务器

# backend server
tomcat1 10.0.0.165
tomcat2 10.0.0.166
  1. 编写shell

Build Steps

image

​​​

shell内容:

cd /var/lib/jenkins/workspace/test-project
tar czvf code.tar.gz ./*
scp code.tar.gz 10.0.0.165:/var/lib/tomcat9/webapps/
scp code.tar.gz 10.0.0.166:/var/lib/tomcat9/webapps/

ssh 10.0.0.165  "systemctl stop tomcat9.service && rm -rf /var/lib/tomcat9/webapps/myapp/* && cd /var/lib/tomcat9/webapps && tar xvf code.tar.gz -C /var/lib/tomcat9/webapps/myapp/"
ssh 10.0.0.166  "systemctl stop tomcat9.service && rm -rf /var/lib/tomcat9/webapps/myapp/* && cd /var/lib/tomcat9/webapps && tar xvf code.tar.gz -C /var/lib/tomcat9/webapps/myapp/"

ssh 10.0.0.165  "systemctl start tomcat9.service"
ssh 10.0.0.166  "systemctl start tomcat9.service"
  1. 执行构建

image

  1. 配置haproxy
...
listen tomcat_8080
        mode http
        bind 10.0.0.167:80
        server 10.0.0.165 10.0.0.165:8080 check inter 3s fall 3 rise 5
        server 10.0.0.166 10.0.0.166:8080 check inter 3s fall 3 rise 5

  1. 浏览器验证

​​image​​

更新index.html为3333,执行构建

image

后端网页同步更新

​​image

注意:若Jenkins控制台输出中文为乱码

在jenkins.service中添加Environment="JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8"​​,重启Jenkins服务

3.4 构建触发器(钩子)

构建触发器(webhook),是一个HTTP回调,其用于在向gitlab提交代码后能够触发Jenkins自动执行代码构建操作。

以下为新建一个develop分支,只有开发人员向develop分支提交代码时才会触发代码构建,而向主分支提交的代码不会自动构建,需要运维人员手动部署代码到生成环境。

image

3.4.1 gitlab新建develop分支

3.4.2 gitlab新建分支

image

3.4.3 Jenkins安装插件

下载安装插件Gitlab Webhook和Gitlab Authentication

image

注意事项:https://www.jenkins.io/security/advisories/

3.4.4 Jenkins修改登录认证方式

授权策略为登录用户可以做任何事

image

若Jenkins新版本没有配置CSRF(跨站请求伪造保护)禁用的选项,则需要在脚本命令行执行下面代码:

hudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true

image

3.4.5 Jenkins新建develop job

image

3.4.6 Jenkins构建shell命令

配置shell脚本

image

执行输出

image

3.4.7 Jenkins配置构建触发器

生成token认证

[root@jenkins ~]#openssl rand -hex 12
0e2db834fe246a8df61f030a

image​​

3.4.8 Jenkins验证分支job配置文件

[root@jenkins ~]#vim /var/lib/jenkins/jobs/develop/config.xml
...
  <authToken>0e2db834fe246a8df61f030a</authToken>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.tasks.Shell>
      <command>echo $USER &amp;&amp; pwd
cd /opt
pwd</command>

3.4.9 测试触发并验证远程触发构建

更新index.html文件

image

浏览器访问或curl命令访问测试

curl http://10.0.0.164:8080/job/develop/build?token=0e2db834fe246a8df61f030a

3.4.10 Jenkins验证job自动构建

image

index.html内容更新

[root@jenkins jenkins]#cat /var/lib/jenkins/workspace/develop/index.html 
<h1>11111111</h1>
<h1>22222222</h1>
<h1>33333333</h1>
<h1>44444444</h1>

3.4.11 gitlab配置系统钩子

gitlab配置URL

​​image​​

3.4.12 测试钩子可用性

image

测试结果

image

说明:若测试不成功,在脚本命令行执行下面代码:

hudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true

image

3.4.13 Jenkins执行shell命令

配置shell脚本内容

cd /var/lib/jenkins/workspace/develop
tar czvf code.tar.gz ./*
scp code.tar.gz 10.0.0.165:/var/lib/tomcat9/webapps/
scp code.tar.gz 10.0.0.166:/var/lib/tomcat9/webapps/

ssh 10.0.0.165  "systemctl stop tomcat9.service && rm -rf /var/lib/tomcat9/webapps/myapp/* && cd /var/lib/tomcat9/webapps && tar xvf code.tar.gz -C /var/lib/tomcat9/webapps/myapp/"
ssh 10.0.0.166  "systemctl stop tomcat9.service && rm -rf /var/lib/tomcat9/webapps/myapp/* && cd /var/lib/tomcat9/webapps && tar xvf code.tar.gz -C /var/lib/tomcat9/webapps/myapp/"

ssh 10.0.0.165  "systemctl start tomcat9.service"
ssh 10.0.0.166  "systemctl start tomcat9.service"

执行构建,查看结果

image

3.4.14 gitlab develop分支测试提交代码

# 克隆代码至本地
git clone -b develop http://10.0.0.163/test-service/test-project.git

# 修改代码
cd test-project/
echo "<h1>55555555</h1>" >> index.html

# 提交代码至暂存区
git add index.html

# 提交代码至本地仓库
[root@gitlab test-project]#git commit -m 'v5'
[develop 5d79393] v5
 1 file changed, 1 insertion(+)

# 上传代码至仓库,同时触发Jenkins自动构建
[root@gitlab test-project]#git push
Username for 'http://10.0.0.163': areke
Password for 'http://areke@10.0.0.163': 
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 301 bytes | 301.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: 
remote: To create a merge request for develop, visit:
remote:   http://10.0.0.163/test-service/test-project/-/merge_requests/new?merge_request%5Bsource_branch%5D=develop
remote: 
To http://10.0.0.163/test-service/test-project.git
   0fd95a9..5d79393  develop -> develop

3.4.15 Jenkins验证develop job自动构建

image

验证后端网页版本更新

image

3.5 构建后项目关联

用于多个job相互关联,需要串行执行多个job的场景,可以安装插件触发执行其他project

3.5.1 安装插件

Parameterized Trigger plugin

image

3.5.2 配置构建后操作

需先创建test-job1的Project

image

3.5.3 验证构建后操作

image

四、创建一个pipeline项目实现自动构建并部署

4.1 pipeline

官网:https://www.jenkins.io/2.0/

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

pipeline是帮助Jenkins实现CI到CD转变的重要角色,是运行在Jenkins 2.X 版本的核心插件,pipeline是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂发布流程,从而实现单个任务很难实现的复杂流程编排和任务可视化,Pipeline的实现方式是一套Groovy DSL,任何发布流程都可以表述为一段Groovy脚本。

4.1.1 pipeline语法

  • Stage

阶段,一个pipeline可以划分为若干个stage,每个stage都是一个操作步骤,如clone代码、代码编译、代码测试和代码部署,stage是一个逻辑分组,可以跨多个node执行。

  • Node

节点,每个node都是一个Jenkins节点,可以是Jenkins master,也可以是Jenkins agent,node是执行step的具体服务器。

  • Step

步骤,step是Jenkins pipeline最基本的操作单元,从在服务器创建目录到构建容器镜像,由各类Jenkins插件提供实现,一个stage中可以有多个step,如:sh、make

4.1.2 pipeline优势

  1. 可持续性

Jenkins的重启或者中断后不影响已经执行的pipeline job

  1. 支持暂停

pipeline可以选择停止并等待人工输入或批准后再继续执行

  1. 可扩展

通过groovy的编程更容易的扩展插件

  1. 并行执行

通过grovy脚本可以实现step、stage间的并行执行,和更复杂的相互依赖关系

4.1.3 pipeline示例

  1. 生成流水线脚本语法

image

  1. 流水线脚本
node {
    stage("colne代码"){
        echo "clone代码"
	git branch: 'develop', credentialsId: 'ff41be5b-c016-45da-938c-9b738cc1ce9d', url: 'git@10.0.0.163:test-service/test-project.git'
    }
    stage("代码构建"){
        echo "代码构建"
    }
    stage("代码测试"){
        echo "代码测试"
    }
    stage("代码部署"){
        echo "代码部署"
    }
}
  1. 流水线执行结果

image

查看日志

image

4.2 准备环境

4.2.1 项目示例

将代码部署到web服务器

image

主机清单

10.0.0.160	Gitlab
10.0.0.164	Jenkins
10.0.0.165	Jenkins-node1
10.0.0.166	Jenkins-node2
10.0.0.167	Maven
10.0.0.168	Sonarqube
10.0.0.175	Web1
10.0.0.176	Web2
10.0.0.177	Web3
10.0.0.189	LB1
10.0.0.190	LB2

4.2.2 gitlab服务器

10.0.0.160

参考第一章节部分:一、安装gitlab服务

4.2.3 Jenkins服务器

10.0.0.164

参考第二章节部分:二、安装jenkins服务

4.2.4 web服务器

10.0.0.175-177

  1. 安装tomcat
apt install -y tomcat9
  1. 测试
hostname -I > /var/lib/tomcat9/webapps/ROOT/index.html

访问网页

[root@lb1 ~]#curl 10.0.0.175:8080
10.0.0.175 

[root@lb1 ~]#curl 10.0.0.176:8080
10.0.0.176 

[root@lb1 ~]#curl 10.0.0.177:8080
10.0.0.177 

4.2.5 LoadBalance服务器

10.0.0.189-190

  1. 安装haproxy、keepalived、socat
apt install -y haproxy socat keepalived
  1. 配置
  • 启用内核参数
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

# 配置生效
sysctl -p
  • 配置keepalived
# 配置keepalived.conf
[root@lb1 ~]#cat /etc/keepalived/keepalived.conf 
! Configuration File for keepalived

global_defs {
   router_id 10.0.0.189		# 本机IP,LB2为10.0.0.190
   vrrp_skip_check_adv_addr
   vrrp_garp_interval 0
   vrrp_gna_interval 0
   vrrp_mcast_group4 224.0.0.18
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/chk_haproxy.sh"
    interval 1
    timeout 2
    weight -30
    fall 3
    rise 5
}

vrrp_instance haproxy {
    state MASTER		# LB2设置为BACKUP
    interface eth0
    virtual_router_id 51
    priority 100		# LB2可设置优先级80
    advert_int 1
    authentication {                                                                                                                                                                           
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.188/24 dev eth0 label eth0:1
    }
  
    track_script {
      chk_haproxy
    }
}

# 编写haproxy检测脚本
[root@lb1 ~]#cat /etc/keepalived/chk_haproxy.sh 
#!/bin/bash
/usr/bin/killall -0 haproxy

#添加执行权限
[root@lb1 ~]# chmod a+x /etc/keepalived/chk_haproxy.sh
  • 配置haproxy
[root@lb1 ~]#cat /etc/haproxy/haproxy.cfg
# 在global配置应该如下
#    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners

# 末尾增加如下配置
listen Web_80
    bind 10.0.0.188:80
    mode http
    log global
    server 10.0.0.175 10.0.0.175:8080 check inter 3s fall 3 rise 5
    server 10.0.0.176 10.0.0.176:8080 check inter 3s fall 3 rise 5
    server 10.0.0.177 10.0.0.177:8080 check inter 3s fall 3 rise 5

重启

systemctl restart keepalived.service haproxy.service
  1. 测试
[root@jenkins ~]#curl 10.0.0.188
10.0.0.175 
[root@jenkins ~]#curl 10.0.0.188
10.0.0.176 
[root@jenkins ~]#curl 10.0.0.188
10.0.0.177

# 将175服务器下线
[root@lb1 ~]#echo "set weight Web_80/10.0.0.175 0"|socat stdio /run/haproxy/admin.sock
# 测试访问后端服务器
[root@lb1 ~]#curl 10.0.0.188
10.0.0.176
[root@lb1 ~]#curl 10.0.0.188
10.0.0.177

4.2.6 Sonarqube服务器

部署sonarqube 10.0版本(10.0.0.168)

官网:https://www.sonarsource.com/products/sonarqube/

4.2.6.1 基础环境依赖

https://docs.sonarqube.org/10.0/requirements/prerequisites-and-overview/

  1. Java

image

  1. Database:

PostgreSQL

image.

Oracle

image

说明:7.9.x 版本以上不支持MySQL

  1. 系统及内核参数

image

# 使用普通账户启动sonarqube
useradd -s /bin/bash -m sonarqube

# 修改内核参数
echo "vm.max_map_count=524288" >> /etc/sysctl.conf
echo "fs.file-max=131072" >> /etc/sysctl.conf

# 执行生效
sysctl -p

# 修改limits.conf
echo "sonarqube - nofile 131072" >> /etc/security/limits.conf
echo "sonarqube - nproc 8192" >> /etc/security/limits.conf

# 重启服务器后,切换sonarqube用户查看
sonarqube@sonarqube:~$ ulimit -n
131072
sonarqube@sonarqube:~$ ulimit -u
8192

4.2.6.2 安装JDK17

apt-cache madison openjdk-17-jdk
apt install -y openjdk-17-jdk

#查看java版本
[root@sonarqube ~]#java -version
openjdk version "17.0.7" 2023-04-18
OpenJDK Runtime Environment (build 17.0.7+7-Ubuntu-0ubuntu120.04)
OpenJDK 64-Bit Server VM (build 17.0.7+7-Ubuntu-0ubuntu120.04, mixed mode, sharing)

4.2.6.3 部署PostgreSQL服务器

apt-cache madison postgresql-12
apt install -y postgresql-12

# 初始化并启动
[root@sonarqube ~]#su - postgres 
postgres@sonarqube:~$ /usr/lib/postgresql/12/bin/pg_ctl init -D /var/lib/postgresql/12/main
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory /var/lib/postgresql/12/main ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... Asia/Shanghai
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

initdb: warning: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    /usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main -l logfile start
# 启动服务
postgres@sonarqube:~$ /usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main -l logfile start

# 登录数据库
postgres@sonarqube:~$ psql
psql (12.15 (Ubuntu 12.15-0ubuntu0.20.04.1))
Type "help" for help.

#创建数据库并进行授权普通用户访问
##创建数据库
postgres=# create database sonar;
CREATE DATABASE
## 创建用户
postgres=# create user sonar with encrypted password '123456';
CREATE ROLE
## 授权
postgres=# grant all privileges on database sonar to sonar;
GRANT
## 执行变更
postgres=# alter database sonar owner to sonar;
ALTER DATABASE
## 退出
postgres=# \q
postgres@sonarqube:~$ 

# 修改监听地址
postgres@sonarqube:~$ vim /var/lib/postgresql/12/main/postgresql.conf 
...
listen_addresses = '*'

# 开启远程访问
postgres@sonarqube:~$ vim /var/lib/postgresql/12/main/pg_hba.conf
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
host    all             all             0.0.0.0/0               md5	# 新增一条配置

# 配置环境变量
postgres@sonarqube:~$ cd ~
postgres@sonarqube:~$ cat >> .profile <<EOF
PATH=\$PATH:/usr/lib/postgresql/12/bin
export PATH
EOF

postgres@sonarqube:~$ source .profile

# 重启服务
## 重启
postgres@sonarqube:~$ /usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main -l logfile restart
## 关闭
postgres@sonarqube:~$ /usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main -l logfile stop
## 启动
postgres@sonarqube:~$ /usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main -l logfile start

# 远程连接测试
[root@sonarqube ~]#psql -U sonar -h 10.0.0.168
Password for user sonar: 
psql (12.15 (Ubuntu 12.15-0ubuntu0.20.04.1))
Type "help" for help.

sonar=> 

设置开机自启动

[root@sonarqube ~]#cat /etc/rc.local 
#!/bin/bash
su - postgres -c "/usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main -l logfile start"
exit 0

4.2.6.4 部署sonarqube

下载地址: https://www.sonarsource.com/products/sonarqube/downloads/

# 下载
mkdir /apps
cd /apps
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-10.0.0.68432.zip
unzip sonarqube-10.0.0.68432.zip
ln -s sonarqube-10.0.0.68432 sonarqube
chown  -R sonarqube:sonarqube /apps/

# 配置postgresql数据库连接信息
su - sonarqube
echo "sonar.jdbc.username=sonar" >> /apps/sonarqube/conf/sonar.properties
echo "sonar.jdbc.password=123456" >> /apps/sonarqube/conf/sonar.properties
echo "sonar.jdbc.url=jdbc:postgresql://10.0.0.168/sonar" >> /apps/sonarqube/conf/sonar.properties

# 启动sonar
sonarqube@sonarqube:~$ /apps/sonarqube/bin/linux-x86-64/sonar.sh start
/usr/bin/java
Starting SonarQube...
Started SonarQube.

# 查看日志
sonarqube@sonarqube:/apps/sonarqube$ tail -f /apps/sonarqube/logs/nohup.log 
2023.07.02 11:24:45 INFO  app[][o.s.a.ProcessLauncherImpl] Launch process[COMPUTE_ENGINE] from [/apps/sonarqube-10.0.0.68432]: /usr/lib/jvm/java-17-openjdk-amd64/bin/java -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/apps/sonarqube-10.0.0.68432/temp -XX:-OmitStackTraceInFastThrow --add-opens=java.base/java.util=ALL-UNNAMED --add-exports=java.base/jdk.internal.ref=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.management/sun.management=ALL-UNNAMED --add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED -Dcom.redhat.fips=false -Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError -Dhttp.nonProxyHosts=localhost|127.*|[::1] -cp ./lib/sonar-application-10.0.0.68432.jar:/apps/sonarqube-10.0.0.68432/lib/jdbc/postgresql/postgresql-42.5.1.jar org.sonar.ce.app.CeServer /apps/sonarqube-10.0.0.68432/temp/sq-process3897498440763538588properties
2023.07.02 11:24:45 WARN  app[][startup] ####################################################################################################################
2023.07.02 11:24:45 WARN  app[][startup] Default Administrator credentials are still being used. Make sure to change the password or deactivate the account.
2023.07.02 11:24:45 WARN  app[][startup] ####################################################################################################################
WARNING: A terminally deprecated method in java.lang.System has been called
WARNING: System::setSecurityManager has been called by org.sonar.process.PluginSecurityManager (file:/apps/sonarqube-10.0.0.68432/lib/sonar-application-10.0.0.68432.jar)
WARNING: Please consider reporting this to the maintainers of org.sonar.process.PluginSecurityManager
WARNING: System::setSecurityManager will be removed in a future release
2023.07.02 11:24:49 INFO  app[][o.s.a.SchedulerImpl] Process[ce] is up
2023.07.02 11:24:49 INFO  app[][o.s.a.SchedulerImpl] SonarQube is operational

验证sonarqube

image

设置开机自启

[root@sonarqube ~]#vim /etc/rc.local 
#!/bin/bash
su - postgres -c "/usr/lib/postgresql/12/bin/pg_ctl -D /var/lib/postgresql/12/main -l logfile start"
su - sonarqube -c "/apps/sonarqube/bin/linux-x86-64/sonar.sh start"
exit 0

4.2.6.5 访问Sonarqube Web页面

http://10.0.0.168:9000,用户名、密码都是admin

进入首页

image

安装中文插件

image​​

查看中文

image

4.2.7 部署sonar-scanner扫描器

官方文档:https://docs.sonarqube.org/latest/analyzing-source-code/scanners/sonarscanner/

下载地址:https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/

4.2.7.1 Jenkins服务器部署sonar-scanner

cd /usr/local/src
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.0.2856-linux.zip
unzip sonar-scanner-cli-4.8.0.2856-linux.zip
ln -s sonar-scanner-4.8.0.2856-linux /usr/local/src/sonar-scanner
ln -s /usr/local/src/sonar-scanner/bin/sonar-scanner* /usr/local/bin/

# 添加sonarqube服务器信息
[root@jenkins src]#vim /usr/local/src/sonar-scanner/conf/sonar-scanner.properties 
#----- Default SonarQube server
sonar.host.url=http://10.0.0.168:9000

#----- Default source code encoding
sonar.sourceEncoding=UTF-8

4.2.7.2 准备测试项目

  1. 关闭强制认证

image

  1. 准备测试项目
cd /opt
unzip sonar-examples-master.zip
cd /opt/sonar-examples-master/projects/languages/php/php-sonar-runner

# 编辑配置项目信息
[root@jenkins php-sonar-runner]#cat sonar-project.properties 
# Required metadata
sonar.projectKey=org.sonarqube:php-simple-sq-scanner	# 自定义key
sonar.projectName=PHP::SimpleProject::SonarQubeScanner	# 项目名称,需要提前在web创建该项目
sonar.projectVersion=1.0	# 项目版本

# Comma-separated paths to directories with sources (required)
sonar.sources=src	# 源代码目录

# Language
sonar.language=php	# 代码语言

# Encoding of the source files
sonar.sourceEncoding=UTF-8	# 编码格式
  1. 新建项目
  • 创建项目

image

image

  • 创建项目令牌

image

  • 设置令牌过期时间

image

image

  • 选择分析代码语言,生成sonar-scanner执行命令

image

4.2.7.3 执行扫描分析命令

# 进入待扫描目录,复制sonar-scanner执行命令进行扫描
[root@jenkins php-sonar-runner]#pwd
/opt/sonar-examples-master/projects/languages/php/php-sonar-runner
[root@jenkins php-sonar-runner]#sonar-scanner \
  -Dsonar.projectKey=PHP::SimpleProject::SonarQubeScanner \
  -Dsonar.sources=. \
  -Dsonar.host.url=http://10.0.0.168:9000 \
  -Dsonar.token=sqp_af5455edc6430bf9c6065e300d758441c7be2589

查看执行结果

...
INFO: ------------- Run sensors on project
INFO: Sensor Analysis Warnings import [csharp]
INFO: Sensor Analysis Warnings import [csharp] (done) | time=1ms
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=30ms
INFO: SCM Publisher No SCM system was detected. You can use the 'sonar.scm.provider' property to explicitly specify it.
INFO: CPD Executor Calculating CPD for 1 file
INFO: CPD Executor CPD calculation finished (done) | time=30ms
INFO: Analysis report generated in 90ms, dir size=142.4 kB
INFO: Analysis report compressed in 9ms, zip size=24.1 kB
INFO: Analysis report uploaded in 36ms
INFO: ANALYSIS SUCCESSFUL, you can find the results at: http://10.0.0.168:9000/dashboard?id=PHP%3A%3ASimpleProject%3A%3ASonarQubeScanner
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://10.0.0.168:9000/api/ce/task?id=AYkVbgu4jnYPb4OTsyQA
INFO: Analysis total time: 13.567 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 15.584s
INFO: Final Memory: 19M/67M
INFO: ------------------------------------------------------------------------

4.2.7.4 验证Web页面扫描结果

image

4.2.8 Jenkins执行代码扫描

4.2.8.1 安装SonarQube Scanner插件

image

4.2.8.2 添加Sonarqube Server URL

自定义SonarQube Server名称,配置Server URL

image

4.2.8.3 添加sonarqube scanner扫描器

  • 手动添加scanner扫描器

自定义名称,sonar-scanner目录路径

​​image​​

  • 自动安装

也可选择自动安装

image

4.2.8.4 配置扫描

sonarqube网页新建job1-web项目,生成token信息,配置信息参考如下:

sonar.projectKey=job1-web
sonar.projectName=job1-web
sonar.projectVersion=1.0
sonar.sources=./
sonar.language=php
sonar.sourceEncoding=UTF-8
sonar.token=sqp_f051847ec08d00e6b057af64327858a7e77adf61

Jenkins选择项目,增加配置步骤选择Execute SonarQube Scanner,配置扫描信息

image

4.2.8.5 验证扫描结果

构建项目,查看构建日志

image

查看项目构建历史,可跳转SonarQube查看扫描结果

image

扫描结果

image

4.3 创建自动构建项目

4.3.1 编写部署脚本

对不同代码分支、不同分组的web服务器进行自动部署或回退操作

#!/bin/bash
DATE=`date +%Y-%m-%d_%H-%M-%S`
METHOD=$1
BRANCH=$2
GROUP_LIST=$3

function IP_list(){
  if [[ ${GROUP_LIST} == "GROUP1" ]];then
     Server_IP="10.0.0.175"
     echo ${Server_IP}
     ssh root@10.0.0.189 ""echo set weight Web_80/10.0.0.175 0" | socat stdio /run/haproxy/admin.sock"
     ssh root@10.0.0.190 ""echo set weight Web_80/10.0.0.175 0" | socat stdio /run/haproxy/admin.sock"
  elif [[ ${GROUP_LIST} == "GROUP2" ]];then
     Server_IP="10.0.0.176 10.0.0.177"
     echo ${Server_IP}
     ssh root@10.0.0.189 ""echo set weight Web_80/10.0.0.175 0" | socat stdio /run/haproxy/admin.sock"
     ssh root@10.0.0.190 ""echo set weight Web_80/10.0.0.175 0" | socat stdio /run/haproxy/admin.sock"
  elif [[ ${GROUP_LIST} == "GROUP3" ]];then
     Server_IP="10.0.0.175 10.0.0.176 10.0.0.177"
     echo ${Server_IP}
  fi
}

function clone_code(){
  echo "即将开始clone ${BRANCH}分支的代码"
  cd /data/git/web/ && rm -rf test-project && git clone -b  ${BRANCH} git@10.0.0.160:test-service/test-project.git
  echo "${BRANCH}分支代码cllone完成,即开始代码扫描"
  #tar czvf myapp.tar.gz ./index.html
  #echo "代码编译完成,即将开始分发部署包"
}

function scanner_code(){
  cd /data/git/web/test-project && /usr/local/src/sonar-scanner/bin/sonar-scanner \
  -Dsonar.projectKey=job1-web  \
  -Dsonar.sources=.  \
  -Dsonar.host.url=http://10.0.0.168:9000  \
  -Dsonar.sourceEncoding=UTF-8  \
  -Dsonar.token=sqp_f051847ec08d00e6b057af64327858a7e77adf61
  echo "代码扫描完成,请打开sonarqube查看扫描结果"
}

function code_maven(){
  echo  "cd /data/git/web/test-project  && mvn clean package -Dmaven.test.skip=true"
  echo "代码编译完成"
}


function make_zip(){
  cd /data/git/web/test-project && zip -r code.zip ./index.html
  echo "代码打包完成"
}



down_node(){
  for node in ${Server_IP};do
    ssh root@10.0.0.189 ""echo set weight Web_80/${node} 0" | socat stdio /run/haproxy/admin.sock"
    echo "${node} 从负载均衡10.0.0.189下线成功"
    ssh root@10.0.0.190 ""echo set weight Web_80/${node} 0" | socat stdio /run/haproxy/admin.sock"
    echo "${node} 从负载均衡10.0.0.190下线成功"
  done
}

function scp_zipfile(){
  for node in ${Server_IP};do
    scp /data/git/web/test-project/code.zip  root@${node}:/var/lib/tomcat9/webdir/code-${DATE}.zip
    ssh root@${node} "unzip /var/lib/tomcat9/webdir/code-${DATE}.zip -d /var/lib/tomcat9/webdir/code-${DATE} && rm -rf /var/lib/tomcat9/webapps/myapp && ln -sv  /var/lib/tomcat9/webdir/code-${DATE} /var/lib/tomcat9/webapps/myapp && rm -rf /var/lib/tomcat9/webdir/code-${DATE}.zip"
  done
}

function stop_tomcat(){
  for node in ${Server_IP};do
    ssh root@${node}   "systemctl stop tomcat9"
  done
}

function start_tomcat(){
  for node in ${Server_IP};do
    ssh root@${node}   "systemctl start tomcat9"
    #sleep 5
  done
}

function web_test(){
  sleep 10
  for node in ${Server_IP};do
    NUM=`curl -s  -I -m 10 -o /dev/null  -w %{http_code}  http://${node}:8080/myapp/index.html`
    if [[ ${NUM} -eq 200 ]];then
       echo "${node} myapp URL 测试通过,即将添加到负载"
       add_node ${node}
    else
       echo "${node} 测试失败,请检查该服务器是否成功启动tomcat"
    fi
  done
}

function add_node(){
   node=$1
    if [[ ${GROUP_LIST} == "GROUP3" ]];then
      ssh root@10.0.0.189 ""echo set weight Web_80/10.0.0.175 1" | socat stdio /run/haproxy/admin.sock"
	  echo ${node},"-----> 10.0.0.189"
      ssh root@10.0.0.190 ""echo set weight Web_80/10.0.0.175 1" | socat stdio /run/haproxy/admin.sock"
	  echo ${node},"-----> 10.0.0.190"
    fi
    ##########################################
    if [ ${node} == "10.0.0.175" ];then
       echo "灰度部署环境服务器-->10.0.0.175 部署完毕,请进行代码测试!"
    else
      ssh root@10.0.0.189 ""echo set weight Web_80/${node} 1" | socat stdio /run/haproxy/admin.sock"
	  echo ${node},"-----> 10.0.0.189"
      ssh root@10.0.0.190 ""echo set weight Web_80/${node} 1" | socat stdio /run/haproxy/admin.sock"
	  echo ${node},"-----> 10.0.0.190"
    fi
}


function rollback_last_version(){
  for node in ${Server_IP};do
   echo $node
   NOW_VERSION=`ssh root@${node} ""/bin/ls -l  -rt /var/lib/tomcat9/webapps/ | awk -F"->" '{print $2}'  | tail -n1""`
   NOW_VERSION=`basename ${NOW_VERSION}`
   echo $NOW_VERSION,"NOW_VERSION"
    NAME=`ssh  root@${node}  ""ls  -l  -rt  /var/lib/tomcat9/webdir/ | grep -B 1 ${NOW_VERSION} | head -n1 | awk '{print $9}'""`
   echo $NAME,""NAME
   ssh root@${node} "rm -rf /var/lib/tomcat9/webapps/myapp && ln -sv /var/lib/tomcat9/webdir/${NAME} /var/lib/tomcat9/webapps/myapp"
  done 
}

function delete_history_version(){
  for node in ${Server_IP};do
    NUM=`ssh root@${node}  ""/bin/ls -l -d -rt /var/lib/tomcat9/webdir/code-* | wc -l""`
    echo "${node} --> ${NUM}"
      if [ ${NUM} -gt 5 ];then
         NAME=`ssh root@${node} ""/bin/ls -l -d -rt /var/lib/tomcat9/webdir/code-* | head -n1 | awk '{print $9}'""`
         ssh root@${node} "rm -rf ${NAME}"
        echo "${node} 删除历史版本${NAME}成功!"
      fi
  done 
}

main(){
   case $1  in
      deploy)
        IP_list;    
        clone_code;
        scanner_code;
        make_zip;
        down_node;
        stop_tomcat;
        scp_zipfile;
        start_tomcat;
        web_test;
        delete_history_version;
         ;;
      rollback_last_version)
        IP_list;
        #echo ${Server_IP}
        down_node;
        stop_tomcat;
        rollback_last_version;
        start_tomcat;
        web_test;
         ;;
    esac
}

main $1 $2 $3

4.3.2 设置构建参数

image

3.4.13image

4.3.3 设置代码仓库路径,访问凭证

凭证设置可参考:3.1 gitlab配置ssh key

image

4.3.4 编写构建步骤

编写shell执行命令

image

4.4 自动构建测试

4.4.1 clone代码至本地

[root@deploy opt]#git clone  -b develop git@10.0.0.160:test-service/test-project.git
Cloning into 'test-project'...
time="2023-07-05T10:45:14+08:00" level=info msg="SSL_CERT_DIR is configured" ssl_cert_dir=/opt/gitlab/embedded/ssl/certs/
remote: Enumerating objects: 46, done.
remote: Counting objects: 100% (37/37), done.
remote: Compressing objects: 100% (32/32), done.
remote: Total 46 (delta 10), reused 17 (delta 5), pack-reused 9
Receiving objects: 100% (46/46), 5.33 KiB | 5.33 MiB/s, done.
Resolving deltas: 100% (10/10), done.

4.4.2 修改代码并上传仓库

[root@deploy test-project]#cd test-project
[root@deploy test-project]#echo "<h1>1111111111</h1>" >> index.html 
[root@deploy test-project]#git add index.html 
[root@deploy test-project]#git commit -m 'v1'
[develop deac327] v1
 1 file changed, 1 insertion(+), 13 deletions(-)
[root@deploy test-project]#git push
time="2023-07-05T11:01:34+08:00" level=info msg="SSL_CERT_DIR is configured" ssl_cert_dir=/opt/gitlab/embedded/ssl/certs/
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 289 bytes | 289.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: 
remote: To create a merge request for develop, visit:
remote:   http://10.0.0.160/test-service/test-project/-/merge_requests/new?merge_request%5Bsource_branch%5D=develop
remote: 
To 10.0.0.160:test-service/test-project.git
   3e85554..deac327  develop -> develop

查看gitlab仓库

image​​

4.4.3 升级测试服务器

选择构建参数,执行构建

image

查看构建日志

image

4.4.4 验证web测试服务器

访问升级后的web服务器(10.0.0.175)

image

测试服务器已下线

image

4.4.5 访问web网页

配置hots域名解析

10.0.0.188 www.web.com

image

image

4.4.6 升级其他web服务器

构建参数,选择GROUP2

image

完成升级,后端服务器已全上线

image

4.4.7 验证web页面

image

4.5 实现pipeline构建

编写Jenkinsfile,将所有web服务器进行升级部署,可根据其他需求进行修改

pipeline {
    agent any
    environment {
        Server_IP = '10.0.0.175,10.0.0.176,10.0.0.177'
        DATE = sh(script: 'date +%Y-%m-%d_%H-%M-%S', returnStdout: true).trim()
    }
  
    stages {
        stage('clone代码') {
            steps {
                echo "即将开始clone 代码"
                git branch: 'develop', credentialsId: '0cab95c5-cb24-4bb6-b03e-bc6576f8dd08', url: 'git@10.0.0.160:test-service/test-project.git'
            }
        }
      
        stage('代码扫描') {
            steps {
                echo "代码扫描"
                sh '''cd /var/lib/jenkins/workspace/test-pipline && /usr/local/src/sonar-scanner/bin/sonar-scanner \\
                -Dsonar.projectKey=job1-web  \\
                -Dsonar.sources=.  \\
                -Dsonar.host.url=http://10.0.0.168:9000  \\
                -Dsonar.sourceEncoding=UTF-8  \\
                -Dsonar.token=sqp_f051847ec08d00e6b057af64327858a7e77adf61'''
            }
        }
      
        stage('代码打包') {
            steps {
                echo "代码打包"
                sh 'cd /var/lib/jenkins/workspace/test-pipline && zip -r code.zip ./index.html'
            }
        }
      
        stage('后端服务器下线') {
            steps {
                echo '后端服务器下线'
		        script {
                    for (def node in Server_IP.split(',')){
                        sh """
			                ssh root@10.0.0.189 ""echo set weight Web_80/${node} 0" | socat stdio /run/haproxy/admin.sock"
                            echo "${node} 从负载均衡10.0.0.189下线成功"
                            ssh root@10.0.0.190 ""echo set weight Web_80/${node} 0" | socat stdio /run/haproxy/admin.sock"
                            echo "${node} 从负载均衡10.0.0.190下线成功"
                        """
                    }
                }
            }
        }
      
      
        stage('stop tomcat') {
            steps {
                echo 'stop tomcat'
		        script {
                    for (def node in Server_IP.split(',')){
                        sh """
                            ssh root@${node}  "systemctl stop tomcat9"
                        """
                    }
                }
            }
        }
      
        stage('scp_zipfile') {
            steps {
                echo 'scp_zipfile'
                script {
                    for (def node in Server_IP.split(',')){
                        sh """
                            scp /var/lib/jenkins/workspace/test-pipline/code.zip  root@${node}:/var/lib/tomcat9/webdir/code-${env.DATE}.zip
                            ssh root@${node} "unzip /var/lib/tomcat9/webdir/code-${env.DATE}.zip -d /var/lib/tomcat9/webdir/code-${env.DATE} && rm -rf /var/lib/tomcat9/webapps/myapp && ln -sv  /var/lib/tomcat9/webdir/code-${env.DATE} /var/lib/tomcat9/webapps/myapp && rm -rf /var/lib/tomcat9/webdir/code-${env.DATE}.zip"
                        """
                    }
                }
            }
        }
      
      
        stage('start tomcat') {
            steps {
                echo 'start tomcat'
		        script {
                    for (def node in Server_IP.split(',')){
                        sh """
                            ssh root@${node}  "systemctl start tomcat9"
                        """
                    }
                }
            }
        }
      
        stage('web_test') {
            steps {
                echo 'web_test'
                sleep 10
		        script {
                    for (def node in Server_IP.split(',')){
                        sh """
				            NUM=\$(curl -s  -I -m 10 -o /dev/null  -w %{http_code}  http://${node}:8080/myapp/index.html)
				            if [ \${NUM} -eq 200 ];then
       					        echo "${node} myapp URL 测试通过,即将添加到负载"
					            ssh root@10.0.0.189 ""echo set weight Web_80/${node} 1" | socat stdio /run/haproxy/admin.sock"
					            echo "10.0.0.189"
					            ssh root@10.0.0.190 ""echo set weight Web_80/${node} 1" | socat stdio /run/haproxy/admin.sock"
					            echo "10.0.0.190"
    			        	else
       					        echo "${node} 测试失败,请检查该服务器是否成功启动tomcat"
    				        fi
                        """
                    }
                }	
            }
        }
      
        stage('delete_history_version') {
            steps {
                echo 'delete history version'
		        script {
                    for (def node in Server_IP.split(',')){
                        sh """
                            NUM=\$(ssh root@${node}  ""/bin/ls -l -d -rt /var/lib/tomcat9/webdir/code-* | wc -l"")
			                echo "${node} --> \${NUM}"
			                if [ \${NUM} -gt 5 ];then
				                NAME=`ssh root@${node} ""/bin/ls -l -d -rt /var/lib/tomcat9/webdir/code-* | head -n1 | awk '{print \$9}'""`
			                	ssh root@${node} "rm -rf \${NAME}"
			                	echo "${node} 删除历史版本\${NAME}成功!"
			                fi
                        """
                    }
                }
            }
        }
      
    }
}

创建项目,复制脚本

image

运行结果

image

查看每个阶段日志

image