一、安装基础环境

1.1 安装JDK1.8

上传JDK1.8二进制包至服务器

解压二进制包并添加java环境变量

1
2
3
4
5
6
7
8
9
~]$ tar xzvf jdk-8u211-linux-x64.tar.gz
~]$ mv jdk1.8.0_211/ /usr/local/
~]$ sudo vim /etc/profile
# Java环境变量
export JAVA_HOME=/usr/local/jdk1.8.0_211
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib:$CLASSPATH
export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin
export PATH=$PATH:${JAVA_PATH}

加载环境变量并验证

1
2
3
4
5
~]$ source /etc/profile 
~]$ java -version
java version "1.8.0_211
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

1.2 安装maven-3.6.3

下载maven二进制包解压并添加到环境变量

1
2
3
4
5
6
7
~]$ wget https://mirrors.bfsu.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
~]$ tar xzvf apache-maven-3.6.3-bin.tar.gz
~]$ sudo mv apache-maven-3.6.3 /usr/local/
~]$ sudo vim /etc/profile
# maven环境变量
export MAVEN_HOME=/usr/local/apache-maven-3.6.3
export PATH=$MAVEN_HOME/bin:$PATH

重新加载环境变量并验证

1
2
3
4
5
6
7
~]$ source /etc/profile
~]$ mvn -v
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /usr/local/apache-maven-3.6.3
Java version: 1.8.0_211, vendor: Oracle Corporation, runtime: /usr/local/jdk1.8.0_211/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-957.el7.x86_64", arch: "amd64", family: "unix"

1.3 安装Git

1
2
3
~]$ sudo yum install -y git
~]$ git --version
git version 1.8.3.1

1.4 安装NodeJs(前端用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 安装yarn
$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ yum install -y yarn
$ yarn -v
1.22.15

# 安装node-npm
$ wget https://nodejs.org/download/release/v10.18.1/node-v10.18.1-linux-x64.tar.gz && tar xzvf node-v10.18.1-linux-x64.tar.gz && mv node-v10.18.1-linux-x64 /usr/local/node-v10.18.1 && chown root:root -R /usr/local/node-v10.18.1/

$ cat >> /etc/profile <<EOF
# NodeJs环境变量
export NODE_HOME=/usr/local/node-v10.18.1
export PATH=\$NODE_HOME/bin:\$PATH
EOF

$ node -v && npm -v
v10.18.1
6.13.4

npm设置为国内仓库

1
2
~]$ npm config set registry https://registry.npm.taobao.org
~]$ npm config get registry

1.5 安装Yarn(前端用)

1
2
3
4
~]$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
~]$ yum install yarn -y
~]$yarn -v
1.22.5

二、安装Jenkins服务

2.1 下载安装Jenkins服务

下载jenkins的rpm包并安装

1
2
3
4
5
6
7
~]$ wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/jenkins-2.249.3-1.1.noarch.rpm

~]$ rpm -ivh jenkins-2.249.3-1.1.noarch.rpm
warning: jenkins-2.249.3-1.1.noarch.rpm: Header V4 RSA/SHA512 Signature, key ID 45f2c3d5: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:jenkins-2.249.3-1.1 ################################# [100%]s

创建jenkins宿主目录并配置jenkins-home到宿主目录

1
2
3
4
5
6
# 修改jenkins的主目录
创建Jenkins主目录
~]$ mkdir /data/jenkins -p
~]$ sudo chown jenkins:jenkins /data/jenkins/
~]$ vim /etc/sysconfig/jenkins
JENKINS_HOME="/data/jenkins"

修改jenkins配置添加自定义java环境变量并启动jenkins

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 ~]$ vim /etc/init.d/jenkins
# see http://www.nabble.com/guinea-pigs-wanted-----Hudson-RPM-for-RedHat-Linux-td25673707.html
candidates="
/etc/alternatives/java
/usr/local/jdk1.8.0_211/bin/java # 74行新添加为自己的路径
/usr/lib/jvm/java-1.8.0/bin/java
/usr/lib/jvm/jre-1.8.0/bin/java
/usr/lib/jvm/java-1.7.0/bin/java
/usr/lib/jvm/jre-1.7.0/bin/java
/usr/lib/jvm/java-11.0/bin/java
/usr/lib/jvm/jre-11.0/bin/java
/usr/lib/jvm/java-11-openjdk-amd64
/usr/bin/java
"

~]$ systemctl enable jenkins
jenkins.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig jenkins on
~]$ systemctl start jenkins

2.2 配置Jenkins国内仓库

配置jenkins国内镜像仓库

1
2
3
4
5
6
7
8
9
10
11
12
# 修改jenkins为国内镜像仓库
~]$ vim /data/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>

## 重启jenkins服务
~]$ systemctl daemon-reload && systemctl restart jenkins

上面配置jenkins国内镜像仓库失效用下面方法

1
2
3
 ~]$ cd $jenkins_home/updates			# 切换到jenkins宿主目录
~]$ sed -i 's/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json && \
sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json

浏览器访问jenkins8080端口

1
2
 ~]$ netstat  -anpt | grep 8080
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 13960/java

查看jenkins管理密码进行初始化

1
2
 ~]$ cat /data/jenkins/secrets/initialAdminPassword
0c23b38c14f44172a3b678213dfe8baa

2.3 需要安装的插件

Manage Jenkins –> Manage Plugins –> 可选插件 –> Search

安装以下插件

  • Git & Git Parameter
  • Maven Integration
  • Localization: Chinese
  • Pipeline
  • Config File Provider
  • Extended Choice Parameter
  • description setter
  • Build Name and Description Setter

2.4 Jenkins添加全局工具

添加自定义的工具列表,把前面我们安装的基础环境变量添加进去

Manage Jenkins –> Global Tool Configuration –> Maven配置 –> 默认settings提供 –> Settings file in filesystem –> 填写我们maven的settings.xml文件路径

Manage Jenkins –> Global Tool Configuration –> Maven配置 –> 默认全局settings提供 –> Global Settings file on filesystem –> 填写我们maven的settings.xml文件路径

三、创建pipeline的Job

Job的命名规范:项目组名_部署环境名_项目名称

3.1 创建dev_uat后端项目流水线

选择新建一个Job

输入Job名称,创建一个流水线类型的Job

3.2 dev—uat环境pipeline脚本与部署脚本

整个管道大致流程:

  1. 不同项目组成员登陆Jenkins账号,选择指定的项目点击构建。
  2. (拉取代码步骤)Jenkins通过Git插件拉取指定项目和指定分支的代码到本地。
  3. (Maven代码编译步骤)Maven对前面拉取的代码进行编译构建生成jar包。
  4. (发布代码步骤)Jenkins服务器执行流程
    • 将构建好的项目jar包 项目名称-exec.jar 移动至 ${project} 目录并格式化规范名称 项目名称-部署的环境-本次构建ID.jar
    • 将名称规范的jar包推送到目标部署服务器的 /tmp 目录下。
    • 通过传参的方式,让目标部署主机执行Jenkins服务器本地的部署脚本。
  5. (发布代码步骤)目标服务器脚本部署流程
    • shell脚本加载服务器环境变量。
    • 通过jps判断发布的服务是否正在运行,如果正在运行就停止服务。
    • 将旧jar包备份至../backup目录下,将/tmp下的新jar包移动到当前目录。
    • 启动服务程序,通过判断服务名称来决定服务启动的 JAVA_OPS参数。
    • 通过jps判断服务是否启动成功,如果启动成功就删除../backup备份目录下五天之前的jar包。

Jenkins的一个项目一个服务Pipeline脚本内容

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// 更换环境需要改的配置
// 1. parameters内的部署环境与对应Git项目地址
// 2. 拉取代码步骤中的对应环境代码分支
// 3.发布代码中的部署环境判断、远程部署的目标主机ip与用户名、不同环境的nacos服务器信息、jar_name环境变量
// 认证
def git_auth = "89efc092-2c68-4b4f-813f-b3e3148ef56e"
def deployment_huanjing = "dev"
def git_add = "http://172.23.1.57:8082/gitlab/backend/bas-center.git"
def git_branch = "develop"

def mysh(cmd) {
sh('#!/bin/sh -e\n' + cmd)
}

pipeline {
agent any

environment{
PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/jdk1.8.0_211/bin/:/usr/local/apache-maven-3.6.3/bin/"
}

parameters {
// 配置发布的环境变量
choice (choices: ["${deployment_huanjing}"], description: '部署的环境', name: 'Deployment')
//choice (choices: ['http://172.23.1.57:8082/gitlab/backend/cms-center.git'], description: 'Git地址', name: 'git_url')
choice (choices: ["${git_add}"], description: 'Git地址', name: 'git_url')
choice (choices: ["${git_branch}"], description: 'Git分支', name: 'git_fenzhi')
}

stages {
stage('1.拉取代码') {
steps {
//配置构建的分支
//checkout([$class: 'GitSCM', branches: [[name: '*/develop']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
checkout([$class: 'GitSCM', branches: [[name: "*/${git_branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
}
stage('2.Maven代码编译') {
steps {
mysh '''
source /etc/profile &> /dev/null
mvn clean package -Dmaven.test.skip=true
'''
}
}
stage('3.发布代码') {
steps {
mysh '''
if [ ${Deployment} = 'dev' ]; then
# 定义变量名称
# 目标部署主机的IP和用户名(需要提前做免密登录)
remote_host="172.23.1.55"
remote_user="root"
jar_name="bas-center"

# 定义不同环境的nacos注册中心地址
#uat环境nacos配置
#nacos_server="172.30.26.79:8848"
#dev环境nacos配置
nacos_server="172.23.1.55:8848"

# jenkins本地临时存放jar包目录
project_mulu="/root/project/\${jar_name}"

# 远程部署服务器的jar包目录
remote_service_mulu="/home/framework"

# 定义格式化包名生成变量
format_name=\${jar_name}-${Deployment}-${BUILD_NUMBER}
old_jar_name=\$(find ./* -name "\${jar_name}-*.jar")
new_jar_name="\${format_name}-exec.jar"

# 1.判断创建jar包目录,2.将构建后的jar重命名并移动到jar目录,3.发送jar包至部署服务器
[ -d \${project_mulu} ]||mkdir -p \${project_mulu}
mv \$old_jar_name \${project_mulu}/\$new_jar_name
scp \${project_mulu}/\$new_jar_name \${remote_user}@\${remote_host}:/tmp/

# 远程服务器传参方式执行本地部署脚本
ssh \${remote_user}@\${remote_host} "bash -s" < ~/scripts/dev_uat.sh \${jar_name} \${remote_host} \${remote_service_mulu} \${new_jar_name} ${Deployment} \${nacos_server}

fi
'''
}
}
}
}

Jenkins的一个项目多个服务Pipeline脚本内容

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// 更换环境需要改的配置
// 1. parameters内的部署环境与对应Git项目地址
// 2. 拉取代码步骤中的对应环境代码分支
// 3.发布代码中的部署环境判断、远程部署的目标主机ip与用户名、不同环境的nacos服务器信息、jar_name环境变量
// 认证
def git_auth = "89efc092-2c68-4b4f-813f-b3e3148ef56e"
def deployment_huanjing = "dev"
def git_add = "http://172.23.1.57:8082/gitlab/backend/message-center.git"
def git_branch = "develop"

// 定义mysh函数,取消默认sh打印的多于日志,类似于每个变量名称前都有+号
def mysh(cmd) {
sh('#!/bin/sh -e\n' + cmd)
}

pipeline {
agent any

environment{
PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/jdk1.8.0_211/bin/:/usr/local/apache-maven-3.6.3/bin/"
}

parameters {
// 配置发布的环境变量
choice (choices: ["${deployment_huanjing}"], description: '部署的环境', name: 'Deployment')
//choice (choices: ['http://172.23.1.57:8082/gitlab/backend/cms-center.git'], description: 'Git地址', name: 'git_url')
choice (choices: ["${git_add}"], description: 'Git地址', name: 'git_url')
choice (choices: ["${git_branch}"], description: 'Git分支', name: 'git_fenzhi')
}

stages {
stage('1.拉取代码') {
steps {
//配置构建的分支
//checkout([$class: 'GitSCM', branches: [[name: '*/develop']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
checkout([$class: 'GitSCM', branches: [[name: "*/${git_branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
}
stage('2.Maven代码编译') {
steps {
mysh '''
source /etc/profile &> /dev/null
mvn clean package -Dmaven.test.skip=true
'''
}
}
stage('3.发布代码') {
steps {
mysh '''
if [ ${Deployment} = 'dev' ]; then
# 定义变量名称
# 目标部署主机的IP和用户名(需要提前做免密登录)
remote_host="172.23.1.55"
remote_user="root"
message_cneter="message-consumer message-producer"
info="[INFO]"

# 定义不同环境的nacos注册中心地址
#uat环境nacos配置
#nacos_server="172.30.26.79:8848"
#dev环境nacos配置
nacos_server="172.23.1.55:8848"

# 循环获取单个项目下的多个部署服务名称实现部署
for jar_name in `echo \${message_cneter}`
do
# jenkins本地临时存放jar包目录
project_mulu="/root/project/message-center/\${jar_name}"

# 远程部署服务器的jar包目录
remote_service_mulu="/home/framework"

# 定义格式化包名生成变量
format_name=\${jar_name}-${Deployment}-${BUILD_NUMBER}
old_jar_name=\$(find ./* -name "\${jar_name}-*.jar")
new_jar_name="\${format_name}-exec.jar"

# 1.判断创建jar包目录,2.将构建后的jar重命名并移动到jar目录,3.发送jar包至部署服务器
[ -d \${project_mulu} ]||mkdir -p \${project_mulu}
mv \$old_jar_name \${project_mulu}/\$new_jar_name
scp \${project_mulu}/\$new_jar_name \${remote_user}@\${remote_host}:/tmp/

# 远程服务器传参方式执行本地部署脚本
ssh \${remote_user}@\${remote_host} "bash -s" < ~/scripts/dev_uat.sh \${jar_name} \${remote_host} \${remote_service_mulu} \${new_jar_name} ${Deployment} \${nacos_server}

done

if [ \${?} -eq 0 ];then
echo "=================================================================================================================="
echo "\${info} \${message_cneter}项目部署部署成功..."
echo "\${info} 部署的目标主机:\${remote_host}"
echo "\${info} 部署主机服务目录:\${remote_service_mulu}"
echo "\${info} 部署的服务信息:"
ssh \${remote_user}@\${remote_host} ". /etc/profile && jps|grep message"
echo "=================================================================================================================="
else
echo "\${info} \${message_cneter}项目部署失败,请检查日志..."
fi
fi
'''
}
}
}
}

DEV和UAT环境使用的通用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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# 第一个参数为${jar_name} 
# 第二个参数为${remote_host}
# 第三个参数为${remote_service_mulu}
# 第四个参数为${new_jar_name}
# 第五个参数为${Deployment} 部署的环境
# 第六个参数为${nacos_server}

jar_ops1="-Xms256m -Xmx512m -server -Dspring.profiles.active=$5 -Dnacos.server=$6"
jar_ops2="-Xms1000m -Xmx1000m -server -Dspring.profiles.active=$5 -Dnacos.server=$6"
INFO="[INFO]"

# 加载系统环境变量
source /etc/profile &> /dev/null


# 通过jps判断服务进程是否启动,如果启动就kill,未启动就提示信息
if [ $(jps -l|grep "$1"|awk '{print $1}'|wc -l) -ge 1 ];then
echo "$INFO $1 服务进程已经存在,正在停止服务..."
jps -l | grep "$1"
kill -9 $(jps -l|grep "$1"|awk '{print $1}')
if [ $(ps elf|grep -v grep |grep $1|wc -l) = "0" ];then
echo "$INFO $1 服务进程停止成功,开始部署服务......"
fi
else
echo "$INFO $1 服务进程不存在,开始部署服务......"
fi
sleep 3


# 1.切换到目标服务器服务部署目录,2.备份原有jar包至../backup目录,3.移动新jar包到当前项目目录下
cd $3
[ -d ../backup ]|| mkdir ../backup -p

old_jar=$(basename $(find ./$1*-exec.jar -type f))

if [ -f ./${old_jar} ];then
echo "${INFO} 备份${1}服务的历史jar包至${3}/../backup目录下"
echo "历史的jar包名称:${old_jar}"
mv ${old_jar} ../backup/
else
echo "${INFO} 不存在历史jar包,不进行备份..."
fi
#find ./$1*.jar -type f -exec mv {} ../backup/ \;
echo "${INFO} 移动${1}服务最新jar包${4}${3}目录下。"
mv /tmp/$4 ./


# 后台启动jar程序
if [ $1 == "gratus-center" -o $1 == "pms-center" -o $1 == "oms-center" -o $1 == "payment-center" ];then
echo "$INFO 正在启动${1}服务..."
nohup java -jar $jar_ops2 $3/$4 >> $3/nohup.out 2>&1 &
sleep 20
else
echo "$INFO 正在启动${1}服务..."
nohup java -jar $jar_ops1 $3/$4 >> $3/nohup.out 2>&1 &
sleep 20
fi


# 判断服务是否启动成功
if [ $(jps -l |grep -v grep |grep $1|wc -l) -ge 1 ];then
# find ../backup/$1*.jar -mtime 5 -exec rm -f {} \;
echo "$INFO ------------------------------------------------------------------------"
echo "$INFO DEPLOYMENT SUCCESS"
echo "$INFO ------------------------------------------------------------------------"
echo "$INFO ${1}服务部署成功,新的部署项目名称为$4"
echo $(jps -l |grep -v grep |grep $1)
echo "$INFO 部署的目标主机:$2"
echo "$INFO 目标主机服务存放目录:$3/$4"
echo "$INFO 历史jar包备份目录:$3../backup/$4"
else
echo "${ERRO} ${1}服务发布失败,请查看$3/nohup.out输出日志"
exit 1
fi

3.3 preprd-prd环境pipeline脚本与部署脚本

整个管道大致流程:

  1. 不同项目组成员登陆Jenkins账号,选择指定的项目点击构建。
  2. (拉取代码步骤)Jenkins通过Git插件拉取指定项目和指定分支的代码到本地。
  3. (Maven代码编译步骤)Maven对前面拉取的代码进行编译构建生成jar包。
  4. (发布代码步骤)Jenkins服务器执行流程
    • 将构建好的项目jar包 项目名称-exec.jar 移动至 ${project} 目录并格式化规范名称 项目名称-部署的环境-本次构建ID.jar
    • 判断部署的环境如果为pro生产环境,即获取nacos的登录token,之后通过curl针对当前部署的服务在nocas进行下线操作并延迟20秒钟。
    • 将名称规范的jar包推送到for循环获取到的目标部署服务器 /tmp 目录下。
    • 通过传参的方式,让目标部署主机执行Jenkins服务器本地的部署脚本。
  5. (发布代码步骤)目标服务器脚本部署流程
    • shell脚本加载服务器环境变量。
    • 通过jps判断发布的服务是否正在运行,如果正在运行就停止服务。
    • 将旧jar包备份至../backup目录下,将/tmp下的新jar包移动到当前目录。
    • 启动最新的服务程序jar包
    • 通过for循环三次每次间隔10秒对服务的ip:port/doc.html页面健康探测,状态码为200即为active。
    • 判断健康检查为active时即打印成功的部署信息,Jeknis继续下一个发布操作。
    • 判断健康检查非active时,随后判断部署的环境是否为prd生产环境,当为生产环境时执行回滚版本操作,从backup目录下移动上一个版本的jar包到服务发布目录,重新启动历史jar包,健康探测成功后退出脚本,终止后续发布操作。非prd生产环境时就退出脚本终止后续发布操作。

preprd_prd的Pipeline脚本

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// 更换环境需要改的配置
// 1. git的验证ID、git地址、git拉取的分支、部署的环境、当前服务使用的端口号
// 2. 发布代码中的:jar_name、remote_host_list(多个主机空格隔开)、remote_user、remote_service_mulu、project_mulu、nacos_server、nacos_username、nacos_password
// gitlab认证账号密码的JenkinsID
def git_auth = "e810a67e-8430-4517-8f58-25b5bb0cc103"
def git_add = "http://172.23.1.57:8082/gitlab/backend/cms-center.git"
def git_branch = "develop"
def deployment_huanjing = "uat"
def remote_service_port = "7400"

def mysh(cmd) {
sh('#!/bin/sh -e\n' + cmd)
}

pipeline {
agent any

environment{
PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/jdk1.8.0_211/bin/:/usr/local/apache-maven-3.6.3/bin/"
}

parameters {
// 配置发布的环境变量
choice (choices: ["${deployment_huanjing}"], description: '部署的环境', name: 'Deployment')
choice (choices: ["${git_add}"], description: 'Git地址', name: 'git_url')
choice (choices: ["${git_branch}"], description: 'Git分支', name: 'git_fenzhi')
choice (choices: ["${remote_service_port}"], description: '服务端口号', name: 'Remote_service_port')
}

stages {
stage('1.拉取代码') {
steps {
//配置构建的分支
//checkout([$class: 'GitSCM', branches: [[name: '*/develop']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
checkout([$class: 'GitSCM', branches: [[name: "*/${git_branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
}
stage('2.Maven代码编译') {
steps {
mysh '''
source /etc/profile &> /dev/null
mvn clean package -Dmaven.test.skip=true
'''
}
}
stage('3.发布代码') {
steps {
mysh '''
# 定义构建后jar包前缀变量名称
jar_name="cms-center"

# 目标部署主机的IP和用户名(需要提前做免密登录)
remote_host_list="172.23.5.92 172.23.5.107"
remote_user="root"
# 远程部署服务器的jar包目录
remote_service_mulu="/home/framework"

# jenkins本地临时存放jar包目录
project_mulu="/root/project/\${jar_name}"

# 定义nacos登录信息
# dev
#nacos_server="172.23.5.117:8848"
# uat
nacos_server="172.23.5.117:8849"
nacos_username="nacos"
nacos_password="neoderm2020"
nacos_token=`curl -s -X POST -d "username=\${nacos_username}&password=\${nacos_password}" \${nacos_server}/nacos/v1/auth/users/login | awk -F '"' '{print $4}'`

# 定义格式化包名生成变量
format_name=\${jar_name}-${Deployment}-${BUILD_NUMBER}
old_jar_name=\$(find ./* -name "\${jar_name}-*.jar")
new_jar_name="\${format_name}-exec.jar"

# 1.Jenkins本地判断创建jar包目录。2.将构建后的jar重命名并移动到jar目录。3.判断部署环境如果为prd环境则进行nacos注册中心节点下线操作。4.传送最新jar包至远程服务器。5.远程主机执行本地部署脚本
[ -d \${project_mulu} ]||mkdir -p \${project_mulu}
mv \$old_jar_name \${project_mulu}/\$new_jar_name

for remote_host in `echo \${remote_host_list}`
do
echo "===========================【开始部署\${jar_name}服务至远程主机:\${remote_host}】==========================="
# 根据部署环境判断是否nacos提前下线节点
if [ ${Deployment} = 'uat' ]; then
nacos_offline_param="serviceName=\${jar_name}&clusterName=DEFAULT&groupName=DEFAULT_GROUP&ip=\${remote_host}&port=${Remote_service_port}&enabled=false"
[ "\${nacos_token}" == "" ]||echo "[INFO] 获取到Nacos登录Token:\${nacos_token}"
echo "[INFO] 正在从Nacos服务器下线\${remote_host}节点的\${jar_name}服务..."
curl -s -X PUT -d "${nacos_offline_param}" http://${nacos_server}/nacos/v1/ns/instance?&accessToken=${Nacos_Token} && echo "[INFO] 通知Nacos服务下线成功,20秒后开始部署服务..."
sleep 20
fi

scp \${project_mulu}/\$new_jar_name \${remote_user}@\${remote_host}:/tmp/
# 远程服务器传参方式执行本地部署脚本
ssh \${remote_user}@\${remote_host} "bash -s" < ~/scripts/preprd_prd.sh \${jar_name} \${remote_host} \${remote_service_mulu} \${new_jar_name} ${Deployment} \${nacos_server} ${Remote_service_port}
echo "================================================【END】================================================"
done
'''
}
}
}
}

preprd_prd的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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# 第一个参数为${jar_name} 
# 第二个参数为${remote_host}
# 第三个参数为${remote_service_mulu}
# 第四个参数为${new_jar_name}
# 第五个参数为${Deployment} 部署的环境
# 第六个参数为${nacos_server}
# 第七个参数为${remote_service_port}

jar_ops="-Xms256m -Xmx512m -server -Dspring.profiles.active=$5 -Dnacos.server=$6"
INFO="[INFO]"
ERRO="[ERRO]"


# 加载系统环境变量
source /etc/profile &> /dev/null


# 通过jps判断服务进程是否启动,如果启动就kill,未启动就提示信息
if [ $(jps -l|grep "${1}"|awk '{print $1}'|wc -l) -ge 1 ];then
echo "${INFO} ${1}服务进程已经存在,正在停止服务..."
jps -l | grep "${1}"
kill -9 $(jps -l|grep "${1}"|awk '{print $1}')
if [ $(ps elf|grep -v grep |grep ${1}|wc -l) = "0" ];then
echo "${INFO} ${1}服务已经停止成功,开始部署服务..."
fi
else
echo "${INFO} ${1}服务进程不存在,开始部署服务..."
fi

sleep 3

# 1.切换到目标服务器服务部署目录,2.备份原有jar包至../backup目录,3.移动新jar包到当前项目目录下
cd ${3}
[ -d ../backup ]|| mkdir ../backup -p
old_jar=$(basename $(find ./$1*-exec.jar -type f))

if [ -f ./${old_jar} ];then
echo "${INFO} 备份${1}服务的历史jar包至${3}/../backup目录下"
echo "${INFO} 历史的jar包名称:${old_jar}"
mv ${old_jar} ../backup/
else
echo "${INFO} 不存在历史jar包,不进行备份..."
fi

echo "${INFO} 移动${1}服务最新jar包${4}${3}目录下。"
mv /tmp/$4 ./


# 后台启动jar程序
echo "$INFO 正在启动${1}服务..."
nohup java -jar ${jar_ops} ${3}/${4} >> ${3}/nohup.out 2>&1 &
sleep 20


# 针对服务进行健康检查,如果服务状态码为200即为成功
for i in `seq 3`
do
#echo "${INFO}正在进行第${i}次${2}:${7}/doc.html主机${7}端口健康探测..."
http_code=$(curl -m 5 -s -o /dev/null -w %{http_code} http://${2}:${7}/doc.html)
if [ "${http_code}" == "200" ];then
service_status="active"
echo "${INFO} 服务健康检查成功,状态为${service_status}"
break
else
service_status="down"
echo "${INFO}${i}${2}:${7}/doc.html主机${7}端口健康探测状态为down..."
#echo "${INFO}第${i}次服务健康检查失败,状态为${service_status}"
fi
sleep 10
done


# 判断服务是否启动成功.
# 如果发布成功就打印成功信息脚本正常退出,pipeline继续发布下个节点版本。
# 如果发布失败判断是否为pro环境,如果为pro环境将回滚至发布前版本,脚本退出,pipeline脚本退出终止后续节点发版
# 如果发布失败后环境不为pro,那么将打印发布失败信息脚本退出。
if [ "$service_status" == "active" ];then
# find ../backup/$1*.jar -mtime 5 -exec rm -f {} \;
echo "$INFO ------------------------------------------------------------------------"
echo "$INFO DEPLOYMENT SUCCESS"
echo "$INFO ------------------------------------------------------------------------"
echo "$INFO ${1}服务部署成功,新的部署项目名称为$4"
echo $(jps -l |grep -v grep |grep $1)
echo "$INFO 部署的目标主机:$2"
echo "$INFO 目标主机服务存放目录:$3/$4"
echo "$INFO 历史jar包备份目录:$3../backup/$4"
else
if [ "$5" == "uat" ];then
echo "${ERRO} ${1}服务发布失败,已停止后续节点发布操作,开始回滚服务至${old_jar}版本..."
find ./ -name "${1}-*.jar" -exec mv {} ../backup \;
mv ../backup/${old_jar} ./
[ -f ./${old_jar} ]&& echo "$INFO 历史jar包已经移动至${3}发布目录下,正在启动服务..."
nohup java -jar $jar_ops $3/${old_jar} >> $3/nohup.out 2>&1 &
sleep 30
if [ $(jps -l |grep -v grep |grep $1|wc -l) -ge 1 ];then
echo "$INFO ------------------------------------------------------------------------"
echo "$INFO RollBACK SUCCESS TO ${old_jar}"
echo "$INFO ------------------------------------------------------------------------"
exit 100
else
echo "${ERRO} ${1}服务发布失败,请查看$3/nohup.out输出日志..."
exit 1
fi
else
echo "${ERRO} ${1}服务发布失败,请查看$3/nohup.out输出日志"
fi
fi

3.3 创建前端项目Job

安装Nginx服务器

1
2
/]$ vim /etc/yum.repos.d/nginx.repo
/]$ yum install -y nginx

创建web根目录并生成nginx虚拟机主机配置文件

1
2
3
4
5
6
7
8
9
10
/]$ mkdir -p /data/web
/]$ vim /etc/nginx/conf.d/web-center-admin.conf
server {
listen 8066;

location / {
root /data/web/;
try_files $uri $uri/ /admin/index.html;
}
}

测试nginx配置是否正常,启动nginx服务验证。

1
2
3
4
5
/]$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
/]$ systemctl enable nginx
/]$ systemctl start nginx

前端使用的pipeline代码

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 更换环境需要修改的配置
// 1. 通用全局变量中的Gitlab账号的凭据ID、要部署的环境(dev|uat)、当前流水线使用的git地址、流水线构建的分支
// 2. 拉取代码步骤中的对应环境代码分支
// 3.发布代码中的部署环境判断、远程部署的目标主机ip与用户名、不同环境的nacos服务器信息、jar_name环境变量
// 部署的jar包命名规范:项目名称-部署的环境-本次构建ID.jar

// Git认证信息与部署环境项目分支
def deployment_huanjing = "dev"
def git_auth = "89efc092-2c68-4b4f-813f-b3e3148ef56e"
def git_add = "http://172.23.1.57:8082/gitlab/frontenddev/web-center.git"
def git_branch = "develop"


def mysh(cmd) {
sh('#!/bin/sh -e\n' + cmd)
}

pipeline {
agent any
// 定义Jenkins构建时加载的环境变量路径
environment{
PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/jdk1.8.0_211/bin/:/usr/local/apache-maven-3.6.3/bin/:/usr/local/node-v10.18.1/bin/"
}

parameters {
// 定义参数化构建,会调用全局变量中的内容在构建时可视化展示。
choice (choices: ["${deployment_huanjing}"], description: '部署的环境', name: 'Deployment')
choice (choices: ["${git_add}"], description: 'Git地址', name: 'git_url')
choice (choices: ["${git_branch}"], description: 'Git分支', name: 'git_fenzhi')
}

stages {
stage('1.拉取代码') {
steps {
// 配置构建流水线时拉取的代码信息
checkout([$class: 'GitSCM', branches: [[name: "*/${git_branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
}
stage('2.Maven代码编译') {
steps {
mysh '''
info="[INFO] "
project_name="admin-frontend"

echo "\${info}开始构建编译代码..."
source /etc/profile &> /dev/null
cd \${project_name}
yarn && yarn build
if [ $? -eq 0 ];then
echo "\${info}项目代码编译构建成功,开始发布代码至目标服务器..."
else
echo "\${info}项目构建失败..."
fi
'''
}
}
stage('3.发布代码') {
steps {
mysh '''
# 传送构建成功的项目至目标主机项目目录
# 目标部署主机的IP和用户名(需要提前做免密登录)
info="[INFO] "
remote_host="172.23.1.55"
remote_user="root"
remote_scp_service="admin"
remote_service_mulu="/data/web"
project_name="admin-frontend"

if [ ${Deployment} = 'dev' ]; then

scp -r ./\${project_name}/dist/\${remote_scp_service} \${remote_user}@\${remote_host}:\${remote_service_mulu}
if [ $? -eq 0 ];then
echo "\${info}\${project_name}项目部署成功,部署的服务器:\${remote_host} 部署的vhost目录:\${remote_service_mulu}"
else
echo "\${info}项目构建失败...查看Jenkins服务器日志..."
fi
fi
'''
}
}
}
}

四、分项目组看到不同视图权限

公司内部Jenkins项目太多,不同的项目组与开发测试人员要有不同项目的权限。系统自带的矩阵管理不太适合,这里使用Role-based Authorization Strategy插件,使不同的账号有不同的权限,看到不同的项目。

本次试验的目的是:dev和uat两组人员,登录自己的jenkins账号,只可以看到自己项目组的任务,并且只有read和build的权限。

1.安装Role-based Authorization Strategy插件,安装后重启jenkins。

  1. 开启插件

系统管理>>>全局安全配置>>>Role-Based Strategy

3.创建dev和uat代表不同项目组的成员

Manage Jenkins —> Manage Users —> 新建用户

4.创建权限角色并把权限角色分配给用户

5.在创建Job时不同项目按不同名称前缀来命名,例如dev组的Job名以BackEnd_dev开头

添加项目角色时,需要制定匹配项目的模式,如上图中的Pattern,官方文档介绍该选项支持正则表达式,如“Roger-.”表示所有以Roger-开头的项目,“(?i)roger-.*”表示以roger-开头的项目并且不区分大小写,*如以ABC开头的项目可以配置为“ABC**|ABC.*”,也可以使用“abc|bcd|efg”直接匹配多个项目。**

**此处一定注意:**全局角色**admin不能删除,且必须在*全局角色*中创建一个只有Overall/Read的角色,这个角色是分配给下面的项目角色使用的,否则,分配了项目角色的用户登录后会提示“ 用户名 is missing the Overall/Read permission”

6.登陆dev或者uat的用户验证权限