关于本文档 · 贡献者 · 文档协议 · 致谢
关于本文档
文档名称:《DevOps 之 Jenkins 的 CICD》
使用协议:《知识共享公共许可协议(CCPL)》
贡献者
| 贡献者名称 | 贡献 度 |
文档变更记录 | 个人主页 |
|---|---|---|---|
| 马哥(马永亮) | 主编 | http://github.com/iKubernet es/ |
|
| 王晓春 | 作者 | 302页,版本迭代升级,修订和内容丰富 | http://www.wangxiaochun.c om |
文档协议
署名要求 :使用本系列文档,您必须保留本页中的文档来源信息,具体请参考《知识共享 (Creative Commons) 署名4.0公共许可协议国际版》。
非商业化使用 :遵循《知识共享公共许可协议(CCPL)》,并且您不能将本文档用于马哥教育相关业务之外的其他任何商业用途。
您的权利 :遵循本协议后,在马哥教育相关业务之外的领域,您将有以下使用权限:
共享 — 允许以非商业性质复制本作品。
改编 — 在原基础上修改、转换或以本作品为基础进行重新编辑并用于个人非商业使用。
致谢
本文档中,部分素材参考了相关项目的文档,以及通过搜索引擎获得的内容,这里先一并向相关的贡献者表示感谢。
内容概述
- Jenkins 部署
Jenkins 基本配置
Jenkins 实现 CICD
Jenkins 分布式
Jenkins 流水线 Pipeline
代码质量检测 SonarQube
1 Jenkins 部署与基本配置
1.1 Jenkins 介绍

官方网站:
https://jenkins.io/zh/

官方文档
https://www.jenkins.io/zh/doc/
Jenkins是一个独立的开源软件项目,是基于Java开发的一种CI(Continuous integration,持续集成) &CD (Continuous Delivery,持续交付)工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。其前身是商业软件Hudson。可用于自动化各种任务,如构建,测试和部署软件。
Jenkins 作为一个可扩展的自动化服务器,可以用作简单的 CI 服务器,或者变成任何项目的持续交付中心。
Jenkins 只是一个调度平台,其本身并不能完成项目的构建部署
Jenkins 需要安装各种插件,可能还需要编写Shell,python脚本等才能调用和集成众多的组件来实现复杂的构建部署功能

主要用途:
持续、自动地构建/测试软件项目监控一些定时执行的任务
Jenkins特点:
开源免费
跨平台,支持所有的平台
-
master/slave支持分布式的build
-
web形式的可视化的管理页面
-
安装配置简单
及时快速的提示和帮助
已有的1800+插件
Jenkins 官方介绍视频
https://v.qq.com/x/page/m0509xul0xk.html
Jenkins 版本
https://www.jenkins.io/download/
https://www.jenkins.io/zh/download/
https://mirrors.tuna.tsinghua.edu.cn/jenkins/
Jenkins 项目产生两个发行线, 长期支持版本 (LTS) 和定期发布版本。

稳定版 LTS(每4周)
LTS (长期支持) 版本每12周从常规版本流中选择,作为该时间段的稳定大版本。 每隔 4 周会更新迭代稳定的小版本,其中包括错误和安全修复反向移植。
下载链接
https://get.jenkins.io/
https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/


常规版本 (每周)
每周都会发布一个新版本,为用户和插件开发人员提供错误修复和功能。

1.2 Jenkins 安装和启动
1.2.1 Jenkins 的安装
Jenkins 支持多种部署和运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序
Jenkins支持多种安装方法
-
docker
-
通用java包 war文件二进制包
https://www.jenkins.io/zh/doc/book/installing/
1.2.1.1 安装前环境准备
1.2.1.1.1 系统准备
#关闭防火墙和SELinux
略
#设置语言环境,防止后期Jenkins汉化出问题
[root@jenkins ~]# localectl set-locale LANG=en_US.UTF-8
1.2.1.1.2 JAVA 环境
jenkins基于JAVA实现,安装jenkins前需要先安装 JDK
#安装openjdk
[root@ubuntu1804 ~]#apt update
[root@ubuntu1804 ~]#apt -y install openjdk-8-jdk
[root@ubuntu1804 ~]#java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-8u242-b08-0ubuntu3~18.04-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)
#或者安装oracle的jdk
[root@ubuntu1804 /usr/local/src]# tar xvf jdk-8u192-linux-x64.tar.gz
[root@ubuntu1804 /usr/local/src]# ln -sv /usr/local/src/jdk1.8.0_192/
/usr/local/jdk
[root@ubuntu1804 /usr/local/src]# ln -sv /usr/local/jdk/bin/java /usr/bin/ #java
命令软连接
[root@ubuntu1804 /usr/local/src]# vim /etc/profile
exportJAVA_HOME=/usr/local/jdk
exportPATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export
CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
[root@ubuntu1804 /usr/local/src]# source /etc/profile
[root@ubuntu1804 /usr/local/src]# java -version
java version "1.8.0_192"
Java(TM) SE Runtime Environment (build 1.8.0_192-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.192-b12, mixed mode)
#或者安装JDK-11版
[root@ubuntu2004 ~]#apt -y install openjdk-11-jdk
[root@rocky8 ~]#yum -y install java-11-openjdk
3.2.1.2 二进制包安装 Jenkins
3.2.1.2.1 Ubuntu 二进制包安装 jenkins
Ubuntu 安装jenkins 官方说明
https://pkg.jenkins.io/debian-stable/
安装过程
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key
add -
Then add the following entry in your /etc/apt/sources.list:
deb https://pkg.jenkins.io/debian-stable binary/
Update your local package index, then finally install Jenkins:
sudo apt-get update
sudo apt-get install jenkins
deb 包下载地址国内镜像站点
https://mirrors.aliyun.com/jenkins/debian-stable/
https://mirror.tuna.tsinghua.edu.cn/jenkins/debian-stable/
范例: Ubuntu二进制包安装jenkins
[root@ubuntu1804 ~]#apt update
[root@ubuntu1804 ~]#apt -y install openjdk-8-jdk daemon
[root@ubuntu1804 ~]#wget https://mirror.tuna.tsinghua.edu.cn/jenkins/debian-
stable/jenkins_2.289.2_all.deb
[root@ubuntu1804 ~]#dpkg -i jenkins_2.289.2_all.deb
[root@ubuntu1804 ~]#systemctl status jenkins.service
● jenkins.service - LSB: Start Jenkins at boot time
Loaded: loaded (/etc/init.d/jenkins; generated)
Active: active (exited) since Mon 2021-07-2619:56:02 CST; 3min 46s ago
Docs: man:systemd-sysv-generator(8)
Process: 22197ExecStop=/etc/init.d/jenkins stop(code=exited,
status=0/SUCCESS)
Process: 22234ExecStart=/etc/init.d/jenkins start(code=exited,
status=0/SUCCESS)
Jul 2619:56:01 ubuntu1804.wang.org systemd[1]: Starting LSB: Start Jenkins at
boot time...
Jul 2619:56:01 ubuntu1804.wang.org jenkins[22234]: Correct java version found
Jul 2619:56:01 ubuntu1804.wang.org jenkins[22234]: * Starting Jenkins
Automation Server jenkins
Jul 2619:56:01 ubuntu1804.wang.org su[22270]: Successful sufor root by root
Jul 2619:56:01 ubuntu1804.wang.org su[22270]: + ??? root:root
Jul 2619:56:01 ubuntu1804.wang.org su[22270]: pam_unix(su:session): session
opened for user root by (uid=0)
Jul 2619:56:01 ubuntu1804.wang.org jenkins[22234]: mesg: ttyname failed:
Inappropriate ioctl for device
Jul 2619:56:01 ubuntu1804.wang.org su[22270]: pam_unix(su:session): session
closed for user root
Jul 2619:56:02 ubuntu1804.wang.org jenkins[22234]: ...done.
Jul 2619:56:02 ubuntu1804.wang.org systemd[1]: Started LSB: Start Jenkins at
boot time.
[root@ubuntu1804 ~]#cat /var/log/jenkins/jenkins.log
2021-07-2611:56:05.894+0000[id=28] INFO
jenkins.install.SetupWizard#init:
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password
generated.
Please use the following password to proceed to installation:
8bdf8b1805cf451084ebebd9083823b1
This may also be found at: /var/lib/jenkins/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************
2021-07-2611:56:15.715+0000[id=29] INFO
jenkins.InitReactorRunner$1#onAttained: Completed initialization
2021-07-2611:56:15.727+0000[id=20] INFO hudson.WebAppMain$3#run: Jenkins
is fully up and running
范例: Ubuntu二进制包安装jenkins 旧版
[root@ubuntu1804 ~]#wget https://pkg.jenkins.io/debian-
stable/binary/jenkins_2.204.4_all.deb
[root@ubuntu1804 ~]#apt install daemon
[root@ubuntu1804 ~]#dpkg -i jenkins_2.204.4_all.deb
[root@ubuntu1804 ~]#systemctl status jenkins
● jenkins.service - LSB: Start Jenkins at boot time
Loaded: loaded (/etc/init.d/jenkins; generated)
Active: active (exited) since Thu 2020-03-0515:41:27 CST; 34s ago
Docs: man:systemd-sysv-generator(8)
Tasks: 0 (limit: 2293)
CGroup: /system.slice/jenkins.service
Mar 0515:41:25 ubuntu1804.wang.org systemd[1]: Starting LSB: Start Jenkins at
boot time...
Mar 0515:41:25 ubuntu1804.wang.org jenkins[11662]: Correct java version found
Mar 0515:41:25 ubuntu1804.wang.org jenkins[11662]: * Starting Jenkins
Automation Server jenkins
Mar 0515:41:25 ubuntu1804.wang.org su[11693]: Successful sufor jenkins by root
Mar 0515:41:25 ubuntu1804.wang.org su[11693]: + ??? root:jenkins
Mar 0515:41:26 ubuntu1804.wang.org su[11693]: pam_unix(su:session): session
opened for user jenkins by (uid
Mar 0515:41:26 ubuntu1804.wang.org su[11693]: pam_unix(su:session): session
closed for user jenkins
Mar 0515:41:27 ubuntu1804.wang.org jenkins[11662]: ...done.
Mar 0515:41:27 ubuntu1804.wang.org systemd[1]: Started LSB: Start Jenkins at
boot time.
[root@ubuntu1804 ~]#ps aux|grep jenkins
jenkins 116940.0 0.3 766207532 ? Ss 15:41 0:00
/lib/systemd/systemd --user
jenkins 116950.0 0.1 1119802676 ? S 15:41 0:00 (sd-pam)
jenkins 117080.0 0.0 20388184 ? S 15:41 0:00
/usr/bin/daemon --name=jenkins --inherit--env=JENKINS_HOME=/var/lib/jenkins --
output=/var/log/jenkins/jenkins.log --pidfile=/var/run/jenkins/jenkins.pid --
/usr/bin/java -Djava.awt.headless=true-jar /usr/share/jenkins/jenkins.war --
webroot=/var/cache/jenkins/war --httpPort=8080
jenkins 1170928.2 11.4 2561460231920 ? Sl 15:41 0:31 /usr/bin/java
-Djava.awt.headless=true-jar /usr/share/jenkins/jenkins.war --
webroot=/var/cache/jenkins/war --httpPort=8080
root 124650.0 0.0 144281156 pts/0 S+15:43 0:00 grep--
color=auto jenkins
[root@ubuntu1804 ~]#ss -ntlp |grep java
LISTEN 050 *:8080 *:*
users:(("java",pid=11709,fd=164))
#查看日志
[root@jenkins-ubunutu1804 ~]#cat /var/log/jenkins/jenkins.log
1.2.1.2.2 CentOS 二进制包安装 jenkins
CentOS 安装jenkins官方说明
https://pkg.jenkins.io/redhat-stable/
安装过程
wget-O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-
stable/jenkins.repo
rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
yum install jenkins
rpm包国内镜像下载链接
https://mirrors.aliyun.com/jenkins/redhat-stable/
https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/
范例: CentOS二进制包安装jenkins
[root@centos8 ~]#yum install java
[root@centos8 ~]#wget https://mirrors.aliyun.com/jenkins/redhat-stable/jenkins-
2.289.2-1.1.noarch.rpm
[root@centos8 ~]#yum -y install jenkins-2.289.2-1.1.noarch.rpm
[root@centos8 ~]#rpm -ql jenkins
/etc/init.d/jenkins
/etc/logrotate.d/jenkins
/etc/sysconfig/jenkins
/usr/lib/jenkins
/usr/lib/jenkins/jenkins.war
/usr/sbin/rcjenkins
/var/cache/jenkins
/var/lib/jenkins
/var/log/jenkins
[root@centos8 ~]#systemctl start jenkins.service
#查看第一次的登录密码
[root@centos8 ~]#grep -A2 password /var/log/jenkins/jenkins.log
Jenkins initial setup is required. An admin user has been created and a password
generated.
Please use the following password to proceed to installation:
cf4cd0d45e6041a3ba0dcaec345b105a
#查看第一次的登录密码
[root@centos8 ~]#cat /var/lib/jenkins/secrets/initialAdminPassword
cf4cd0d45e6041a3ba0dcaec345b105a
#默认配置
[root@centos8 ~]#grep -v "#" /etc/sysconfig/jenkins | grep -v "^$"
JENKINS_HOME="/var/lib/jenkins"
JENKINS_JAVA_CMD=""
JENKINS_USER="jenkins"
JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true"
JENKINS_PORT="8080"
JENKINS_LISTEN_ADDRESS=""
JENKINS_HTTPS_PORT=""
JENKINS_HTTPS_KEYSTORE=""
JENKINS_HTTPS_KEYSTORE_PASSWORD=""
JENKINS_HTTPS_LISTEN_ADDRESS=""
JENKINS_HTTP2_PORT=""
JENKINS_HTTP2_LISTEN_ADDRESS=""
JENKINS_DEBUG_LEVEL="5"
JENKINS_ENABLE_ACCESS_LOG="no"
JENKINS_HANDLER_MAX="100"
JENKINS_HANDLER_IDLE="20"
JENKINS_EXTRA_LIB_FOLDER=""
JENKINS_ARGS=""
#修改配置
[root@centos8 ~]#grep -v "#" /etc/sysconfig/jenkins | grep -v "^$"
JENKINS_HOME="/var/lib/jenkins"
JENKINS_JAVA_CMD=""
JENKINS_USER="jenkins"
JENKINS_JAVA_OPTIONS="-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.101" \"
JENKINS_PORT="8080"
JENKINS_LISTEN_ADDRESS=""
JENKINS_HTTPS_PORT=""
JENKINS_HTTPS_KEYSTORE=""
JENKINS_HTTPS_KEYSTORE_PASSWORD=""
JENKINS_HTTPS_LISTEN_ADDRESS=""
JENKINS_DEBUG_LEVEL="5"
JENKINS_ENABLE_ACCESS_LOG="no"
JENKINS_HANDLER_MAX="100"
JENKINS_HANDLER_IDLE="20"
JENKINS_ARGS=""
# 可选启动参数:
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.101""
3.2.1.2.3 修改 jenkins 服务的用户
默认jenkins服务使用jenkins 帐号启动,将文件复制到生产服务器可能会遇到权限问题,因此修改为 root用户
[root@jenkins-ubunutu1804 ~]#vim /etc/default/jenkins
JENKINS_USER=root
JENKINS_GROUP=root
[root@jenkins-ubunutu1804 ~]#systemctl restart jenkins
[root@jenkins-ubunutu1804 ~]#ps aux|grep jenkins
root 1213540.0 0.0 20388188 ? S 18:22 0:00
/usr/bin/daemon --name=jenkins --inherit--env=JENKINS_HOME=/var/lib/jenkins --
output=/var/log/jenkins/jenkins.log --pidfile=/var/run/jenkins/jenkins.pid --
/usr/bin/java -Djava.awt.headless=true-jar /usr/share/jenkins/jenkins.war --
webroot=/var/cache/jenkins/war --httpPort=8080
root 1213553.2 20.0 3090932403664 ? Sl 18:22 0:29 /usr/bin/java
-Djava.awt.headless=true-jar /usr/share/jenkins/jenkins.war --
webroot=/var/cache/jenkins/war --httpPort=8080
root 1267400.0 0.0 144281040 pts/1 S+18:37 0:00 grep--
color=auto jenkins
1.2.1.2.4 一键安装 Jenkins 脚本
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-02-15
#FileName: install_jenkins.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
URL="https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/jenkins-2.289.3-
1.1.noarch.rpm"
#URL="https://mirrors.tuna.tsinghua.edu.cn/jenkins/debian-
stable/jenkins_2.289.3_all.deb"
#URL="https://mirrors.aliyun.com/jenkins/debian-stable/jenkins_2.289.3_all.deb"
GREEN="echo -e \E[32;1m"
END="\E[0m"
HOST=`hostname -I|awk '{print $1}'`
. /etc/os-release
color () {
RES_COL=60
MOVE_TO_COL="echo -en \\033[${RES_COL}G"
SETCOLOR_SUCCESS="echo -en \\033[1;32m"
SETCOLOR_FAILURE="echo -en \\033[1;31m"
SETCOLOR_WARNING="echo -en \\033[1;33m"
SETCOLOR_NORMAL="echo -en \E[0m"
echo-n"$1" && $MOVE_TO_COL
echo-n"["
if [ $2="success"-o$2="0" ] ;then
${SETCOLOR_SUCCESS}
echo-n$" OK "
elif [ $2="failure"-o$2="1" ] ;then
${SETCOLOR_FAILURE}
echo-n$"FAILED"
else
${SETCOLOR_WARNING}
echo-n$"WARNING"
fi
${SETCOLOR_NORMAL}
echo-n"]"
echo
}
install_java(){
if [ $ID="centos"-o$ID="rocky" ];then
yum -y install java-1.8.0-openjdk
else
apt update
apt -y install openjdk-8-jdk
fi
if [ $?-eq0 ];then
color "安装java完成!"0
else
color "安装java失败!"1
exit
fi
}
install_jenkins() {
wget-P /usr/local/src/ $URL || { color "下载失败!"1 ;exit ; }
if [ $ID="centos"-o$ID="rocky" ];then
yum -y install /usr/local/src/${URL##*/}
systemctl enable jenkins
systemctl start jenkins
else
apt -y install daemon net-tools || { color "安装依赖包失败!"1 ;exit ; }
dpkg -i /usr/local/src/${URL##*/}
fi
if [ $?-eq0 ];then
color "安装Jenkins完成!"0
else
color "安装Jenkins失败!"1
exit
fi
}
start_jenkins() {
systemctl is-active jenkins
if [ $?-eq0 ];then
echo
color "Jenkins安装完成!"0
echo"------------------------------------------------------------------
-"
echo-e"访问链接: \c"
${GREEN}"http://$HOST:8080/"${END}
else
color "Jenkins安装失败!"1
exit
fi
while :;do
[ -f /var/lib/jenkins/secrets/initialAdminPassword ] && { key=`cat
/var/lib/jenkins/secrets/initialAdminPassword` ; break; }
sleep1
done
echo-e"登录秘钥: \c"
${GREEN}$key${END}
}
install_java
install_jenkins
start_jenkins
1.2.1.3 基于 war 包直接部署
可以直接下载 war 包,相当于绿色软件,就可以直接使用
下载链接
https://get.jenkins.io/war-stable/
https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/
1.2.1.4 基于 Docker 部署 Jenkins
#docker run -u root \
-d-p8080:8080 \
-p50000:50000 \
-v jenkins-data:/var/jenkins_home \
-v /etc/localtime:/etc/localtime:ro \
-v /var/run/docker.sock:/var/run/docekr.sock \
--restart=always \
jenkinsci/blueocean
#jenkinsci/jenkins是没有blueocean插件的,得自己装
#jenkinsci/blueocean:带了的
#/var/run/docker.sock 表示Docker守护程序通过其监听的基于Unix的套接字。该映射允许
jenkinsci/blueocean容器与Docker守护进程通信,如果jenkinsci/blueocean容器需要实例化其他
Docker容器,则该守护进程是必需的。如果运行声明式管道,其语法包含agent部分用docker;例如,agent
{ docker {... }}此选项是必需的。
1.2.2 启动 Jenkins
启动 Jenkins 可以通过下面三种方式实现
利用 service 文件启动
-
利用 jar 命令直接启动
-
利用 tomcat 启动
1.2.2.1 通过脚本或service启动
deb或rpm包安装后,可以通过init脚本或service方式直接启动
[root@jenkins ~]#systemctl start jenkins
#查看日志
[root@jenkins ~]#tail -n1 /var/log/jenkins/jenkins.log
2020-02-1106:16:25.540+0000[id=20] INFO hudson.WebAppMain$3#run: Jenkins
is fully up and running
1.2.2.2 通过 java 命令直接启动 jenkins
#查看帮助
#java -jar jenkins.war --help
Running from: /usr/share/jenkins/jenkins.war
webroot: $user.home/.jenkins
Jenkins Automation Server Engine 2.289.2
Usage: java -jar jenkins.war [--option=value] [--option=value]
Options:
--webroot= folder where the WAR file is expanded into.
Default is ${JENKINS_HOME}/war
--pluginroot= folder where the plugin archives are expanded
into. Default is ${JENKINS_HOME}/plugins
(NOTE: this option does not change the directory
where the plugin archives are stored)
--extractedFilesFolder= folder where extracted files are to be located.
Default is the temp folder
--daemon= fork into background and run as daemon (Unix only)
#用户 java 命令直接启动jenkins
# java \
-Dcom.sun.management.jmxremote \
-Djava.rmi.server.hostname="10.0.0.101 " \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-jar jenkins-2.138.3.war &
1.2.2.3 将 jenkins.war 放在tomcat进行运行
先安装tomcat,将jenkins.war配置tomcat的应用目录即可
[root@rocky8 ~]#mkdir /home/tomcat/.jenkins -pv
mkdir: created directory '/home/tomcat'
mkdir: created directory '/home/tomcat/.jenkins'
[root@rocky8 ~]#chown -R tomcat.tomcat /home/tomcat/
[root@rocky8 ~]#systemctl restart tomcat
[root@rocky8 ~]#cat /home/tomcat/.jenkins/secrets/initialAdminPassword
dbbff06091f1436e8ada27b26b108856

1.2.3 首次登录 Jenkins页面初始化
1.2.3.1 首次登录 Jenkins 页面
用浏览器访问: http://10.0.0.101:8080/

[root@ubuntu1804 ~]#cat /var/lib/jenkins/secrets/initialAdminPassword
7d19df2dd74b48a9a48e9534456d0c92
输入文件中的密码:

1.2.3.2 选择安装 jenkins 插件
因为默认安装插件需要连接国外的网站,会很慢,所以建议 选择插件安装 ,先不安装任何插件,后续做优化配置后再安装会快很多.

选择安装推荐的插件 会安装很慢,可以选择不安装,直接点右上角的X直接完成安装过程,后续再用离线方式安装插件

离线状态

如果显示 jenkins 已离线 ,将 /var/lib/jenkins/hudson.model.UpdateCenter.xml 文件中的更新检查地址改成国内镜像地址,如清华大学地址,然后重启 jenkins 即可:
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
https://mirrors.aliyun.com/jenkins/updates/update-center.json
https://jenkins-zh.gitee.io/update-center-mirror/tsinghua/update-center.json
范例: 解决离线问题
[root@ubuntu1804 ~]#vim /var/lib/jenkins/hudson.model.UpdateCenter.xml
<?xml version='1.1'encoding='UTF-8'?>
<sites>
<site>
<id>default</id>
#修改此行为下面行 <url>https://updates.jenkins.io/update-center.json</url>
<url>https://jenkins-zh.gitee.io/update-center-mirror/tsinghua/update-
center.json</url>
</site>
</sites>
1.2.3.3 插件安装
选 无 ,不安装任何插件

如果是选择安装推荐的插件,进入下面页面,安装插件很慢,可以通过下面方法解决

为了解决插件安装慢的解决方式 ,利用清华的jenkins源通过 Nginx 进行 rewrite 或者反向代理,如下:
#此方式只支持http
#在jenkins服务器上修改/etc/hosts 指向新安装的nginx服务器:10.0.0.102
[root@jenkins-ubuntu ~]#vim /etc/hosts
10.0.0.102 updates.jenkins-ci.org updates.jenkins.io
#在另一台主机安装nginx,并修改配置
[root@ubuntu1804 ~]#apt -y install nginx
[root@ubuntu1804 ~]#vim /etc/nginx/sites-enabled/default
#加下面行
location /download/plugins {
proxy_set_header Host mirrors.tuna.tsinghua.edu.cn;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
rewrite /download/plugins(.*) /jenkins/plugins/$1 break;
proxy_pass http://mirrors.tuna.tsinghua.edu.cn;
}
[root@ubuntu1804 ~]#systemctl restart nginx
对于 https 可以将上面的update-center.json 文件中updates.jenkins.io 替换为国内镜像站点即可解决
1.2.3.4 创建 Jenkins 管理员(可选)
用户信息保存在下面目录
[root@jenkins ~]#ls /var/lib/jenkins/users/
系统默认有一个管理员帐号admin,继续即可

也可以新创建一个管理员帐号

也可以选项下面的 使用 admin 帐号继续
1.2.3.4 配置 Jenkins URL
保存完成即可
.jpg)
1.2.3.5 配置完成并登陆 jenkins
如果没有创建新管理员帐号,界面如下

如果创建新管理员,界面如下

1.2.3.6 登陆 Jenkins界面
如果没有创建管理员,直接是admin登录

如果创建新的管理员,直接用新管理员登录

1.3 Jenkins 基础配置
3.3.1 修改管理员密码


1.3.2 Jenkins 管理工具
jenkins 指供了Web 管理界面,也提供了命令行管理工具

先下载jenkins.cli.jar文件,可以执行下面操作进行管理jenkins
[root@jenkins ~]#ll -h jenkins-cli.jar
-rw-r--r--1 root root 3.4M Oct 1611:02 jenkins-cli.jar
[root@jenkins ~]#java -jar jenkins-cli.jar -s
http://admin:123456@jenkins.wang.org:8080/ -webSocket help
[root@jenkins ~]#java -jar jenkins-cli.jar -s
http://admin:123456@jenkins.wang.org:8080/ -webSocket list-jobs
[root@jenkins ~]#java -jar jenkins-cli.jar -s
http://admin:123456@jenkins.wang.org:8080/ -webSocket restart
1.3.3 Jenkins 插件管理及安装
jenkins 本身的功能有限,但是插件丰富,大大扩展了jenkins的功能,当前已有1800+的插件.
要想使用jenkins实现生产需求,就必须安装相应的插件才能实现特定的功能

1.3.3.1 插件安装目录
[root@ubuntu1804 ~]#ls /var/lib/jenkins/plugins/
ace-editor momentjs
ace-editor.jpi momentjs.jpi
ant pam-auth
antisamy-markup-formatter pam-auth.jpi
antisamy-markup-formatter.jpi pipeline-build-step
ant.jpi pipeline-build-step.jpi
apache-httpcomponents-client-4-api pipeline-github-lib
apache-httpcomponents-client-4-api.jpi pipeline-github-lib.jpi
authentication-tokens pipeline-graph-analysis
authentication-tokens.jpi pipeline-graph-analysis.jpi
bouncycastle-api pipeline-input-step
bouncycastle-api.jpi pipeline-input-step.jpi
branch-api pipeline-milestone-step
branch-api.jpi pipeline-milestone-step.jpi
build-timeout pipeline-model-api
build-timeout.jpi pipeline-model-api.jpi
.....
1.3.3.2 插件管理
插件安装过程中,如果因为某种原因导致有安装失败的插件,没有关系,可以后期再单独安装

如果因为防火墙等原因导致安装插件失败或者安装插件缓慢,可以通过下面方式配置
1.3.3.2.1 方法1: 更改 Jenkins 的镜像源为国内镜像站
修改指向国内的网址
[root@jenkins ~]#
sed-i.bak 's#updates.jenkins.io/download#mirror.tuna.tsinghua.edu.cn/jenkins#g'
/var/lib/jenkins/updates/default.json
[root@jenkins ~]#sed -i 's#www.google.com#www.baidu.com#g'
/var/lib/jenkins/updates/default.json
#注意:如果是tomcat运行war包方式需要下面路径
[root@jenkins ~]#sed -i.bak
's#https://updates.jenkins.io/download#https://mirror.tuna.tsinghua.edu.cn/jenki
ns#g' /root/.jenkins/updates/default.json
将升级站点URL替换成下面国内镜像地址


将升级站点URL替换成下面国内镜像地址,提交后再次安装插件即可
#查看镜像源
http://mirrors.jenkins-ci.org/status.html
#默认镜像源
https://updates.jenkins.io/update-center.json
#国内镜像源
https://mirror.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
https://mirrors.aliyun.com/jenkins/updates/update-center.json
查看镜像状态

修改update site 为
https://mirror.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

在浏览器地址栏输入,点击yes 重启jenkins
http://jenkins服务器:8080/restart

1.3.3.2.2 方法2: Jenkins 官网或镜像网站下载想要的插件文件,再导入到 Jenkins 中
https://plugins.jenkins.io/
.jpg)
国内镜像站点插件下载地址:
http://updates.jenkins-ci.org/download/plugins/
https://updates.jenkins.io/download/plugins/
https://mirrors.aliyun.com/jenkins/plugins/
https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/


1.3.3.2.3 方法3: 离线插件包复制至插件安装目录
可以将其它主机的已安装好的插件打包后,再将之导入到安装插件目录即可
[root@jenkins ~]#systemctl stop jenkins
[root@jenkins ~]#tar jenkins_plugins.tar.gz -C /var/lib/jenkins/plugins/
[root@jenkins ~]#chown -R jenkins.jenkins /var/lib/jenkins/plugins/
[root@jenkins ~]#systemctl start jenkins
1.3.3.3 安装中文插件
插件管理--搜索 chinese -- 选中 Location: Chinese (simplified) 进行安装


1.3.4 修改 Jenkins 的启动用户为 root
默认Jenkins以jenkins的用户身份运行,会导致权限受限,可以修改service文件设为root身份运行解决此问题
#基于 Ubuntu安装修改下面文件
[root@jenkins ~]#vim /lib/systemd/system/jenkins.service
#User=jenkins
#Group=jenkins
User=root
Group=root
[root@jenkins ~]#systemctl daemon-reload
[root@jenkins ~]#systemctl restart jenkins.service
#基于RHEL系统安装修改下面文件
[root@jenkins ~]#vim /etc/sysconfig/jenkins
#JENKINS_USER="jenkins"
JENKINS_USER="root"
1.3.5 优化配置
默认只能并行2个任务,建议根据CPU核心数,将执行者数量修改为CPU的核数
管理 jenkins -- Configure System

修改为如下

1.3.6 Jenkins 的备份还原
Jenkins的相关数据都是放在主目录中, 将主目录备份即可实现Jenkins的备份,必要时用于还原另外如果有相关脚本等,也需要进行备份
可以如下查看目录位置
管理Jenkins--- Configure System

jenkins 主目录包含以下文件和目录:
*.xml 需要备份
config-history 需要备份
fingerprints 需要备份
global-build-stats 需要备份
*.key* 需要备份
jobs jobs配置需要备份(config.xml, nextBuildNumber), builds目录
(build logs等)根据需求而定
nodes 需要备份
plugins 需要备份 *.jpi及 *.hpi,可以不备份每个插件子目录,jenkins启动后会更新
插件子目录
secrets 需要备份
updates 需要备份
userContent 用户上传内容,可以根据需要备份
users 用户缓存信息,最好备份
logs 插件logs,根据需求而定,可以不备份
monitoring 可以不备份,插件会实时生成监控数据
2 Jenkins 实现 CICD
2.1 Jenkins 实现 CICD 说明
任务中构建将程序源码转换成一个可用的目标(target)的过程,该过程可能会包括获取下载源码,解决依赖、编译和打包等环节
目标可以包括库、可执行文件及生成的脚本等,该类文件即是所谓的“制品”,它们通常应该存储于制品库,Nexus就是著名的制品库服务之一
程序员可以在本地进行构建,但基于有标准、统一构建环境的构建系统完成应用程序的构建,能有效确保制品质量
Jenkins虽然可以为构建服务器,但自身并未提供构建工具
Jenkins可以集成用户所需要的大部分主流构建工具
构建工具与源程序的编程语言及工程工具有密切关系,因而,在Jenkins服务器中具体需要安装和集成的构建工具,取决于用户的实际需要
Maven: Java SBT: Scala Babel、Browserify、Weboack、Grunt及Gulp等: javascript Gradle: Java,Groovey和Kotlin等
Jenkins 实现CICD 流程


Jenkins根据业务场景的不同,提供了多种风格的任务,默认是自由风格任务,通过安装插件,还可以支持其它风格的插件
Job的风格分类
- 自由风格freestyle: 根据内部的配置属性,实现各种场景的风格流水线 pipeline Maven 项目
2.2 创建 Freestyle 风格的任务 Job
2.2.1 Freestyle 风格任务说明

自由风格的任务提供了下面的组成
-
通用配置:当前任务的基本配置,历史记录、存储数据、认证、存储目录等
-
源码管理:指定当前任务依赖的代码仓库地址(仓库的分支)
-
构建触发器:在什么情况下,才会自动执行当前的任务
-
构建环境:构建过程中,依赖的环境变量等
-
构建:当前的代码后续操作
-
构建后动作:构建任务成功后,我们可以做的事情,发送邮件、提交代码标签、触发其他任务、等等
构建支持变量
http://jenkins-server:8080/env-vars.html/
构建状态
晴雨表主要是针对一个任务的整体执行成功比例来算的。80%成功表示太阳。
.jpg)
2.2.2 Freestyle 风格任务构建流程

新建任务
输入任务名
选择自由风格的软件项目
描述该任务的作用
设置丢弃旧的构建
丢弃旧的构建:构建后的产物,保留多久条件1:保持构建的天数:当前项目构建的产物最多保留多少天条件2:保持构建的最大个数:当前项目最多保留多少构建产物,多出的自动删除
源码管理
从gitlab等仓库下载源码
构建触发器
定义自动构建的触发器
构建
构建项目的具体过程,比如: 编译,打包,部署等
构建后操作
构建完成后可以执行的操作,比如,通知或执行其它任务
2.2.3 Jenkins 构建的环境变量
构建时,jenkins中内置很多变量,可以直接在脚本中调用

2.2.4 案例: 创建简单的 Freestyle 任务

如果没有安装相关插件,只有一种"自由风格的任务软件项目可选



查看输出信息,可以看到很多变量

重复上面过程创建多个任务,如下显示

2.3 Jenkins 结合 GitLab 实现代码下载
2.3.1 GitLab 创建项目
https://gitee.com/lbtooth/wheel_of_fortune.git
导入项目

.jpg)

2.3.2 Jenkins 安装和 Gitlab 相关的插件
只有安装GitLab相关的插件,才能让Jenkins和GitLab相连
在管理插件中搜索需要gitlab的相关插件并安装


选中下面“安装完成后重启Jenkins(空闲时),自动重启jenkins
.jpg)


2.3.2 基于 ssh key 拉取代码
实现jenkins服务器到gitlab服务器的基于密钥的验证,可以让jenkins连接到gitlab执行操作,比如拉取代码
2.3.2.1 在 Jenkins 服务器上生成 ssh key
# 在 jenkins 服务器上生成密钥对
[root@jenkins-ubunutu1804 ~]#ssh-keygen
[root@jenkins-ubunutu1804 ~]#cat .ssh/id_rsa.pub
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQC/LAA5tcFrSLye3QE9a+RH8LSYzwewJ4MBSBvVP7pImKMqg21W
ozWw56RKqiSsj9ewO8zL43yfAwOjetrKr2Ovbxw9bOaxj0r1CobpXsD5H7pS4Cq0lLJxSmFwCLroz1C9
ecGhBWBmaCbkOaJ0Q6JLTO830w7noTFYZq4/NWTGtE4xpVDDNUFTAS4j4T/0QQF6YvXIqw0EzdKKkuZL
w9Rl9f2j7D1eNJX3QyY2LSgxPsXE77PzlKeJue0FKa0JwzNeKNS01rM9ztoc0VQVhxjOgjY+rhoUtBFY
wxXQLmwtBq82dh6qVBKrCDpNIPE+XaXFZVMyZ0Ahs3vD2iIP9Xz/ root@jenkins-ubunutu1804
2.3.2.2 在 Gitlab服务器上用户中关联 Jenkins 生成的ssh 公钥key
新版界面
在GitLab中项目具有访问权限的用户帐号的profile中导入Jenkins的公钥

旧版界面

2.3.2.3 在 Jenkins服务器上测试 ssh key
测试可以不使用用户名密码后直接获取代码
先在gitlab查看项目的下载地址: git@gitlab.wang.org:testgroup/testproject.git

在jenkins服务器上执行克隆,不再需要用户和密码
[root@jenkins-ubunutu1804 ~]#git clone
git@gitlab.wang.org:testgroup/testproject.git
Cloning into 'testproject'...
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)
Receiving objects: 100% (9/9), done.
[root@jenkins-ubunutu1804 ~]#ls
testproject
[root@jenkins-ubunutu1804 ~]#tree testproject/
testproject/
├── index.html
└── README.md
0 directories, 2 files
[root@jenkins-ubunutu1804 ~]#
2.3.3 添加基于用户名和 private key 类型的凭据
虽然 Jenkins 将root用户公钥传给gitlab可以实现从GitLab服务器基于ssh key 克隆项目,但是Jenkins 无法自动获取root用户的私钥,也就无法在直接在Jenkins的项目中直接连接GitLab的仓库
还需要在Jenkins通过将Jenkins的root对应的私钥创建为Jenkins的凭证,以方便后续的连接GitLab使用
2.3.3.1 Jenkins 凭证概述
凭证就是认证到某个系统中的认证信息,用于提供对受限资源的访问;
Jenkins所支持的凭证类型如下
用户名和密码(Username with password)
-
SSH用户名和私钥日(SSH Username with private key)
-
Github App
-
Secret file: 需要保密的文本文件,保存有Token等信息
-
Secret text:Token,串需要保密的文本,例如Github的API Token等
-
Certificate
其它凭证类型还有二进制数据,或者更复杂形式的项目,例如OAuth凭证等;
凭证的作用域决定了它可用的目标范围
系统:作用于Jenkins系统自身,仅可用于系统和后台任务,且一般用于连接到agent节点之上全局:作用于Jenkins上的所有任务,以确保任务的正常执行
用户:作用于用户级别,仅生效于Jenkins中的线程代表该用户进行身份验证之时;
注意:在Jenkins内部,凭证被存放在JENKINS_ HOME目录下的secrets目录中,请务必确保该目录的访问权限进行了正确的设置
2.3.3.2 Jenkins 添加用户名和private key 类型凭据
新版界面
系统管理 -- 凭据


复制Jenkins服务器root用户之前生成的私钥
[root@jenkins-ubuntu ~]#cat .ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA7i2eeMfdhILDKU9GlNpi9CAH5OAp98wP0/77EfFvHqB7AGCi
7/5jhyT1hUUlP+CS1cw+3bkD+RzBlIh55mKrgBXGBmnea2IfZDtPsQTtiwdDDJkv
acgRdQ2rxWet3l7uFSH0wUxjTkKG8ABUSNW1gp9lGTryhsbXZOZRJfKNtjMgKrkE
WE8xO9BzGJzIAUq4INcfC71oEHaUi4WfEbSwNKCNYlN7FsZq0ypHPr4wHazhHc56
xM+GPtUNI2ZlFJawUuDQWucXBzwrUUiELsqaxVOQU5MUcDSukw8wN8lXTW7hmnuA
hleVNSBsXN0W4BsYb5aJXDjp4PQ5MpTDLAwOPwIDAQABAoIBADu+V6zmPWt6vWeE
SikWapHf4vsHO5+7oRDFOcczb3MYQCJFGznl7qM8oxVt1b0jINHeLLrDKPr4upn+
bc1bXLeBPq3nKnJ3J3al5gR6PveLt8bWOe1n0PEyn66hphxMZZ4JaXJ/Lb24tE5J
Vtr6OFBumRZuEd26zNazaxGAuQlFZ9EzzojaDAxKEgF6QJS8ZnzClH2SypAhxpjN
uRHm0UsoSi+n5ESxw1+djE6lGRzPnGg+BA35IAvRi75YZKrgCpRwLcPRLUHVgNH2
gMUk6mHAgro1w1J0jZT7rON9o0fntwvy/xIRVdm9DEGleLWGaBxCNp1AjNVCfaVz
L79rvGECgYEA/qdqvGvBOeQyQVT+fljshvKF52MDBw2ZhuTN7ZkHIMVMDP35Ln7a
VGCEdhRxBrJOEoxzFtV8zwxFRJ3U5WBodCWXNQ5O40wTLw7bF2gnFTuORdVW9VNx
GdJVEP5DmrJUb/PQsz0Ke1Nb/rvEQJnjvhkLjcjKOwX7XHPoAJQBYG8CgYEA72/o
dHugr6fgv2O3q5w8sRPDxDdStY6Dr4lHtjYbOGo2kL6EgKDcR8LBSd3NSEk1RWPU
0mRxWMvpoQ/qD4t+XX68k68nvBXv7qw9M0l0W/bT/+9s4xN8DhJS+GI8pFXKBvO0
bO/YWonoVsny0YZPzsfQWHm8G/n08H3xDxvbdzECgYEAuL1LuZWSgCUEMFEwrwhj
zyJx8gLqV1uOXUXv/sZdXXDEU0iMVSbBzSSX8/GwbWM9MEej1pTaDnqgZb76i8z8
+gWrRFo08MBnymPEnZ55e/XQqOi0RRVbn5fvDnznHnrwtqbyaJWH3SAERTCClzsM
9QPGVf2seFVGnTOYw5KbzRECgYAeQC1GSjhK+RLUG20hKWQhmzWonLS+a3sHunhs
9PkLb5/lOazT837hMiHpizRcZaNtWOeSjU4kwd6KktAnlqAof9KjdgW3Ja5ioTA6
QpWI6O5v73f6WIPb40TITOEMgio8Jp4tBUB4b+QC0xDyl92NaoFQLFEv16yylbbX
CdX4gQKBgD942GNAMqxKC1qm3vASQpVlQ02ryFiM6QVg+iXWhYKDxDEuwxQPrcTH
EiZQFSOlfdWgUCBedraR7+X5/m2AWEuPXRtBdAVtnwNduVtOmd2EDo9jzKrRrnxm
Gg9L37fInHSrPQ6g9VPVDNT7Hl/5fmd3Hdgk3umaJ2L5xr2QqFdr
-----END RSA PRIVATE KEY-----


旧版界面
Jenkins-凭据-jenkins—全局凭据—添加凭据


复制root的私钥
[root@jenkins-ubunutu1804 ~]#cat .ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAvywAObXBa0i8nt0BPWvkR/C0mM8HsCeDAUgb1T+6SJijKoNt
VqM1sOekSqokrI/XsDvMy+N8nwMDo3rayq9jr28cPWzmsY9K9QqG6V7A+R+6UuAq
tJSycUphcAi66M9QvXnBoQVgZmgm5DmidEOiS0zvN9MO56ExWGauPzVkxrROMaVQ
wzVBUwEuI+E/9EEBemL1yKsNBM3SipLmS8PUZfX9o+w9XjSV90MmNi0oMT7FxO+z
85SnibntBSmtCcMzXijUtNazPc7aHNFUFYcYzoI2Pq4aFLQRWMMV0C5sLQavNnYe
qlQSqwg6TSDxPl2lxWVTMmdAIbN7w9oiD/V8/wIDAQABAoIBAQCCFLyqiCRujfXa
22Mmmi2hTgZ1HBqNILWhv6FAv7ZQA5yzJu7VTwUPtO8z5wZBbTdEscwuyEJaKMDn
Eoeh9yoLi71ZhqqLE4fbqSgXz+PbIF22WtZ0PeIV+JjIlQgptjeoVhsNKA1qYWBl
V1pVZlgeiOEVyUWREzvyfRv/4qMKGSOs9zHbsvSD7eqh8tq7P4jS4fNz6OM8JfqF
GLsbQUX8AlNxTraR9nv/hQx5KhUb5jqFV2yr3FK4IVziL91aM6nheH2DADj5th99
6u5+/zueRP30RX0F1Y6ny7FOxAe2ZIkQnGg/RlYxxdV3BZhnNiwjJ520gyC59RsD
bYaDdBwhAoGBAPSlJUcOiE+RJcQT5yeReHqOqaBoG4hw6fZyMfzX/cTHuE8iJvYB
78h7Nuw4z0TsSlpQdDgF3X5hbJn/VG10rxbbYIxFPO4b7X0WjEIS/QmxBIBChORj
3mhzSGf1DAuHE+chovNb5bjIxVArX+2TZHYieWaOC2YEEFgrpSv2b3CXAoGBAMgL
fZN//pBstXQk0Yz3kZx6++aJcZ0kUZVUU7rrGOo3SSeaXOEgYDtcd86Uj8jCTPYs
4od+kfUzn0ixMCYjpfhca8WexIPrJ2Gd5toVqEZDV3QkwyT6T+BGVYHy2NwPGtH4
wYdjhNuNwiTap79EzCMOg85x/yrVw883BofxHfvZAoGBAPK1LGh0WHNnsqn2fOta
fMZJ5qtG3ZndO5/N5x3LQu4InieT4EdL4JFq/DAapDbinVlAXCyAVR/ek5msIBx/
GH16oyxGPI6VkmT5C6k5oWQOBEMiuyjCk5HYXUsVZx/AoNQ7IKiC0UMjm+1POto9
0fsJdJtz7IcHHRf8JN+amzB9AoGAbuJnpiXxjk6juhBak1/7N5i4Ho6bCnbCPhrz
Go4MTm98vlYDG8rdbKoRwtF4bdi93kr8+gv/jcIijaGhxdJGwkdAeddKqLDlMGfd
OY99qgzT4g4qmUmikveJmDFrYXeB71eKtqhEUYrfTZxiFVRmLxxxlTJ9NVouYqLm
nN3bN+kCgYAm+ffg75HKTyZFTBm3u/SGegeyZ1rAiiuIfn220Dt1Y8NwDoPhNTo0
AQ8lNCEQxC4KKok2a4GJViKaVHeTWYOGvOXKZHG3Gs+caQq0jUGmLJC5CBiRm4n5
TpOBqfsMBe3SjDSwaCfEsHU4zoTTWb67dRhf1pVsGD24vj3m2Hbhgw==
-----END RSA PRIVATE KEY-----
添加私钥

2.3.4 添加基于用户名和密码类型的凭据
如果基于http协议则无需实现ssh key 凭证,而选择添加gitlab用户名和密码的形式

2.3.5 Jenkins 任务中使用凭据
2.3.5.1 创建 Jenkins 任务

2.3.5.2 使用凭据
2.3.5.2.1 使用基于 Ssh Key 的凭据
注意: URL 使用 git 协议

2.3.5.2.2 使用基于用户和密码的凭据
注意: URL 使用 http 协议

2.3.6 执行任务验证

查看Jenkins工作目录下代码是否拉取成功
[root@jenkins ~]#ls /var/lib/jenkins/workspace/wheel-gitlab/
images index.html js
2.4 配置 Jenkins 结合 GitLab 实现自动化部署和回滚
2.4.1 Jenkins 创建任务

2.4.2 配置 Git 项目地址和凭证
先确认安装gitlab插件

先在gitlab上确认git地址和分支名称

按上面的信息填定Git路径等信息

添加完成的证书没有报错表示认证通过
2.4.3 准备脚本并加入构建任务
[root@jenkins ~]#cat /data/jenkins-scripts/wheel-html-gitlab-deploy-rollback.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2022-07-22
#FileName: wheel-html.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2022 All rights reserved
#********************************************************************
HOST_LIST="
10.0.0.102
10.0.0.103
"
APP=wheel
APP_PATH=/data/html
DATA_PATH=/opt
DATE=`date +%F_%H-%M-%S`
deploy () {
for i in${HOST_LIST};do
ssh$i"rm -f ${APP_PATH} && mkdir -pv ${DATA_PATH}/${APP}-${DATE}"
scp -r * $i:${DATA_PATH}/${APP}-${DATE}
ssh$i"ln -sv ${DATA_PATH}/${APP}-${DATE}${APP_PATH}"
done
}
rollback() {
for i in${HOST_LIST};do
CURRENT_VERISION=$(ssh $i "readlink /data/html")
CURRENT_VERISION=$(basename ${CURRENT_VERISION})
echo${CURRENT_VERISION}
PRE_VERSION=$(ssh $i "ls -1 ${DATA_PATH} | grep -B1
${CURRENT_VERISION}|head -n1 ")
echo$PRE_VERSION
ssh$i"rm -f ${APP_PATH}&& ln -sv ${DATA_PATH}/${PRE_VERSION}
${APP_PATH}"
done
}
case $1in
deploy)
deploy
;;
rollback)
rollback
;;
*)
exit
;;
esac
在Jenkins中引用脚本

2.4.4 实现部署任务
立即构建

2.4.4.2 验证构建结果

2.4.4.1 服务器验证数据
[root@ubuntu2004 ~]#ls /data/html
images index.html js
[root@ubuntu2004 ~]#ll /opt/
total 12
drwxr-xr-x 3 root root 4096 Jul 2611:33 ./
drwxr-xr-x 21 root root 4096 Jul 2114:34 ../
drwxr-xr-x 4 root root 4096 Jul 2611:33 wheel-2022-07-26_11-33-22/
2.4.4.2 将代码部署至后端 Web 服务器
先和后端 Web服务器实现基于key验证
#并在后端服务器安装nginx服务
[root@ubuntu2004 ~]#apt -y install nginx
[root@ubuntu2004 ~]#vim /etc/nginx/sites-enabled/default
#root /var/www/html; #注释此行
root /data/html; #加下面行
[root@ubuntu2004 ~]#systemctl restart nginx
2.4.4.3 访问 Web 服务

2.4.4.4 修改代码再上传重新构建
git clone git@gitlab.wang.org:dev/wheel_of_fortune.git
cd wheel_of_fortune/
vi index.html
git add .;git commit -m '500w';git push
重新执行任务,可以看到如下修改后的显示

2.4.5 实现版本回滚任务
新建任务如下,实现回滚功能
.jpg)
只修改构建的shell部分,基它不变

执行任务后,可以查看到 Web页面是否还原为上一个版本

2.5 参数化构建
jenkins支持参数化构建,类似于脚本中的参数,可以实现灵活的构建任务
2.5.1 参数类型说明
Jenkins 支持多种参数类型,比如:Boolean,Choice选项,Multi_line字符串,字符串,文件类型等
2.5.1.1 创建包含各种类型参数的任务




2.5.1.2 构建

2.5.1.3 执行结果

[root@jenkins test-parameter]#pwd
/var/lib/jenkins/workspace/test-parameter
[root@jenkins test-parameter]#ls
test.txt
[root@jenkins test-parameter]#cat test.txt
upload[root@jenkins test-parameter]#
2.5.2 字符参数实现实现不同分支的部署



范例:脚本
[root@jenkins ~]#cat /data/jenkins/scripts/hello_world_war_job1.sh
#!/bin/bash
DATE=`date +%F-%s`
HOST_LIST="
10.0.0.8
10.0.0.18
"
tar -C$WORKSPACE/src/main/webapp/ -cf hello.tar .
for host in$HOST_LIST;do
scp hello.tar $host:/data/tomcat/appdir/hello-${DATE}.tar
ssh$host"systemctl stop tomcat && \
mkdir /data/tomcat/webdir/hello-${DATE} && \
tar xf /data/tomcat/appdir/hello-${DATE}.tar -C
/data/tomcat/webdir/hello-${DATE} && \
rm -f /usr/local/tomcat/webapps/hello && \
ln -s /data/tomcat/webdir/hello-${DATE}
/usr/local/tomcat/webapps/hello && \
systemctl start tomcat"
done

2.5.3 选项参数实现实现不同分支的部署
创建新分支


确认分支创建成功

准备脚本
[root@jenkins-ubuntu ~]#mkdir /data/git/scripts/ -pv
[root@jenkins-ubuntu ~]#cat /data/git/scripts/deploy.sh
#!/bin/bash
BRANCH=$1
cd /data/git && rm-rf testproject
git clone -b$BRANCHgit@10.0.0.100:testgroup/testproject.git
cd testproject
case $BRANCHin
main)
scp -r * 10.0.0.102:/var/www/html/
;;
devel)
scp -r * 10.0.0.103:/var/www/html/
;;
*)
echo$BRANCH is error
;;
esac
[root@jenkins-ubuntu ~]#chmod +x /data/git/scripts/deploy.sh
修改原有构建


修改不同分支的代码
[root@ubuntu1804 testproject]#pwd
/data/testproject
[root@ubuntu1804 testproject]#git branch
devel
* main
[root@ubuntu1804 testproject]#vim index.html
<h1> index.html v1</h1>
<h1> index.html v2</h1>
<h1> index.html v3</h1>
<h1> index.html v4</h1>
[root@ubuntu1804 testproject]#git add .
[root@ubuntu1804 testproject]#git commit -m v4
[root@ubuntu1804 testproject]#git push
#切换至devel分支进行修改代码
[root@ubuntu1804 testproject]#git checkout devel
Switched to branch 'devel'
Your branch is up to date with 'origin/devel'.
[root@ubuntu1804 testproject]#git branch
* devel
main
[root@ubuntu1804 testproject]#vim index.html
<h1> index.html v1</h1>
<h1> index.html v2</h1>
<h1> index.html v3</h1>
<h1> index.html v4-devel <h1>
[root@ubuntu1804 testproject]#git add .
[root@ubuntu1804 testproject]#git commit -m v4-devel
[root@ubuntu1804 testproject]#git push
执行修改过的构建



执行devel分支的构建

验证结果
2.5.4 选项参数实现不同分支的部署和回滚

范例: 脚本
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-03-02
#FileName: jenkins_deploy_rollback_branch
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
PROJECT="testproject"
#PROJECT=$JOB_NAME
PROJECT_DIR="/data"
#保存web压缩包
APPDIR="/data/tomcat/appdir"
#保存解压后的web目录
WEBDIR="/data/tomcat/webdir"
#tomcat工作目录,存放上面目录中子目录的软链接
WEBAPPS="/data/tomcat/webapps"
#tomcat服务器列表
HOSTS="
10.0.0.8
"
DATE=`date +%F_%H-%M-%S`
pull_code(){
rm-rf$WORKSPACE
#rm -rf /var/lib/jenkins/workspace/$JOB_NAME
cd${JENKINS_HOME}/workspace
#cd /var/lib/jenkins/workspace/
git clone -b$BRANCHgit@gitlab.wang.org:testgroup/$PROJECT.git
cd${$WORKSPACE} && \
tar zcf ${PROJECT_DIR}/${PROJECT}-${DATE}.tar.gz ./*
}
push_code_webservers () {
for host in$HOSTS;do
scp ${PROJECT_DIR}/${PROJECT}-${DATE}.tar.gz $host:${APPDIR}
ssh$host"mkdir $WEBDIR/${PROJECT}-${DATE} && \
tar xf ${APPDIR}/${PROJECT}-${DATE}.tar.gz -C
$WEBDIR/${PROJECT}-${DATE} && \
systemctl stop tomcat && \
rm -f ${WEBAPPS}/ROOT && \
ln -s ${WEBDIR}/${PROJECT}-${DATE}${WEBAPPS}/ROOT && \
chown -R tomcat.tomcat $WEBAPPS && \
systemctl start tomcat"
done
}
deploy (){
pull_code
push_code_webservers
}
rollback (){
local current_version previous_version
for host in$HOSTS;do
current_version=$(ssh $host "readlink /data/tomcat/webapps/ROOT")
current_version=`basename $current_version`
previous_version=`ssh $host "ls /data/tomcat/webdir/ | grep -B1
$current_version |head -n1"`
echo$current_version
echo$before_version
ssh$host"systemctl stop tomcat && \
rm -f ${WEBAPPS}/ROOT && \
ln -s ${WEBDIR}/$previous_version${WEBAPPS}/ROOT && \
systemctl start tomcat"
done
}
case $OPSin
deploy)
deploy
;;
rollback)
rollback
;;
*)
echo"Usage: `basename $0` deploy|rollback"
esac
2.6 利用 Git Parameter 插件实现拉取指定版本 2.6.1 利用 Git Parameter 插件实现拉取指定 Tag**
创建多个tag,并同步到仓库
#git tag v1.0
#git push origin --tags
2.6.1.1 安装Git Parameter 插件

2.6.1.2 创建任务



2.6.1.3 准备Shell 脚本
[root@jenkins ~]#cat /data/ansible/scripts/hello_world_war_job1.sh
#!/bin/bash
DATE=`date +%F-%s`
HOST_LIST="
10.0.0.8
10.0.0.18
"
tar -C$WORKSPACE/src/main/webapp/ -cf hello.tar .
for host in$HOST_LIST;do
scp hello.tar $host:/data/tomcat/appdir/hello-${DATE}.tar
ssh$host"systemctl stop tomcat && \
mkdir /data/tomcat/webdir/hello-${DATE} && \
tar xf /data/tomcat/appdir/hello-${DATE}.tar -C
/data/tomcat/webdir/hello-${DATE} && \
rm -f /usr/local/tomcat/webapps/hello && \
ln -s /data/tomcat/webdir/hello-${DATE}
/usr/local/tomcat/webapps/hello && \
systemctl start tomcat"
done
2.6.1.4 执行构建并验证结果

2.6.2 利用 Git Parameter 插件实现拉取指定 Commit_ID
基于 git 提交的指定的 commit id 拉取代码
2.6.2.1 安装Git Parameter 插件


2.6.2.2 创建任务


2.6.2.3 执行构建
2.6.2.4 验证结果


2.7 实现 Java 应用源码编译并部署
java 程序需要使用构建工具,如: maven,ant,gradle等进行构建打包才能部署,其中maven比较流行以下以 maven 为例实现 Java 应用部署
部署环境如下

web服务为tomcat服务器,目录结构规划如下
/data/tomcat/appdir #保存web压缩包
/data/tomcat/webdir #保存解压后的web目录
/data/tomcat/webapps #tomcat工作目录,存放上面目录中子目录的软链接
2.7.1 Gitlab仓库中准备 Java 代码
在gitlab新建 java 项目
https://gitee.com/lbtooth/hello-world-war.git
导入项目


或者新建项目

[root@gitlab data]#git clone -b main https://gitee.com/lbtooth/hello-world-
war.git
[root@gitlab data]#cd hello-world-war/
[root@gitlab hello-world-war]#git config --global user.name "wangxiaochun"
[root@gitlab hello-world-war]#git config --global user.email "29308620@qq.com"
[root@gitlab hello-world-war]#git branch
* main
[root@gitlab hello-world-war]#git remote -v
origin https://gitee.com/lbtooth/hello-world-war.git (fetch)
origin https://gitee.com/lbtooth/hello-world-war.git (push)
[root@gitlab hello-world-war]#git remote remove origin
[root@gitlab hello-world-war]#git remote add origin
git@gitlab.wang.org:testgroup/hello-world-war.git
[root@gitlab hello-world-war]#git remote -v
origin git@gitlab.wang.org:testgroup/hello-world-war.git (fetch)
origin git@gitlab.wang.org:testgroup/hello-world-war.git (push)
[root@gitlab hello-world-war]#git push
[root@gitlab hello-world-war]#git push --set-upstream origin main
#或者推送所有分支和标签
[root@gitlab hello-world-war]#git push -u origin --all
[root@gitlab hello-world-war]#git push -u origin --tags
2.7.2 安装 tomcat 服务器和配置
部署java应用至tomcat服务器,并需要提前创建用户和授权
#安装tomcat
参考tomcat章节,略
#配置远程连接权限
[root@centos8 ~]#vim /usr/local/tomcat/webapps/manager/META-INF/context.xml
#注释下面行
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->
#创建用户和授权
[root@centos8 ~]#vim /usr/local/tomcat/conf/tomcat-users.xml
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="tomcat"password="tomcat"roles="manager-gui,manager-script"/>
#加上面三行
</tomcat-users>
[root@centos8 ~]#systemctl restart tomcat
#添加名称解析
[root@jenkins ~]#vim /etc/hosts
10.0.0.8 web01.wang.org
10.0.0.18 web02.wang.org
范例: Ubuntu2004 apt 安装tomat9和配置
[root@ubuntu2004 ~]#apt -y install tomcat9 tomcat9-admin
[root@ubuntu2004 ~]#java -version
openjdk version "11.0.15"2022-04-19
OpenJDK Runtime Environment (build 11.0.15+10-Ubuntu-0ubuntu0.20.04.1)
OpenJDK 64-Bit Server VM (build 11.0.15+10-Ubuntu-0ubuntu0.20.04.1, mixed mode,
sharing)
[root@ubuntu2004 ~]#cp -a /usr/share/tomcat9-admin/* /var/lib/tomcat9/webapps/
#配置远程连接权限
[root@ubuntu2004 ~]#vim /var/lib/tomcat9/webapps/manager/META-INF/context.xml
#注释下面行
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->
#创建用户和授权
[root@ubuntu2004 ~]#vim /var/lib/tomcat9/conf/tomcat-users.xml
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="tomcat"password="tomcat"roles="manager-gui,manager-script"/>
#加上面三行
</tomcat-users>
[root@ubuntu2004 ~]#systemctl restart tomcat
2.7.3 Jenkins 安装 Maven 和 Tomcat 插件
Maven 插件实现Maven风格的任务

Deploy to container 插件实现连接 tomcat

2.7.4 Jenkins 服务器上安装 maven 和配置镜像加速
[root@jenkins ~]#apt install maven -y
#镜像加速
[root@jenkins ~]#vim /etc/maven/settings.xml
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
#查看相关变量值
[root@jenkins ~]#mvn --version
Apache Maven 3.6.0
Maven home: /usr/share/maven
Java version: 1.8.0_292, vendor: Private Build, runtime: /usr/lib/jvm/java-8-
openjdk-amd64/jre
Default locale: en_HK, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-112-generic", arch: "amd64", family: "unix"
2.7.5 Jenkins 全局工具配置 JDK 和 Maven
参考上一步的信息,填写全局工具配置


2.7.6 创建 Tomcat 的全局凭据
根据tomcat的用户权限配置,创建jenkins连接tomcat的用户和权限



2.7.7 创建 Maven 风格的任务


输入maven的编译选项
clean package -Dmaven.test.skip=true


2.7.8 构建验证



2.8 实现 Golang 应用源码编译并部署
2.8.1 安装 Golang 环境
#基于仓库安装
[root@ubuntu2004 ~]#apt -y install golang
[root@ubuntu2004 ~]#go version
go version go1.13.8 linux/amd64
#或者从官网下载指定版本
2.8.2 准备 Golang 源代码
下载: https://gitee.com/lbtooth/http_demo_go.git
[root@ubuntu2004 ~]#mkdir /data/ ; cd /data
[root@ubuntu2004 data]#git clone https://gitee.com/lbtooth/http_demo_go.git
https://gitee.com/lbtooth/ http_server_demo.git
[root@ubuntu2004 data]#cd http_server_demo
[root@ubuntu2004 http_demo_go]#pwd
/data/http_demo_go
[root@ubuntu2004 http_demo_go]#ls
go.mod hello.html main.go
2.8.3 Gitlab 创建项目


2.8.4 将源码上传到 GitLab
2.8.4.1 生成ssh密钥并上传到GitLab
[root@ubuntu2004 ~]#ssh-keygen
[root@ubuntu2004 ~]#cat .ssh/id_rsa.pub
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABgQDX28R1iOKyGgZmD+OGXRJ//2zxqxYvw8vftHxeQlL8rzNzMV0k
d5CoklpDdS+Xeds+IssV/jApwLKJIqWZoQ/RCYTCPpAVLsSknO9o4yiovGcRHe9NzEYcqnK7LSjwuIvx
JMu6T3TpBDp/EARN16WFeqKRDtUnSDu+U1PLawSUN9Ye7OQv+oADmrAvX8TuOmGRy9QqjflWIzvfJw3B
rDAfP0EAwHYCNUPZbDtfIn1kJvaNTTOjWdqH2TqBmabVnTawN8B+nqwosUJp5h/4Y+B9qdRTlpmzdZtg
ZUiHf2vy/LkVeoNd6i892AxepFnSwMZooUW7ByMA6uKuZRPDrwz0Lo9zQNt4BE5MoikuaqHvfsw408B4
wF9e/l3o2lOu+MQ9im544G4C7Tudo669b/Jva4fzu40L/EORohXOx1r4kzC5i2yywo2SQPB/nZSU/2u6
7TFsMDv+5Fi4vVO0P/Zpl0PEJEcmo87/CnhVqnh00FknXtVJyIAilH2Te+oVojk=
root@ubuntu2004.magedu.org
将 ssh 的公钥上传到 GitLab

2.8.4.2 上传代码到 GitLab
[root@ubuntu2004 http_demo_go]#git init
[root@ubuntu2004 http_demo_go]#git config --global user.name "wang"
[root@ubuntu2004 http_demo_go]#git config --global user.email "wang@qq.com"
[root@ubuntu2004 http_demo_go]#git checkout -b main
[root@ubuntu2004 http_demo_go]#git add .; git commit -m 'v1.0'
[root@ubuntu2004 http_demo_go]#git remote add origin
git@gitlab.wang.org:dev/http_demo_go.git
[root@ubuntu2004 http_demo_go]#git push -u origin --all

2.8.5 编写 Shell 脚本
范例: http_demo项目
[root@jenkins ~]#cat /data/scripts/http_hello_go.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2021-07-21
#FileName: http_hello_go.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2021 All rights reserved
#********************************************************************
APP=http_server_demo
APP_PATH=/data
DATE=`date +%F_%H-%M-%S`
HOST_LIST="
10.0.0.102
10.0.0.103
"
build () {
#cd ${WORKSPACE}
go build -o${APP}
}
deloy () {
for host in$HOST_LIST;do
ssh$host"mkdir -p $APP_PATH/${APP}-${DATE}"
scp -r hello.html ${APP}$host:$APP_PATH/${APP}-${DATE}/
ssh$host"killall -0 ${APP} &>/dev/null && killall -9 $APP;rm -f
${APP_PATH}/${APP} && \
ln -s ${APP_PATH}/${APP}-${DATE}${APP_PATH}/${APP}; \
cd ${APP_PATH}/${APP}/ && ./${APP}" &
done
}
build
deloy
范例: ginweb 项目
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2022-07-25
#FileName: ginweb.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2022 All rights reserved
#********************************************************************
APP=ginweb
APP_PATH=/data
DATE=`date +%F_%H-%M-%S`
HOST_LIST="
10.0.0.102
"
build () {
CGO_ENABLED=0 go build -o ${APP}
}
deloy () {
for host in $HOST_LIST;do
ssh $host "mkdir -p $APP_PATH/${APP}-${DATE}"
scp -r * $host:$APP_PATH/${APP}-${DATE}/
ssh $host "killall -0 ${APP} &> /dev/null && killall -9 ${APP}; rm -f
${APP_PATH}/${APP} && \
ln -s ${APP_PATH}/${APP}-${DATE} ${APP_PATH}/${APP}; \
cd ${APP_PATH}/${APP}/ && nohup ./${APP}&>/dev/null" &
done
}
build
deloy
2.8.6 创建 Jenkins 任务


2.8.7 执行任务


2.8.8 验证服务
访问服务器的链接,验证是否能正常访问
http://10.0.0.102:9999/hello
http://10.0.0.102:9999/world
http://10.0.0.102:9999/info

2.9 集成 Ansible 的任务构建

官方参考
https://plugins.jenkins.io/ansible/
2.9.1 安装 Ansible 环境
root@jenkins ~]#apt -y install ansible -y
[root@jenkins ~]#ansible --version
ansible 2.9.6
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules',
'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
executable location = /usr/bin/ansible
python version =3.8.10 (default, Jun 222022, 20:18:18) [GCC 9.4.0]
2.9.2 安装 Ansible 插件
安装ansible插件

安装插件后,添加了ansible的构建步骤


2.9.3 使用 Ansible Ad-Hoc 实现任务

2.9.4 使用 Ansible Playbook 实现任务
2.9.4.1 准备 Playbook文件
[root@jenkins ~]#cat /data/ansible/test.yml
- hosts: webservers
remote_user: root
tasks:
- name: excute cmd
shell:
cmd: hostname -I
register: result
- name: show result
debug:
msg: "{{ result }}"
2.9.4.2 创建任务

2.9.5 使用 Ansible Playbook 实现参数化任务
上面的任务是固定的,不灵活,利用参数在同一个任务就可以灵活实现测试和生产多套不同环境的部署
2.9.5.1 准备Playbook文件
[root@jenkins ~]#cat /data/ansible/test.yml
- hosts: webservers
remote_user: root
tasks:
- name: excute cmd
shell:
cmd: hostname -I
register: result
- name: show result
debug:
msg: "{{ result }}"
2.9.5.2 准备两个主机清单文件
[root@jenkins ~]#cat /etc/ansible/hosts_test
[webservers]
10.0.0.102
[root@jenkins ~]#cat /etc/ansible/hosts_product
[webservers]
10.0.0.103
2.9.5.3 创建参数化任务


2.9.5.4 执行任务

2.9.6 使用 Ansible Playbook 实现向 Playbook 中传参功能
2.9.6.1 编写Playbook文件
[root@jenkins ~]#cat /data/ansible/test-vars.yml
- hosts: "{{ ansible_hosts }}"
remote_user: root
tasks:
- name: excute cmd
shell:
cmd: hostname -I
register: result
- name: show result
debug:
msg: "{{ result }}"
2.9.6.2 创建主机清单文件
[root@jenkins ~]#cat /etc/ansible/hosts-test
[webservers]
10.0.0.104
[appservers]
10.0.0.106
[root@jenkins ~]#cat /etc/ansible/hosts-product
[webservers]
10.0.0.105
[appservers]
10.0.0.107
2.9.6.3 创建 Ansible Playbook 的任务
创建任务
添加第一个参数选项

添加第二个参数选项


点"高级"添加ansible的变量,添加Ansible Playbook的变量

注意: 此处的Extra Variables 指的是ansible的变量,key为ansible Playbook的变量名,Value可以是固定值,或者是任务中的变量(需要用${变量名}形式)
如下配置相当于: ansible-playbook -e "ansible_hosts=${hosts_list}"


2.9.6.4 执行构建

2.9.6.5 查看结果

2.10 构建后通知
Jenkins通知:将任务的执行状态、事件或信息推送给相关用户,这些通常发生在pipeline的“构建后处理 (post-processing)”时期
Email是Jenkins内置支持的通知方式,它也能够通过webhook扩展支持其它的即时通信媒介,例如:钉钉,Slack等;
2.10.1 邮件通知
2.10.1.1 生成邮箱登录授权码
可以使用QQ或163邮箱等


2.10.1.2 配置 Jenkins管理员邮箱 注意:必须指定 系统管理员邮件地址 才能实现邮件通知
Jenkins—系统管理—系统设置:
注意:系统管理员邮件地址,必须和下面SMTP的用户名相同

2.10.1.3 安装 mailer 插件
先安装mailer插件后才可以显示和配置发件配置信息

2.10.1.4 配置发送邮件的邮件通知
Jenkins—系统管理—系统设置:
注意:必须安装插件才能出现下面的SMTP配置
配置邮件通知信息如下:
-
用户名必须要和上面的系统管理员邮件地址相同用户默认邮件后缀可为空
-
启用"使用SSL协议"
-
SMTP 端口可以为空,默认为465
-
Reply-To Address 可以为空

测试配置,确认能否收到邮件

2.10.1.5 配置任务的构建后通知

2.10.1.6 执行任务验证结果
注意:当任务执行失败时才会收邮件


2.10.1.7 在 Pipeline 中也可以添加邮件通知
范例:
pipeline {
agent any
stages {
stage('Source') {
steps {
git branch: 'main', credentialsId: '95b957c7-d786-46c9-9d76-
b767121d1c85', url: 'git@10.0.0.100:testgroup/spring-boot-helloworld.git'
}
}
stage('Build') {
steps {
sh'mvn clean package -Dmaven.test.skip=true'
}
}
stage('Test') {
steps {
echo"Test"
}
}
stage('Deploy') {
steps {
echo"Deploy"
}
}
}
post {
always {
mail to:"29308620@qq.com",
subject:"Status of pipeline: ${currentBuild.fullDisplayName}",
body:"${env.BUILD_URL} has result ${currentBuild.result}"
}
}
}
2.10.2 钉钉通知
2.10.2.1 钉钉配置群聊机器人
注册钉钉,创建群聊

指定群类型---内部项目群

选择归属企业和添加相关人员到群里


指定群助手

添加机器人

指定机器人类型为webhook




#复制加签内容如下
SEC9f06df8a086c4efdb58cb7753e836fcfb638fb0297a57bc2f5d9232a3fc86bc9

#复制Webhook信息如下
https://oapi.dingtalk.com/robot/send?
access_token=3ca57ace4ed34f0803599637c5cd932eb3491a16ef7ace06b99a6e3e465609f5

2.10.2.2 Jenkins 安装插件

2.10.2.3 Jenkins 系统配置 管理 Jenkins --- configure system


测试查看钉钉收到消息
2.10.2.4 配置任务实现钉钉通知
手机号支持多个,每个手机号一行,也可选 atall 即所有群里的人员(不必再输入手机号)
自定义内容可以如下:
-
构建 ID: ${BUILD_ID} -
部署项目 : ${JOB_NAME} -
部署目录 : ${WORKSPACE}


安装插件后有时会出现以下问题无法正常显示

2.10.2.5 执行任务验证钉钉通知
如果任务成功,显示下面提示
注意: 如果不成功,重启 jenkins服务,再尝试执行构建

如果失败,显示下面提示

2.10.2.6 Pipeline 实现钉钉通知
官方说明
https://jenkinsci.github.io/dingtalk-plugin/guide/pipeline.html
范例: pipeline实现钉钉通知
pipeline {
agent any
stages {
stage('Source') {
steps {
git branch: 'main', credentialsId: '95b957c7-d786-46c9-9d76-
b767121d1c85', url: 'git@10.0.0.100:testgroup/spring-boot-helloworld.git'
}
}
stage('Build') {
steps {
sh'mvn clean package -Dmaven.test.skip=true'
}
}
stage('Test') {
steps {
echo"Test"
}
}
stage('Deploy') {
steps {
echo"Deploy"
}
}
}
post {
unsuccessful {
dingtalk(
robot: 'dingtalk' ,type: 'TEXT',
type: "MARKDOWN"
text: [
"# ${JOB_NAME}有问题",
"- Status of pipeline: ${currentBuild.fullDisplayName}" ,
"- ${env.BUILD_URL} has result ${currentBuild.result}"
],
at: [
'wangxiaochun'
]
)
}
success {
mail to:"29308620@qq.com",
subject:"Status of pipeline: ${currentBuild.fullDisplayName}",
body:"${env.BUILD_URL} has result ${currentBuild.result}"
}
}
}
2.11 自动化构建
2.11.1 定时和 SCM 构建
周期性构建这是—-种基于 cron 类型的构建机制.按照预定义的时间周期性启动作务
对于期望能够基于代码变更进行触的CI场景来说,周期性构建并非其最佳选项,但对于有些类型的住务, 它却也能够通过精心编排的周期性构建来避免资源冲突;
周期性构建分为定时构建和轮询构建

定时构建: 按时间周期性的触发构建
- 轮询SCM(Source Code Management): 指的是定期到代码仓库检查代码是否有变更,存在代码变更时就运行pipeline;为了能够从CI中得到更多的收益,轮询操作越频繁越好;显然,这会给SCM带去无谓的压力,所以构建的触发由SCM负责通知Jenkins最为理想;但在外部的SCM无法通知到局域网中的Jenkins时,可以采轮询SCM方式倒也不失为一种选择
Jenkins cron语法遵循Unix cron语法的定义,但在细节上略有差别
一项cron的定义包含由空白字符或Tab分隔的5个字段,用于定义周期性的时间点
H 符号可用于任何字段,且它能够在一个时间范围内对项目名称进行散列值计算出一个唯一的偏移量,以避免所有配置相同cron值的项目在同一时间启动;比如:triggers { cron(H(0,30)) }
This field follows the syntax of cron (with minor differences). Specifically,
each line consists of 5 fields separated by TAB or whitespace:
MINUTE HOUR DOM MONTH DOW
MINUTE Minutes within the hour (0–59)
HOUR The hour of the day (0–23)
DOM The day of the month (1–31)
MONTH The month (1–12)
DOW The day of the week (0–7) where 0 and 7 are Sunday.
To specify multiple values for one field, the following operators are available.
In the order of precedence,
* specifies all valid values
M-N specifies a range of values
M-N/X or */X steps by intervals of X through the specified range or whole valid
range
A,B,...,Z enumerates multiple values
To allow periodically scheduled tasks to produce even load on the system, the
symbol H (for “hash”) should be used wherever possible. For example, using 00 *
* * for a dozen daily jobs will cause a large spike at midnight. In contrast,
using H H * * * would still execute each job once a day, but not all at the same
time, better using limited resources.
The H symbol can be used with a range. For example, H H(0-7) * * * means some
time between 12:00 AM (midnight) to 7:59 AM. You can also use step intervals
with H, with or without ranges.
The H symbol can be thought of as a random value over a range, but it actually is
a hash of the job name, not a random function, so that the value remains stable
for any given project.
Beware that for the day of month field, short cycles such as */3 or H/3 will not
work consistently near the end of most months, due to variable month lengths. For
example, */3 will run on the 1st, 4th, …31st days of a long month, then again
the next day of the next month. Hashes are always chosen in the 1-28 range, so
H/3 will produce a gap between runs of between 3 and 6 days at the end of a
month. (Longer cycles will also have inconsistent lengths but the effect may be
relatively less noticeable.)
Empty lines and lines that start with # will be ignored as comments.
In addition, @yearly, @annually, @monthly, @weekly, @daily, @midnight, and
@hourly are supported as convenient aliases. These use the hash system for
automatic balancing. For example, @hourly is the same as H * * * * and could mean
at any time during the hour. @midnight actually means some time between 12:00 AM
and 2:59 AM.
Examples:
# Every fifteen minutes (perhaps at :07, :22, :37, :52):
H/15 * * * *
# Every ten minutes in the first half of every hour (three times, perhaps at :04,
:14, :24):
H(0-29)/10 * * * *
# Once every two hours at 45 minutes past the hour starting at 9:45 AM and
finishing at 3:45 PM every weekday:
459-16/2 * * 1-5
# Once in every two hour slot between 8 AM and 4 PM every weekday (perhaps at
9:38 AM, 11:38 AM, 1:38 PM, 3:38 PM):
H H(8-15)/2 * * 1-5
# Once a day on the 1st and 15th of every month except December:
H H 1,15 1-11 *
Time zone specification
Periodic tasks are normally executed at the scheduled time in the time zone of
the Jenkins master JVM (currently Asia/Shanghai). This behavior can optionally be
changed by specifying an alternative time zone in the first line of the field.
Time zone specification starts with TZ=, followed by the ID of a time zone.
Complete example of a schedule with a time zone specification:
TZ=Europe/London
# This job needs to be run in the morning, London time
H 8 * * *
# Butlers do not have a five o'clock, so we run the job again
H(0-30) 17 * * *
范例: 每小时构建

每3分钟构建一次,如:在2:55,2:58,3:01,3:04时间点进行构建

范例: SCM 构建

观察Git 轮询日志可以看到当有变化时才会构建,否则不会执行构建


2.11.2 构建 Webhook 触发器
构建触发器(webhook),也称为钩子,实际上是一个HTTP回调,其用于在开发人员向gitlab提交代码后能够触发jenkins自动执行代码构建操作。

常见场景: 只有在开发人员向develop分支提交代码的时候会自动触发代码构建和部署至测试环境,而向主分支提交的代码不会自动构建,需要运维人员手动部署代码到生产环境。

可以使用下面两种方式实现 Webhook 触发构建
触发远程构建: 此方式无需安装插件
Build when a change is pushed to GitLab. GitLab webhook URL: 需要安装插件
2.11.2.1 触发远程构建
2.11.2.1.1 Jenkins配置构建 Webhook 触发器

生成WebHook 触发器链接
http://jenkins.wang.org:8080//job/hello-demo-go--auto-freestyle/build?
token=666666
2.11.2.1.2 Jenkins 配置生成用户的 API Token

修改用户配置---添加API Token

注意: 此值是一次性的,所以必须立即复制Token
curl 命令测试触发并验证远程触发构建
在任意主机使用图形化浏览器比如:chrome直接访问URL地址
http://admin:<token>@jenkins.wang.org:8080/job/hello-world-war/build?
token=666666
使用curl命令访问URL
curl http://admin:<token>@jenkins.wang.org:8080/job/hello-world-war/build?
token=666666
# 如果执行正常,则无任何显示
2.11.2.1.3 Jenkins 安装插件(旧版才需安装,新版不需要)
系统管理-管理插件-可选插件-Gitlab和Gitlab Hook 两个插件
注意事项:
https://jenkins.io/security/advisory/2018-05-09/#SECURITY-263

在 jenkins 系统管理--全局安全设置,认证改为登录用户可以做任何事情取消跨站请求伪造保护
Gitlab Hook Plugin以纯文本形式存储和显示GitLab API令牌


2.11.2.1.4 Jenkins 修改相关配置(旧版才需安装,新版不需要) 2.11.2.1.4.1 关闭角色授权策略
注意: 必须不能使用角色授权策略,否则重启jenkins服务后会无法登录Jenkins,如下面错误

系统管理—全局安全设置
确认选中”登录登录用户可以做任何事“
新版界面

旧版界面

保存以上配置
2.11.2.1.4.2 修改CSRF配置
Jenkins版本自2.204.6以来的重大变更有:删除禁用 CSRF 保护的功能。 从较旧版本的Jenkins 升级的实例将启用 CSRF 保护和设置默认的发行者,如果之前被禁用。则需要做下面配置官方说明
https://www.jenkins.io/doc/book/security/csrf-protection/
修改 jenkins配置
[root@jenkins ~]#vim /etc/default/jenkins
JAVA_ARGS="-Djava.awt.headless=true -
Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=tru
e"
[root@jenkins ~]#systemctl restart jenkins.service
如果不配置此项,会有下面提示错误

<html>
<head>
<meta http-equiv="Content-Type"content="text/html;charset=utf-8"/>
<title>Error 403 No valid crumb was included in the request</title>
</head>
<body><h2>HTTP ERROR 403 No valid crumb was included in the request</h2>
<table>
<tr><th>URI:</th><td>/job/testproject/build</td></tr>
<tr><th>STATUS:</th><td>403</td></tr>
<tr><th>MESSAGE:</th><td>No valid crumb was included in the request</td></tr>
<tr><th>SERVLET:</th><td>Stapler</td></tr>
</table>
<hr><a href="https://eclipse.org/jetty">Powered by Jetty:// 9.4.41.v20210516</a>
<hr/>
</body>
</html>

2.11.2.1.5 Gitlab配置 Webhook
2.11.2.1.5.1 Gitlab配置 Webhook
在gitlab服务器指定项目中创建webhook,输入下面网址
# 方法 1
http://jenkins.wang.org:8080/job/hello-world-war/build?token=666666
#方法2
http://jenkins.wang.org:8080/job/hello-world-war/build
在secret token处添写666666

旧版如下

测试出现下面提示错误
Hook execution failed: URL 'http://jenkins.wang.org:8080/job/hello-world-
war/build?token=666666' is blocked: Requests to the local network are not
allowed

2.11.2.1.5.2 Gitlab 打开外发请求(旧版才需安装,新版不需要)

再次测试成功

gitlab配置 webhook
2.11.2.1.6 测试调用 webhook
注意: 需要取消 启用 SSL 验证


2.11.2.1.7 提交代码自动触发 webhook执行
[root@gitlab hello-world-war]#sed -i "s/v[0-9].0/$ver/"
src/main/webapp/index.jsp
[root@gitlab hello-world-war]#ver=v1.0;git add .;git commit -m $ver;git push


2.11.2.2 GitLab Webhook URL
2.11.2.2.1 Jenkins 安装 GitLab 插件
没有安装 GitLab 插件,默认无此选项功能


2.11.2.2.2 Jenkins 创建和配置任务

2.11.2.2.3 配置 Gitlab Webhook
在gitlab 上对应代码库做以下配置

测试

出现下面提示错误

2.11.2.2.4 配置 Gitlab 打开外发请求

再次测试成功

2.11.2.2.5 验证结果
修改代码并提交仓库
[root@gitlab testproject]#echo $ver > index.html
[root@gitlab testproject]#ver=v6.0;git add .; git commit -m $ver;git push

2.12 构建前后多个项目关联自动触发任务执行
用于多个 Job 相互关联,需要同行执行多个job的场景,比如:如果job1后希望自动构建job2
可以用两种方法实现
在前面任务中利用构建后操作关联后续任务
在后面任务中利用构建触发器关联前面任务
注意:上面两种方法,都需要在前面任务执行后才能自动关联执行后续任务
2.12.1 在前面任务里配置构建后操作
在先执行的任务中配置构建后操作实现
2.12.1.1 创建构建后操作
在第一个要执行的任务,指定构建后操作,添加第二个任务,要构建的项目可以填写多个项目名,之间用逗号分隔即可

2.12.1.2 创建后面的任务





2.12.1.3 验证构建后操作

[root@jenkins ~]#cat /tmp/jobs.log
test-job1
test-job2
test-job3

2.12.2 在后面构建的任务里创建
2.12.2.1 在后续构建的任务里利用构建触发器实现




2.12.2.2 验证结果 执行test-job1
[root@jenkins ~]#cat /tmp/jobs.log
test-job1
test-job3

执行 test-job2
[root@jenkins ~]#cat /tmp/jobs.log
test-job1
test-job3
test-job2
test-job3

2.13 Blue Ocean 插件实现可视化

Blue Ocean 插件可以实现更加漂亮的可视化界面,并且可以对指定的步骤进行重启等操作
2.13.1 安装 Blue Ocean 插件
注意: 安装完插件,需要重启Jenkins才能生效

2.13.2 使用 Blue Ocean

可以看到每个Job的执过状态,并可以选择构建中的部分步骤进行执行


3 Jenkins 的高级功能
3.1 Jenkins 分布式
Jenkins 分布式即将Jenkins的任务进行分布式处理
3.1.1 Jenkins 分布式说明
3.1.1.1 Jenkins 分布式相关概念

在众多 Job 的场景下,单台 Jenkins Master 同时执行代码 clone、编译、打包及构建,其性能可能会出现瓶颈从而会影响代码部署效率
Jenkins官方提供了 Jenkins 分布式构建,将众多job分散运行到不同的 Jenkins slave节点,大幅提高并行job的处理能力。除此之外,还可以针对不同的开发环境分配至不同的Slave实现编译部署
比如:Java程序分配至Slave1,Go程序的编译分配给Slave2,Nodejs程序分配给Slave3
在 Jenkins 2 中,节点是一个基础概念,代表了任何可以执行 Jenkins 任务的系统
采用 master/agent 架构,因而其节点可划分主节点(master)和代理节点(agent)两种类型,,代理节点也被称为从节点(slave)
主节点负责提供UI、处理HTTP请求及管理构建环境等,而代理节点则主要负责执行构建任务
-
主节点: Jenkins的一个部署实例的核心控制系统,它能够完全访问所有Jenkins配置的选项和任务 (job)列表,而且,若不存在其他代理节点,主节点也是默认的任务执行节点
-
代理节点:在早先版本的Jenkins中,代理节点 (agent)也被称为从节点(slave),它代表着所有的非主节点
这类节点由主节点管理,按需分配或指定执行特定的任务,例如不同的构建任务或测试
脚本式流水线中,节点特指一个运行代理节点的系统,而在声明式流水线中,它则是分配的一个作为代理节点的特定节点
执行器(Executor):简单来说,Executor只是节点或代理节点用于执行任务的一个糟位
Executor的数量定义了该节点可以执行的并发任务量,一个节点上可以有任务数量的糟位,但也允行管理员按节点资源定义合适的数量
在主节点将任务分配给特定节点时,该节点上必须有可用的Executor来立即执行该任务,否则、只能等到有空闲槽位可用

3.1.1.2 Jenkins 主从架构图

3.1.1.3 节点标签
Jenkins中的标签(tag)指的是节点上的标识符,而后可由pipeline中的agent指令等进行过滤和选择节点执行
当Agent节点较多时,基于方便管理的目的,通常应该给这些节点添加能够体现其某种特性或功能的标签,以便于在构建任务中能基于标签过滤出符合条件的agent来
一个 Agent 上可添加多个标签,一个标签也可以添加至多个 Agent
标签名称不允许使用空白字符,也不允许使用标签表达式中预留的关键字,例如: !、&、|、<、>、) 和 ( 等
常用的标签纬度有如下几个
操作系统类型: Linux、Windows、MacOS 操作系统位数: 32bit、64bit 集成的工具链: jdk、Go、Python、Nodejs等
3.1.2 实战案例: 实现 Jenkins 分布式

3.1.2.1 Slave 节点安装 Java 等环境确保和 Master 环境一致
Slave 节点通过从Master节点自动下载的基于 JAVA 的 remoting.jar 程序包实现,所以需要安装JDK
Slave服务器需要创建与Master相同的数据目录,因为脚本中调用的路径只有相对于Master的一个路径,此路径在master与各node节点应该保持一致。任务中执行的脚本存放的路径和master也必须一致.
如果Slave需要执行编译或执行特定的job,则也需要配置Java或其它语言环境,安装 git、maven、go、 ansible等与master相同的基础运行环境
#在两个slave主机上执行下面操作,安装jdk
[root@jenkins-slave1-ubuntu ~]#apt -y install openjdk-8-jdk
[root@jenkins-slave1-ubuntu ~]#java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-8u242-b08-0ubuntu3~18.04-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)
#创建数据目录,可以不创建,会自动创建
[root@jenkins-slave1-ubuntu ~]#mkdir -p /var/lib/jenkins
#如果需要执行特定任务,还需要安装相关的工具
[root@jenkins-slave1-ubuntu ~]#apt -y install git maven golang ansible
#名称解析要和jenkins服务器一致
[root@jenkins-slave1-ubuntu ~]#cat /etc/hosts
10.0.0.100 gitlab.wang.org
10.0.0.101 jenkins.wang.org
#生成ssh key,并复制公钥到Gitlab的相关联的用户
[root@jenkins-slave1-ubuntu ~]#ssh-keygen
[root@jenkins-slave1-ubuntu ~]#cat .ssh/id_rsa.pub
#如果需要和其它主机基于SSH key连接,还需复制公钥到其它主机
[root@jenkins-slave1-ubuntu ~]#ssh-copy-id web01
[root@jenkins-slave1-ubuntu ~]#ssh-copy-id web02

3.1.2.2 Master 节点安装插件
安装 SSH Build Agents 插件,实现 ssh 连接代理

3.1.2.3 添加 Slave 节点 注意: 主从节点的时间要同步 Jenkins—系统管理—节点管理—新建节点: 添加slave节点:



Jenkins Slave 信息
注意: : 只有 Jenkins 提前安装 SSH Build Agents 插件,才能出现Launch agents via SSH选项
注意: Slave节点的远程工作目录建议和Master相同,且此目录不存在也可以自动生成

如果需要Slave执行相关任务,还需要安装工具,并指定相关工具路径如下

3.1.2.4 添加 Master 访问 Slave 认证凭据
用于 Master 连接 Slave 节点的凭据
可以是用户密码的凭据,也可以配置Master节点到Slave节点SSH key 验证

3.1.2.5 查看 Jenkins Slave 创建日志

3.1.2.6 故障排错
如果 slave 没有 java 相应的环境则报错

解决上面错误提示
[root@jenkins-slave1-ubuntu ~]#mkdir -p /var/lib/jenkins/jdk/bin/
[root@jenkins-slave1-ubuntu ~]#ln -s /usr/bin/java /var/lib/jenkins/jdk/bin/
3.1.2.7 验证 Slave Web 状态
正常状态:

如果Slave节点和Master节点时间不同步会出现如下状态

3.1.2.8 验证 Slave 进程状态
[root@jenkins-slave1-ubuntu ~]#ps aux|grep jenkins
root 597782.1 8.0 226302079068 ? Ssl 21:05 0:11 java -jar
remoting.jar -workDir /var/lib/jenkins -jar-cache
/var/lib/jenkins/remoting/jarCache
root 599110.0 0.1 144281012 pts/0 S+21:13 0:00 grep--
color=auto jenkins
[root@jenkins-slave1-ubuntu ~]#ls /var/lib/jenkins
remoting remoting.jar
[root@jenkins-ubuntu ~]#ss -nt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0010.0.0.101:22 10.0.0.1:3307
ESTAB 0010.0.0.101:48588 10.0.0.102:22
3.1.2.9 建立后续的其它节点
重复上面的过程,建立其它的从节点
小技巧: 可以将复制Slave1节点的/root/.ssh目录到Slave2,从而可以省略 Slave2到其它主机的 Ssh key验证过程
[root@jenkins-slave2-ubuntu ~]#apt -y install openjdk-8.jdk




3.1.2.10 指定任务运行的节点
注意事项:
指定slave节点运行任务,可能会需要配置到gitlab服务和web服务器的ssh key验证如果需要执行脚本,还需要复到jenkins服务器的脚本到slave节点

3.2 Jenkins Pipeline
3.2.1 Pipeline 介绍
流水线生产,又叫流水生产流水作业,指劳动对象按一定的工艺路线和统一的生产速度,连续不断地通过各个
工作地,按顺序地进行加工并生产出产品的一种生产组织形式。它是对象专业化组织形式的进一步发展,是劳
动分工较细、生产效率较高的一种生产组织形式。亨利.福特(Henry Ford)于1913年在密歇根州的
Highland Park,建立的生产系统。


所谓的 Pipeline 流水线,其实就是将之前的一个任务或者一个脚本就做完的工作,用 Pipeline 语法划分为多个子任务然后分别执行,两者实现的最终效果是一样的,但是由于原始任务划分为多个子任务之后,以流水线的方式来执行,那么就可以随时查看任意子任务的执行效果,即使在某个阶段出现问题, 我们也可以随时直接定位问题的发生点,大大提高项目的效率,即模块化完成复杂任务的思想体现
Pipeline 是帮助 Jenkins 实现CI到CD转变的重要角色,是运行在 jenkins 2.X 版本的核心插件,简单来说 Pipeline就是一套运行于 Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂发布流程,从而实现单个任务很难实现的复杂流程编排和任务可视化官方帮助:
https://www.jenkins.io/zh/doc/book/pipeline/
https://www.jenkins.io/doc/book/pipeline/
https://www.jenkins.io/2.0/
Pipeline基于Groovy DSL(领域特定语言Domain Specific Language )实现,任何发布流程都可以表述为一段Groovy脚本。
Groovy是一种基于JVM虚拟机的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 是用Java写的 , Groovy语法与Java语法类似, Groovy 代码不仅能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy也可以使用其他非Java语言编写的库
Groovy官网:http://www.groovy-lang.org/learn.html
Groovy语法:http://groovy-lang.org/syntax.html


流水线和自由风格任务流程比较

3.2.2 Pipeline 优势

一致性: pipeline 用统一语法的代码的方式实现各个CICD的阶段的任务,不仅可以被纳入版本控制,还可以通过编辑代码实现目标效果
直观性: 构建过程中每一步都可以直接的图形化显示输出,比如每个阶段的执行时间,直观友好,pipeline 帮助我们快速的定位哪个阶段的任务出现错误
可持续性:jenkins的重启或者中断后不影响已经执行的pipeline Job
支持暂停:pipeline可以选择停止并等待人工输入或批准后再继续执行
支持回放: 如果失败,可以使用回放,进行临时性的修改 job ,再调试执行,如果成功,再真正修改任务即可可扩展:通过groovy的编程更容易的扩展插件
并行执行:通过groovy脚本可以实现step,stage间的并行执行,和更复杂的相互依赖关系
多功能:支持复杂CD要求,包括fork/join子进程,条件判断,循环和并行执行工作的能力
3.2.3 Pipeline 语法
3.2.3.1 Pipeline 语法介绍和结构
官方文档
https://www.jenkins.io/zh/doc/book/pipeline/syntax/
当前 Jenkins 2.X 支持两种语法的流水线: 声明式和脚本式
-
脚本式Scripted Pipeline语法: 此语法是 Jenkins最先支持pipeline语法,它采用命令式风格,直接在流水线脚本中定义逻辑和程序流程
-
声明式Declarative Pipeline语法:后来CloudBees公司为Jenkins引入的一种“流水线即代码”的 pipeline语法,它允许用户在pipeline的定义中将更多的精力关注于期望pipeline的状态和输出之上,而非实现逻辑
声明式和脚本化的流水线从根本上是不同的。 声明式流水线的是 Jenkins 流水线更新一些的特性:
-
相比脚本化的流水线语法,它提供更丰富的语法特性
-
是为了使编写和读取流水线代码更容易而设计的
Pipeline 的基本结构
pipeline
流水线的最外层结构,代表整条pipeline,包含着pipeline的完整逻辑;是声明式流水线语法的关健特征
node 和 agent
用于定义任务在哪里执行
每个node都是一个 Jenkins 节点,可以是 Jenkins master也可以是 Jenkins agent,node是执行 step的具体服务器。
node 代码块也是脚本式pipeline语法的关健特性,声明式pipeline使用 agent 关健字
stages
用于包含所有stage的定义
stage
指定 stage 的名称, 用于定义每个阶段 stage 的主要任务
一个pipeline可以划分为若干个stage,每个stage都是一个完整的操作,比如: clone代码、代码编译、代码测试和代码部署,阶段是一个逻辑分组,可以跨多个node执行。
steps
每个阶段stage需要执行哪些命令
步骤 steps 是jenkins pipeline最基本的操作单元,从在服务器创建目录到构建容器镜像,由各类 Jenkins 插件提供实现,例如: sh “make”
post
用在stage 代码块或整个pipeline执行完成后的附加步骤,此指令非必须项
常用指令
无论是脚本式语法还是声明式语法,他们本质上都是执行各种命令,对于不同的命令需要采用专用的语法来实现指定的功能,常见的语法命令及其样式如下:
echo: 输出信息, echo "Building"
sh: 执行命令,sh 'command' sh([script: 'echo hello'])
git: 克隆代码,git branch: 'develop', credentialsId: 'd7e3bd', url: 'git@10.0.0.100:magedu/app1.git'
env: 设置变量, env.PATH="/usr/local/java/bin:$PATH"
Jenkins 内置语法帮助
http://jenkins-server:8080/job/<job-name>/pipeline-syntax/
#注意:需要安装pipeline插件并且是pipeline风格的任务
3.2.3.2 脚本式流水线语法
node {
stage('Source') {
//
}
stage('Build') {
//
}
stage('Test') {
//
}
stage('Deploy') {
//
}
}
#特点:最外层是node {}
3.2.3.3 声明式流水线语法
声明式流水线是在"Pipeline plugin"的2.5版本添加到 Jenkins 流水线的 ,它在流水线子系统之上提供了一种更简单,更有主见的语法。
所有有效的声明式流水线必须包含在一个 pipeline 块中, 比如:
pipeline {
/* insert Declarative Pipeline here */
}
官方说明
https://www.jenkins.io/zh/doc/book/pipeline/syntax/
Pipeline 的声明式语法要点
steps内部的命令,每一条单独的命令都在当前任务的工作目录下执行。
即使A命令切换到了一个新的目录,接下来的B命令并不会在对应的新目录中执行,而是在当前任务的工作目录下执行。如果非要在切换后的目录下执行命令B,那么采用she11中的&&符号将多条命令拼接在一起即可。
默认情况下,不支持shell里面的复杂语法,因为groovy有自己的条件表达式
如果jenkins的工作目录下存在同名目录,则获取失败
基本语法
pipeline {
agent any
environment{
url='http://www.wangxiaochun.com'
}
stages {
stage('Source') {
steps {
//
echo "Access ${url}"
}
}
stage('Build') {
steps {
//
}
}
stage('Test') {
steps {
//
}
}
stage('Deploy') {
steps {
//
}
}
}
}
#特点:最外层是 pipeline {}

3.2.3.4 基本案例
范例: 脚本式
node {
stage('Get code') {
echo '获取代码'
}
stage('Build') {
echo '构建项目代码'
}
stage('Test') {
echo '测试项目功能'
}
stage('Deploy') {
echo '部署项目'
}
}
范例: 声明式
pipeline {
agent any
stages {
stage('获取代码') {
steps {
echo '获取代码'
}
}
stage('构建代码') {
steps {
echo '构建项目代码'
}
}
stage('代码测试') {
steps {
echo '测试项目功能'
}
}
stage('项目部署') {
steps {
echo '部署项目'
}
}
}
}
3.2.4 Pipeline 编辑器的特性
语法检查
编辑器会尝试检查Groovy语法和引用的有效性,所有问题都会在对应代码行前面通过红色“X”方框标记提示出来;然而,并非所有的错误标记都代表真正的错误,在某些时候脚本可能无法解析依赖或最近创建的输入,这是一个异常而非规则;
完整的错误信息
X标记在提供快速识别问题行的同时,还支持鼠标悬停时展示元整的错误信息
自动补全
编辑器还提供了一定程度上的自动补全功能,比如自动补全括号;
提供了“代码片断生成器”
代码片断生成器提供了一种搜索可用的DSL步骤的方法,以帮助用户随时借鉴和查阅感兴趣步骤的主义和语法
注意: 由于当前pipeline编辑器支持中文不友好,建议先在文本编辑中写完后,再复制到pipeline的编辑器中使用
3.2.5 实现一个简单 Pipeline Job
3.2.5.1 安装 Pipeline 插件
安装 Pipeline 和 Pipeline Stage View 插件


注意: 如果不安装插件,虽然可以创建流水线的任务,但在执行任务时会出现下面的错误提示

3.2.5.2 创建 Pipeline Job

3.2.5.3 测试简单 Pipeline Job 运行
Pipeline 基于脚本式的测试代码

node {
stage(" 代码 clone"){
echo " 代码 clone"
}
stage(" 代码构建 "){
echo " 代码构建 "
}
stage(" 代码测试 "){
echo " 代码测试 "
}
stage(" 代码部署 "){
echo " 代码部署 "
}
}
Jenkins Web 界面配置:

3.2.5.4 执行 Pipeline Job
任务执行结果在阶段视图中以方块的形式显示
一次构建用一行方块来表示,其中每个方块代表流水线中的一个stage 每个方块都代表了一个特定阶段的一次执行结果
方块颜色的意义
蓝色条纹:stage 运行中白色: stage尚未执行红色条纹:state执行失败绿色:stage执行成功
浅红色:stage 执行成动,但是下游的某个stage出现失败

如果安装Blue Ocean 插件,可以下看如下的显示效果

3.2.5.5 自动生成拉取代码的 Pipeline 脚本
点击"流水线语法"跳转至流水线代码生成链接

或者如下也会跳转到流水线代码生成链接

生成流水线脚本

3.2.5.6 更改 Pipeline 任务
node {
stage("clone 代码"){
git branch: 'develop', credentialsId: 'd7e3bd0b-fd88-4ffa-b330-
2258e93319ed', url: 'git@10.0.0.100:dev/app1.git'
}
stage("代码构建"){
echo"代码构建"
}
stage("代码测试"){
echo"代码测试"
}
stage("代码部署"){
echo"代码部署"
}
}
3.2.5.7 执行 Jenkins Pipeline 任务

3.2.5.8 验证 Git Clone 日志


3.2.5.9 Jenkins 服务器验证 clone 代码数据是否成功
[root@jenkins-ubuntu ~]#cat /var/lib/jenkins/workspace/pipeline-test/index.html
<h1>magedu/app1 v11 </h1>
[root@jenkins-ubuntu ~]#
3.2.6 实战案例: 脚本式 Pipeline
3.2.6.1 Pipeline 部署示例
范例:spring-boot-helloWorld 项目
node {
stage("clone代码"){
//sh 'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'main', credentialsId: 'c7fc326e-9a4b-4f80-9908-728bdc7b9630',
url: 'git@gitlab.wang.org:dev1/spring-boot-helloWorld.git'
}
stage("编译代码"){
sh 'mvn clean package -Dmaven.test.skip=true'
}
stage("停止app服务"){
sh 'ssh 10.0.0.104 "pgrep java && killall -9 java || true "'
sh 'ssh 10.0.0.105 "pgrep java && killall -9 java || true "'
}
stage("代码复制"){
sh 'scp target/spring-boot-helloworld-*-SNAPSHOT.jar
10.0.0.104:/data/appdir/'
sh 'scp target/spring-boot-helloworld-*-SNAPSHOT.jar
10.0.0.105:/data/appdir/'
}
stage("启动app服务"){
sh 'ssh 10.0.0.104 "nohup java -jar /data/appdir/spring-boot-helloworld-
*.jar --server.port=8888 &>/dev/null & "'
sh 'ssh 10.0.0.105 "nohup java -jar /data/appdir/spring-boot-helloworld-
*.jar --server.port=8888 &>/dev/null & "'
}
}
范例: hello-world-war 项目
node {
stage("clone代码"){
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'main', credentialsId: '6f7f2c8b-cc7e-417b-925c-f79dbaa308a3',
url: 'git@gitlab.wang.org:magedu/hello-world-war.git'
}
stage("代码打包"){
sh'cd /var/lib/jenkins/workspace/pipeline-test/src/main/webapp && tar czvf
/data/code.tar.gz *'
}
stage("代码复制"){
sh'scp /data/code.tar.gz 10.0.0.8:/data/tomcat/appdir/'
sh'scp /data/code.tar.gz 10.0.0.18:/data/tomcat/appdir/'
}
stage("停止tomcat服务"){
sh'ssh 10.0.0.8 "systemctl stop tomcat"'
sh'ssh 10.0.0.18 "systemctl stop tomcat"'
}
stage("代码部署"){
sh'ssh 10.0.0.8 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
sh'ssh 10.0.0.18 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
}
stage("启动tomcat服务"){
sh'ssh 10.0.0.8 "systemctl start tomcat"'
sh'ssh 10.0.0.18 "systemctl start tomcat"'
}
}
范例:
node {
stage("clone代码"){
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'develop', credentialsId: 'd7e3bd0b-fd88-4ffa-b330-
2258e93319ed', url: 'git@10.0.0.100:magedu/app1.git'
}
stage("代码打包"){
sh'cd /var/lib/jenkins/workspace/pipeline-test/ && tar czvf
/data/code.tar.gz *'
}
stage("代码复制"){
sh'scp /data/code.tar.gz 10.0.0.104:/data/tomcat/appdir/'
sh'scp /data/code.tar.gz 10.0.0.105:/data/tomcat/appdir/'
}
stage("停止tomcat服务"){
sh'ssh 10.0.0.104 "systemctl stop tomcat"'
sh'ssh 10.0.0.105 "systemctl stop tomcat"'
}
stage("代码部署"){
sh'ssh 10.0.0.104 "rm -rf /data/tomcat/webdir/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /data/tomcat/webdir/myapp/"'
sh'ssh 10.0.0.105 "rm -rf /data/tomcat/webdir/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /data/tomcat/webdir/myapp/"'
}
stage("启动tomcat服务"){
sh'ssh 10.0.0.104 "systemctl start tomcat"'
sh'ssh 10.0.0.105 "systemctl start tomcat"'
}
}
3.2.6.2 执行并验证 Pipeline Job
在 Gitlab 提交代码,执行 Pipeline Job 并验证代码是否最终部署到了web服务器。

3.2.6.3 指定 Node 节点运行 Job
注意: node节点和jenkins节点的环境要一致,包括:git,mvn,ssh等

#jenkins的slave的节点需要安装git命令
[root@jenkins-slave1-ubuntu ~]#apt -y install git
[root@jenkins-slave2-ubuntu ~]#apt -y install git
#jenkins的slave的节点需要打通与web server免密钥登录
[root@jenkins-slave1-ubuntu ~]#ssh-keygen
[root@jenkins-slave1-ubuntu ~]#ssh-copy-id 10.0.0.104
[root@jenkins-slave1-ubuntu ~]#ssh-copy-id 10.0.0.105
[root@jenkins-slave2-ubuntu ~]#ssh-keygen
[root@jenkins-slave2-ubuntu ~]#ssh-copy-id 10.0.0.104
[root@jenkins-slave2-ubuntu ~]#ssh-copy-id 10.0.0.105
Jenkins pipeline 代码
范例1:
node("slave1") {
stage("clone代码"){
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'main', credentialsId: '6f7f2c8b-cc7e-417b-925c-f79dbaa308a3',
url: 'git@gitlab.wang.org:magedu/hello-world-war.git'
}
stage("代码打包"){
sh'cd /var/lib/jenkins/workspace/pipeline-test/src/main/webapp && tar czvf
/data/code.tar.gz *'
}
stage("代码复制"){
sh'scp /data/code.tar.gz 10.0.0.8:/data/tomcat/appdir/'
sh'scp /data/code.tar.gz 10.0.0.18:/data/tomcat/appdir/'
}
stage("停止tomcat服务"){
sh'ssh 10.0.0.8 "systemctl stop tomcat"'
sh'ssh 10.0.0.18 "systemctl stop tomcat"'
}
stage("代码部署"){
sh'ssh 10.0.0.8 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
sh'ssh 10.0.0.18 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
}
stage("启动tomcat服务"){
sh'ssh 10.0.0.8 "systemctl start tomcat"'
sh'ssh 10.0.0.18 "systemctl start tomcat"'
}
}
范例2:
node("jenkins-slave1"){ #指定节点label
stage("clone代码"){
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'develop', credentialsId: 'd7e3bd0b-fd88-4ffa-b330-
2258e93319ed', url: 'git@10.0.0.100:magedu/app1.git'
}
stage("代码打包"){
sh'cd /var/lib/jenkins/workspace/pipeline-test/ && tar czvf
/data/code.tar.gz *'
}
stage("代码复制"){
sh'scp /data/code.tar.gz 10.0.0.104:/data/tomcat/appdir/'
sh'scp /data/code.tar.gz 10.0.0.105:/data/tomcat/appdir/'
}
stage("停止tomcat服务"){
sh'ssh 10.0.0.104 "systemctl stop tomcat"'
sh'ssh 10.0.0.105 "systemctl stop tomcat"'
}
stage("代码部署"){
sh'ssh 10.0.0.104 "rm -rf /data/tomcat/webdir/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /data/tomcat/webdir/myapp/"'
sh'ssh 10.0.0.105 "rm -rf /data/tomcat/webdir/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /data/tomcat/webdir/myapp/"'
}
stage("启动tomcat服务"){
sh'ssh 10.0.0.104 "systemctl start tomcat"'
sh'ssh 10.0.0.105 "systemctl start tomcat"'
}
}
3.2.6.3 验证 Slave 执行构建

3.2.6.4 查看流水线步骤
指定当前的构建,可以看本次构建的流水过程

3.2.6.5 验证 Web 服务器代码版本
Gitlab重新提交代码并测试代码部署
[root@centos8 app1]#vim index.html
[root@centos8 app1]#cat index.html
<h1>magedu/app1 v16 </h1>
[root@centos8 app1]#git add .;git commit -m v16;git push
Username for'http://10.0.0.100': wang
Password for'http://wang@10.0.0.100':
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 259 bytes | 259.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.100/magedu/app1/merge_requests/new?
merge_request%5Bsource_branch%5D=develop
remote:
To http://10.0.0.100/magedu/app1.git
2bdda2f..c5ca637 develop -> develop
[root@centos8 app1]#
在后端服务器验证结果
[root@tomcat1 ~]#cat /data/tomcat/tomcat_webapps/myapp/index.html
<h1>magedu/app1 v16 </h1>
[root@tomcat1 ~]#systemctl status tomcat
● tomcat.service - Tomcat
Loaded: loaded (/lib/systemd/system/tomcat.service; disabled; vendor preset:
enabled)
Active: active (running) since Tue 2020-03-1014:30:34 CST; 57s ago
Process: 7034ExecStop=/apps/tomcat/bin/shutdown.sh (code=exited,
status=0/SUCCESS)
Process: 7196ExecStart=/apps/tomcat/bin/startup.sh (code=exited,
status=0/SUCCESS)
Main PID: 7204 (java)
Tasks: 41 (limit: 1084)
CGroup: /system.slice/tomcat.service
└─7204 /apps/jdk/jre/bin/java -
Djava.util.logging.config.file=/apps/tomcat/conf/logging.properties -
Djava.util.logging.mana
Mar 1014:30:34 tomcat1 systemd[1]: Starting Tomcat...
Mar 1014:30:34 tomcat1 startup.sh[7196]: Tomcat started.
Mar 1014:30:34 tomcat1 systemd[1]: Started Tomcat.
[root@tomcat2 ~]#cat /data/tomcat/tomcat_webapps/myapp/index.html
<h1>magedu/app1 v16 </h1>
[root@tomcat2 ~]#systemctl status tomcat
● tomcat.service - Tomcat
Loaded: loaded (/lib/systemd/system/tomcat.service; enabled; vendor preset:
enabled)
Active: active (running) since Tue 2020-03-1014:30:35 CST; 1min 29s ago
Process: 5717ExecStop=/apps/tomcat/bin/shutdown.sh (code=exited,
status=0/SUCCESS)
Process: 5879ExecStart=/apps/tomcat/bin/startup.sh (code=exited,
status=0/SUCCESS)
Main PID: 5887 (java)
Tasks: 41 (limit: 1084)
CGroup: /system.slice/tomcat.service
└─5887 /usr/local/jdk/jre/bin/java -
Djava.util.logging.config.file=/apps/tomcat/conf/logging.properties -
Djava.util.logging
Mar 1014:30:35 tomcat2 systemd[1]: Starting Tomcat...
Mar 1014:30:35 tomcat2 startup.sh[5879]: Tomcat started.
Mar 1014:30:35 tomcat2 systemd[1]: Started Tomcat.
3.2.6.6 通过 Jenkinsfile 文件实现
可以将pipeline的语句写到代码仓库中的 Jenkinsfile 文件,这样更加方便维护
3.2.6.6.1 创建 Jenkinsfile 文件
[root@gitlab-ubuntu testproject]#pwd
/data/testproject
[root@gitlab-ubuntu testproject]#mkdir jenkins
[root@gitlab-ubuntu testproject]#vim Jenkinsfile
#将3.2.6.3代码写入此文件
node("slave1") {
stage("clone代码"){
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'main', credentialsId: '6f7f2c8b-cc7e-417b-925c-f79dbaa308a3',
url: 'git@gitlab.wang.org:magedu/hello-world-war.git'
}
stage("代码打包"){
sh'cd /var/lib/jenkins/workspace/pipeline-test/src/main/webapp && tar czvf
/data/code.tar.gz *'
}
stage("代码复制"){
sh'scp /data/code.tar.gz 10.0.0.8:/data/tomcat/appdir/'
sh'scp /data/code.tar.gz 10.0.0.18:/data/tomcat/appdir/'
}
stage("停止tomcat服务"){
sh'ssh 10.0.0.8 "systemctl stop tomcat"'
sh'ssh 10.0.0.18 "systemctl stop tomcat"'
}
stage("代码部署"){
sh'ssh 10.0.0.8 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
sh'ssh 10.0.0.18 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
}
stage("启动tomcat服务"){
sh'ssh 10.0.0.8 "systemctl start tomcat"'
sh'ssh 10.0.0.18 "systemctl start tomcat"'
}
}
#旧版
node("jenkins-slave1"){ #指定节点label
stage("clone代码"){
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'develop', credentialsId: 'd7e3bd0b-fd88-4ffa-b330-
2258e93319ed', url: 'git@10.0.0.100:magedu/app1.git'
}
stage("代码打包"){
sh'cd /var/lib/jenkins/workspace/pipeline-test/ && tar czvf
/data/code.tar.gz *'
}
stage("代码复制"){
sh'scp /data/code.tar.gz 10.0.0.104:/data/tomcat/appdir/'
sh'scp /data/code.tar.gz 10.0.0.105:/data/tomcat/appdir/'
}
stage("停止tomcat服务"){
sh'ssh 10.0.0.104 "systemctl stop tomcat"'
sh'ssh 10.0.0.105 "systemctl stop tomcat"'
}
stage("代码部署"){
sh'ssh 10.0.0.104 "rm -rf /data/tomcat/webdir/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /data/tomcat/webdir/myapp/"'
sh'ssh 10.0.0.105 "rm -rf /data/tomcat/tomcat_webdir/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /data/tomcat/webdir/myapp/"'
}
stage("启动tomcat服务"){
sh'ssh 10.0.0.104 "systemctl start tomcat"'
sh'ssh 10.0.0.105 "systemctl start tomcat"'
}
}
[root@gitlab-ubuntu testproject]#git add .
[root@gitlab-ubuntu testproject]#git commit -m 'add Jenkinsfile'
[root@gitlab-ubuntu testproject]#git push
3.2.6.6.2 修改 Pipeline job 使用 Jenkinsfile 文件
SCM 软件配置管理(Software Configuration Management)

3.2.6.6.3 再次执行构建验证结果

3.2.7 实战案例: 声明式 Pipeline
3.2.7.1 案例: 基本语法
steps 内部的命令,每一条单独的命令都在当前任务的工作目录下执行。
pipeline {
environment {
APP ="testapp"
}
agent any
stages {
stage ('cmd test') {
steps {
echo'命令测试'
sh'pwd'
sh'rm -rf *'
sh'mkdir testdir1'
sh'cd testdir1 && pwd && mkdir testdir2 && cd testdir2 && pwd'
sh'pwd && tree'
sh'echo $WORKSPACE'
sh'echo $JOB_NAME'
sh'mkdir $WORKSPACE/$JOB_NAME'
sh'touch $WORKSPACE/$JOB_NAME/$APP.log'
sh'pwd && tree'
}
}
}
}

3.2.7.2 案例: 变量
声明和使用变量
pipeline {
agent any
environment {
NAME ="wangxiaochun"
}
stages {
stage('declare var') {
steps {
script {
env.LOGIN=sh(returnStdout: true, script: "who|wc -l")
}
}
}
stage('get var') {
steps {
echo"NAME=${NAME}"
echo"LOGIN=${LOGIN}"
}
}
}
}
3.2.7.3 案例: Maven 编译 Java 项目
pipeline {
agent any
tools {
maven 'maven-3.6.0'
}
stages {
stage('code clone') {
steps {
git branch: 'main', url: 'git@gitlab.wang.org:magedu/spring-
boot-helloWorld.git'
}
}
stage('Build') {
steps {
sh'mvn clean package -Dmaven.test.skip=true'
}
}
stage("停止spring boot服务"){
steps {
sh'ssh 10.0.0.8 "killall -0 java && killall -9 java"'
sh'ssh 10.0.0.18 "killall -0 java && killall -9 java"'
}
}
stage("代码复制"){
steps {
sh'scp target/spring-boot-helloworld-0.9.0-SNAPSHOT.jar
10.0.0.8:/data/appdir/'
sh'scp target/spring-boot-helloworld-0.9.0-SNAPSHOT.jar
10.0.0.18:/data/appdir/'
}
}
stage("启动spring boot服务"){
steps {
sh'ssh 10.0.0.8 "nohup java -jar /data/appdir/spring-boot-
helloworld-*.jar --server.port=8888 &>/dev/null & "'
sh'ssh 10.0.0.18 "nohup java -jar /data/appdir/spring-boot-
helloworld-*.jar --server.port=8888 &>/dev/null & "'
}
}
}
}
范例:
pipeline {
agent any
tools {
maven 'mvn-3.6.3'#指定java编译工具版本
}
stages {
stage('Checkout') {
steps {
git branch: 'master', url:
'http://gitlab.magedu.com/magedu/spring-boot-helloworld.git'
}
}
stage('Build') {
steps {
sh'mvn clean package -Dmaven.test.skip=true'
}
}
}
}
#指定端口运行java应用
#java -jar target/spring-boot-helloworld-0.9.0-SNAPSHOT.jar --server.port=8888
3.2.7.4 案例: 确认和取消
input 指令支持中断当前任务,以待确认和取消
如果没有提示,需要重启Jenkins服务
input {
message "should we continue?"
ok "Yes,we should."
submitter "user1,user2"
parameters i string(参数格式)}
}
范例:
pipeline{
agent {
label 'slave1'#指定在linux标签的agent执行任务
}
stages{
stage("get code"){
steps{
echo"git code from scm"
}
}
stage("build"){
steps{
input message: '确定执行吗?', ok: '确定'
echo"build code"
}
}
stage("package"){
steps{
echo"packge code"
}
}
stage("deploy"){
steps{
echo"deploy packge to nodes"
}
}
}
}
#执行效果如下

3.2.7.5 案例: 交互输入
pipeline {
agent any
stages {
stage ( 'check' ) {
input {
message "Are you ok ?"
ok "是的"
parameters {
string(name: 'PERSON', defaultValue: '王老师',description: '请输入确认
者的身份')
}
}
steps {
echo"经过${PERSON}的检查,该项目没有问题!"
}
}
}
}


3.2.7.6 案例: 选项和密码
官方帮助
https://www.jenkins.io/doc/book/pipeline/syntax/#parameters
范例:
pipeline {
agent any
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who
should I say hello to?')
text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some
information about the person')
booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle
this value')
choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description:
'Pick something')
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a
password')
}
stages {
stage('Example') {
steps {
echo"Hello ${params.PERSON}"
echo"Biography: ${params.BIOGRAPHY}"
echo"Toggle: ${params.TOGGLE}"
echo"Choice: ${params.CHOICE}"
echo"Password: ${params.PASSWORD}"
}
}
}
}
在下面框中填写相应的内容后开始构建


范例:
pipeline {
agent any
stages {
stage ( 'check' ) {
input {
message "Are you ok ?"
ok "是的"
parameters {
choice(name: 'CHOICE',choices: [ 'Dev', 'Test',
'Prod'],description: '选择合适的分支')
password (name: 'PASSWORD',defaultValue:
'SECRET',description: '输入密码')
}
}
steps {
echo"分支:${CHOICE},密码:${PASSWORD}"
}
}
}
}


3.2.7.7 案例: 条件判断
对于pipeline来说,一般会使用if语句或者try语句来进行条件的流程控制,这两种方式效果相似参考资料:
https://www.jenkins.io/doc/book/pipeline/syntax/#flow-control
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
node {
stage('Example') {
try {
sh 'exit 1'
}
catch (exc) {
echo 'Something failed, I should sound the klaxons!'
throw
}
}
}
范例:
node {
stage('Example ') {
if(条件值=='匹配内容'){
echo'true'
} else {
echo'false'
}
}
}
#范例:
node {
stage('Example') {
if (env.BRANCH_NAME =='master') {
echo'I only execute on the master branch'
} else {
echo'I execute elsewhere'
}
}
}
#在if中使用的条件值,一般使用she11命令的执行后的状态返回值来进行获取,由于jenkinsfile的特殊
性,普通she11命令的状态返回值必须以文件的方式落地,也就是说stdout的内容重定向到文件,在
jenkins的sh语法中,需要开启 return status: true属性
#格式如下
result =sh returnstdout: true ,script: "<shell command>"
result =sh(script: "<shell command>",returnstdout: true)
#默认情况下,sh命令的状态返回值是О或者非0,如果想要指定状态返回值的内容的话,可以使用如下格式:
result =sh(script: "<shell command> && echo 'true' ll echo 'false' ",
returnstdout: true)
案例:
pipeline {
agent any
stages {
stage( 'test') {
steps{
script{
result =sh(script: "[ -d hello-world-war ]" ,
returnStatus:true)
if(result ==0){
sh'rm -rf hello-world-war'
}
}
sh'git clone -b main git@10.0.0.100:root/hello-world-war.git'
}
}
}
}

3.2.7.8 案例: Java 应用部署
将上面 3.2.6.1 的内容修改为下面形式
范例1
pipeline{
agent any
stages {
stage("clone代码"){
steps {
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'main', credentialsId: '6f7f2c8b-cc7e-417b-925c-
f79dbaa308a3', url: 'git@gitlab.wang.org:magedu/hello-world-war.git'
}
}
stage("代码打包"){
steps {
sh'cd /var/lib/jenkins/workspace/pipeline-test/src/main/webapp &&
tar czvf /data/code.tar.gz *'
}
}
stage("代码复制"){
steps {
sh'scp /data/code.tar.gz 10.0.0.8:/data/tomcat/appdir/'
sh'scp /data/code.tar.gz 10.0.0.18:/data/tomcat/appdir/'
}
}
stage("停止tomcat服务"){
steps {
sh'ssh 10.0.0.8 "systemctl stop tomcat"'
sh'ssh 10.0.0.18 "systemctl stop tomcat"'
}
}
stage("代码部署"){
steps {
sh'ssh 10.0.0.8 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
sh'ssh 10.0.0.18 "rm -rf /usr/local/tomcat/webapps/myapp/* && cd
/data/tomcat/appdir && tar xvf code.tar.gz -C /usr/local/tomcat/webapps/myapp/"'
}
}
stage("启动tomcat服务"){
steps {
sh'ssh 10.0.0.8 "systemctl start tomcat"'
sh'ssh 10.0.0.18 "systemctl start tomcat"'
}
}
}
}
范例2
pipeline{
agent { label "jenkins-slave1"} #指定节点label
stages {
stage("clone代码"){
//agent { label "jenkins-slave1"} #当前stage执行的节点
steps {
sh'rm -rf /var/lib/jenkins/workspace/pipeline-test/*'
git branch: 'develop', credentialsId: 'd7e3bd0b-fd88-4ffa-b330-
2258e93319ed', url: 'git@10.0.0.100:magedu/app1.git'
}
}
stage("代码打包"){
steps {
sh'cd /var/lib/jenkins/workspace/pipeline-test/ && tar czvf
/data/code.tar.gz *'
}
}
stage("代码复制"){
steps {
sh'scp /data/code.tar.gz
10.0.0.104:/data/tomcat/tomcat_appdir/'
sh'scp /data/code.tar.gz
10.0.0.105:/data/tomcat/tomcat_appdir/'
}
}
stage("停止tomcat服务"){
steps{
sh'ssh 10.0.0.104 "systemctl stop tomcat"'
sh'ssh 10.0.0.105 "systemctl stop tomcat"'
}
}
stage("代码部署"){
steps {
sh'ssh 10.0.0.104 "rm -rf /data/tomcat/tomcat_webdir/myapp/* &&
cd /data/tomcat/tomcat_appdir && tar xvf code.tar.gz -C
/data/tomcat/tomcat_webdir/myapp/"'
sh'ssh 10.0.0.105 "rm -rf /data/tomcat/tomcat_webdir/myapp/* &&
cd /data/tomcat/tomcat_appdir && tar xvf code.tar.gz -C
/data/tomcat/tomcat_webdir/myapp/"'
}
}
stage("启动tomcat服务"){
steps{
sh'ssh 10.0.0.104 "systemctl start tomcat"'
sh'ssh 10.0.0.105 "systemctl start tomcat"'
}
}
}
}
3.2.7.9 案例: 并行
并行执行
声明性Parallel的代码块中的可以嵌套多个stage,从而让多个stage任务并行执行。
注意:
一个stage有且只能有一个steps,stages或parallel
嵌套的stages本身不能包含其他paralle stage
但在其他方面的行为与stage相同
任何包含parallel的stage都不能包含agent或者tools
案例: 并行执行
pipeline {
agent any
stages {
stage( 'Deploy') {
parallel {
stage('deploy_proxy'){
steps {
echo"部署反向代理服务"
}
}
stage('deploy app1') {
steps {
echo"部署deploy_app1应用"
}
}
stage ('deploy app2'){
stages {
stage ('delete container') {
steps {
echo"删除旧容器"
}
}
stage('start container') {
steps {
echo"启动新容器"
}
}
}
}
}
}
}
}
无法看并行执行的效果

安装 Blue Ocean插件

可以看到并行执行效果

3.2.7.10 案例: 并行
pipeline {
agent any
stages {
stage('获取代码'){
steps {
sh'echo "获取代码"'
}
}
stage('构建代码'){
steps {
sh'echo "构建代码"'
}
}
stage('测试阶段'){
parallel {
stage('接口测试'){
steps {
sh'echo "接口测试"'
}
}
stage('系统测试'){
steps {
sh'echo "系统测试"'
}
}
stage( '压力测试'){
steps {
sh'echo "压力测试"'
}
}
}
}
stage('环境部署'){
steps {
sh'echo "环境部署"'
}
}
stage('项目检查'){
steps {
sh'echo "项目检查"'
}
}
stage('环境清理'){
steps {
sh'echo "环境清理"'
}
}
}
}


3.2.7.11 案例: 构建后操作
流水线也提供了构建后的动作,普常可用于消息通知
这个动作就在post 配置段中
post部分定义了一个或多个在管道或阶段运行完成后运行的附加步骤(取决于post 部分在管道中的位置)。
post可以支持以下任何后置条件块:
always、changed、fixed、regression、aborted、 failure、successunstable、
unsuccessful、 cleanup。
这些条件块允许根据管道或阶段的完成状态在每个条件内执行步骤。条件块按如下所示的顺序执行。
条件说明
-
always:无论任务执行的状态如何,都会触发执行动作
-
changed:如果当前流水线或阶段的运行与之前的运行具有不同的完成状态,才运行post中的步骤。 fixed:仅当当前管道或阶段的运行成功且前一次运行失败或不稳定时,才运行post中的步骤。 regression:仅当当前管道或阶段的运行状态为失败、不稳定或中止并且前一次运行成功时才运行 post中的步骤。
-
aborted:仅当当前流水线或阶段的运行处于“中止"状态时才运行post中的步骤,这通常是由于流水线被手动中止。这通常在Web U中用灰色表示
-
failure:仅当当前管道或阶段的运行具有“失败"状态时才运行post 中的步骤,通常在Web UI中用红色表示。
-
success:仅当当前管道或阶段的运行具有"成功"“状态时才运行post 中的步骤,通常在Web U中用蓝色或绿色表示。
-
unstable:仅当当前流水线或阶段的运行处于"不稳定"状态时才运行post中的步骤,这通常由测试失败、代码违规等引起的。这通常在Web UI中用黄色表示。
-
unsuccessful:如果当前流水线或阶段的运行没有"成功”状态,才运行post 中的步骤。这通常在 Web U中表示,具体取决于前面提到的状态。
-
cleanup:在评估所有其他后置条件后运行此后置条件中的步骤,而不管管道或阶段的状态如何
格式说明
在stages同级别的位置,添加一个post配置段
post {
always {
echo '任执行结束后执行此操作'
}
}
案例: 利用 Email 插件实现任务完成状态通知
Email Extension 插件说明
https://www.jenkins.io/doc/pipeline/steps/email-ext/#emailext-extended-email
安装插件 Email Extension

系统管理-- 系统配置配置邮件信息

pipeline { |
|---|
agent any |
stages { |
stage('test') { |
steps { |
echo 'test' |
sh 'true' |
//sh'false' |
}}} |
post {
success {
emailext (
body: """项目名称: ${JOB_NAME}\n构建编号:${BUILD_NUMBER}\n构建日
志:${BUILD_URL}console""",
subject: '【Jenkins构建通知】:$JOB_NAME - Build # $BUILD_NUMBER -
成功!',
to: '29308620@qq.com',
from: '29308620@qq.com'
)
}
failure {
emailext (
body: """项目名称: ${JOB_NAME}\n构建编号:${BUILD_NUMBER}\n构建日
志:${BUILD_URL}console""",
subject: '【Jenkins构建通知】:$JOB_NAME - Build # $BUILD_NUMBER -
失败!',
to: '29308620@qq.com',
from: '29308620@qq.com'
)
}
}
}
构建后可以收到下面成功和失败的邮件


3.3 Jenkins 视图
视图可用于归档job进行分组显示,比如将一个业务的视图放在一个视图显示,安装完成插件之后将会有一个+号用于创建视图,支持三种视图,其中列表视图使用较多。

3.3.1 列表视图
列表视图使用场景比较多,用于将同一个业务的job保存至一个列表视图进行分类管理,即不同业务的 job放在不同的列表视图中。
3.3.1.1 创建新的视图

3.3.1.2 定义视图名称

3.3.1.3 选择视图包含的任务

3.3.1.4 最终状态

3.3.2 我的视图
我的视图会显示当前账户有权限访问的job,因此需要提前划分好权限。
3.3.2.1 创建我的视图
创建后点保存,就会直接看到当前账户有权限的job。

3.3.2.2 最终状态

3.3.3 Pipeline 视图
Pipeline 视图可以显示任务之间的上下游关系
3.3.3.1 安装 build pipeline 插件
安装 build pipeline 插件,可以在原来“列表视图”和“我的视图”上面增加“Build Pipeline View”


插件安装完成

3.3.3.2 创建视图

3.3.3.3 定义视图配置信息

配置说明

3.3.3.4 Web 显示界面
以下图示表示 test-job1 ---> test-job2 ---> test-job3 构成上下游的任务关系

3.4 Jenkins 权限管理
默认jenkins用户可以执行所有操作和管理所有job
为了更好的分层控制,可以实现基于角色的权限管理,先创建角色和用户,给角色授权,然后把用户管理到角色。
查看默认的权限设置

3.4.1 创建新用户
默认所有jenkins用户都具有管理权限 Jenkins—系统管理—管理用户— 新建用户




使用wang用户登录,重复上面操作,也可以创建mage用户

说明默认所有用户都是管理员权限

3.4.2 安装角色权限相关的插件
搜索 Role-based Authorization Strategy 可以找到下面插件


如果直接下载失败,可以直接清华源下载,将插件放在 /var/lib/jenkins/plugins 目录下

3.4.3 更改认证方式
Jenkins—系统管理—全局安全配置
默认创建的用户登录后可以做任何操作,取决于默认的认证授权方式。


3.4.4 创建全局角色
Jenkins—系统管理--Manage and Assign Roles 新版界面


旧版界面

旧版

3.4.5 对全局角色分配权限
全局角色配置分配权限,实现控制登陆用户能操作jenkins的那些资源
只分配置全部overall中的Read权限即可

注意:add完成后,还需要保存
旧版

3.4.6 将用户关联到全局角色
Jenkins—系统管理--Manage and Assign Roles ---Assign Roles



3.4.7 测试普通用户登录

登录成功之的界面,没有系统管理权限,只能执行被授权过的job且没有了管理员权限。

3.4.8 创建项目角色
项目角色分配权限, 用于控制用户能看到哪些项目,并且有什么样的权限项目角色使用pattern正则表达式,用于匹配相关的项目名称比如: pattern 设为正则表达式 testproject.* 表示所有testproject开头的job
.jpg)
可以显示匹配的job


再创建项目角色testproject2-role

3.4.9 对项目角色分配权限
给项目角色分配权限,可以在凭据部分授予View权限即可,其它部分全部权限。 分配权限如下显示

3.4.10 将用户关联到项目角色
Jenkins—系统管理--Manage and Assign Roles ---Assign Roles



3.4.11 用户登录验证结果
用wang用户登录查看以下显示

用户mage登录,查看


4 代码质量检测 SonarQube
4.1 代码质量检测工具 SonarQube
4.1.1 代码测试工具 SonarQube 简介

SonarQube 是一个开源平台,用于管理源代码的质量。Sonar 不只是一个质量数据报告工具,更是代码质量管理平台。支持的语言包括:Java、Go、Python、PHP、C、C++C#、C#、JavaScripts、 Scala、HTML、PL/SQL、Swift、Ruby等29种语言。

SonarQube是一种自动代码审查工具,用于检测代码中的错误漏洞和代码异味,它集成到现有的工作流程,以便在项目分支和拉取(PR)请求之间进行连续的代码检查
SonarQube 支持多种插件,实现和 Jenkins 等 CICD 工具的集成

主要特点:
代码覆盖:通过单元测试,将会显示哪行代码被选中
- 改善编码规则
搜寻编码规则:按照名字,插件,激活级别和类别进行查询
-
项目搜寻:按照项目的名字进行查询
-
对比数据:比较同一张表中的任何测量的趋势
官方网站:http://www.sonarqube.org/
下载地址:https://www.sonarqube.org/downloads/
Github 地址: https://github.com/SonarSource/sonarqube
4.1.2 七个维度检测代码质量
- 可维护性(maintainability)
所谓“代码易维护”就是指,在不破坏原有代码设计、不引入新的 bug 的情况下,能够快速地修改或者添加代码。
- 可读性(readability)
在编写代码的时候,时刻要考虑到代码是否易读、易理解。除此之外,代码的可读性在非常大程度上会影响代码的可维护性。
看代码是否符合编码规范、命名是否达意、注释是否详尽、函数是否长短合适、模块划分是否清晰、是否符合高内聚低耦合等等。
code review 是一个很好的测验代码可读性的手段
- 可扩展性(extensibility)
表示代码应对未来需求变化的能力。跟可读性一样,代码是否易扩展也很大程度上决定代码是否易维护.
代码的可扩展性表示,在不修改或少量修改原有代码的情况下,通过扩展的方式添加新的功能代码
- 灵活性(flexibility)
如果一段代码易扩展、易复用或者易用,都可以称这段代码写得比较灵活
- 简洁性(simplicity)
KISS 原则:尽量保持代码简单。代码简单、逻辑清晰,也就意味着易读、易维护.
- 可复用性(reusability)
代码的可复用性可以简单地理解为,尽量减少重复代码的编写,复用已有的代码
- 可测试性(testability)
代码可测试性的好坏,能从侧面上非常准确地反应代码质量的好坏。代码的可测试性差,比较难写单元测试,那基本上就能说明代码设计得有问题
4.1.3 架构和集成
官方说明
https://docs.sonarqube.org/8.9/architecture/architecture-integration/
https://docs.sonarqube.org/7.9/architecture/architecture-integration/
4.1.3.1 SonarQube 架构
SonarQube 四个主要组件

SonarQube Server 包括三个主要部分
Web Server: UI 界面
Search Server :为UI提供搜索功能,基于 ElasticSearch 实现
-
Compute Engine Server:处理代码分析报告,并将之存储到 SonarQube Database
-
SonarQube Database: 负责存储 SonarQube 的配置,以及项目的质量快照等
-
SonarQube Plugin: 可以在 SonarQube Server 安装丰富的插件,实现支持各种开发语言、SCM、 集成、身份验证和治理等功能
-
Code analysis Scanners: 代码扫描器,是SonarQube Server的客户端, 将代码扫描后得出报告提交给 SonarQube Server
4.1.3.2 SonarQube 生态集成

Sonar有两种使用方式:插件和客户端。Sonar的插件名称为 sonarlint,实现支持多种ide的插件安装
4.1.4 SonarQube 版本说明
SonarQube 分为: 社区版,开发版,企业版和数据中心版
其中只有社区版是开源免费的

SonarQube 分两种版本: LTS 和非 LTS 版
SonarQube 的 LTS (Long Term Support长期支持版本) 在其约 18 个月 的生命周期内提供组织稳定性和错误修复。
生产建议使用 LTS 版
官方LTS版本说明
https://www.sonarqube.org/downloads/lts/
TLS 版有如下版本
-
8.9 7.9 -
6.7 -
5.6 -
4.5

3.7
各种版本下载
https://www.sonarqube.org/downloads/


4.2 安装环境准备
4.2.1 硬件依赖
CPU/内存/磁盘
官方说明
https://docs.sonarqube.org/8.9/requirements/requirements/
https://docs.sonarqube.org/7.9/requirements/requirements/
Hardware Requirements
Asmall-scale(individual or small team) instance of the SonarQube server
requires at least 2GB of RAM to run efficiently and 1GB of free RAM for the OS.
If you are installing an instance for a large teams or Enterprise, please
consider the additional recommendations below.
The amount of disk space you need will depend on how much code you analyze with
SonarQube. As an example, SonarCloud the public instance of SonarQube, has more
than 350 million lines of code under analysis with 5 years of history. SonarCloud
is currently running on clustered Amazon EC2 m5.large instances with allocations
of 50 Gb of drive space per node. It handles 19,000+ projects with roughly 14M
open issues. SonarCloud runs on PostgreSQL 9.5 and it is using about 250Gb of
disk space for the database.
SonarQube must be installed on hard drives that have excellent read & write
performance. Most importantly, the "data" folder houses the Elasticsearch indices
on which a huge amount of I/O will be done when the server is up and running.
Great read & write hard drive performance will therefore have a great impact on
the overall SonarQube server performance.
SonarQube does not support 32-bit systems on the server side. SonarQube does,
however, support 32-bit systems on the scanner side.
硬件需求
小型应用至少需要2GB的RAM
磁盘空间取决于SonarQube分析的代码量
必须安装在读写性能较好的磁盘, 存储数据的目录中包含ElasticSearch的索引,服务器启动并运行时,将会在该索引上进行大是I/O操作不支持32位操作系统
4.2.2 数据库环境依赖
4.2.2.1 SonarQube 7.9 以上版本的数据库要求
https://docs.sonarqube.org/7.9/requirements/requirements/
SonarQube 7.9 不再支持MySQL,可以选择安装 PostgreSQL
官方说明: 7.9.x 版本不再支持MySQL
https://docs.sonarqube.org/7.9/setup/upgrade-notes/

4.2.2.2 SonarQube 6.7 的数据库要求
https://docs.sonarqube.org/6.7/Requirements.html
SonarQube 6.7 数据库要使用MySQL 5.6版本,不支持MySQL 5.5的版本

4.2.3 Java 环境依赖
4.2.3.1 SonarQube 7.9 以上版本的 java 环境要求
SonarQube 7.9 以上版本不再支持 java 8

范例:安装 openjdk-11-jdk
#Ubuntu安装java
[root@SonarQube-Server ~]#apt -y install openjdk-11-jdk
#RHEL系统安装java
[root@SonarQube-Server ~]#yum -y install java-11-openjdk
[root@SonarQube-Server ~]#java -version
openjdk version "11.0.6"2020-01-14
OpenJDK Runtime Environment (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1)
OpenJDK 64-Bit Server VM (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1, mixed
mode, sharing)
4.2.3.2 SonarQube 6.7 的 Java 环境要求

4.2.4 创建SonarQube用户
#使用普通账户启动sonarqube
#Ubuntu使用useradd创建用户时默认使用/bin/sh,并且不创建家目录
[root@SonarQube-Server ~]#useradd -s /bin/bash -m sonarqube
4.2.5 系统内核优化
按官网说明修改配置
https://docs.sonarqube.org/7.9/requirements/requirements/
安装在 Linux 对系统的要求
Linux
If you're running on Linux, you must ensure that:
vm.max_map_count is greater or equals to 262144
fs.file-max is greater or equals to 65536
the user running SonarQube can open at least 65536 file descriptors
the user running SonarQube can open at least 4096 threads

注意: 必须修改内核限制,否则在启动时会报以下错误
sonarqube@SonarQube-Server:~$ cat /usr/local/sonarqube/logs/es.log

创建用户和修改内核配置
[root@SonarQube-Server ~]#vim /etc/sysctl.conf
vm.max_map_count=262144#此项必须修改,否则无法启动
fs.file-max=65536#此项可不改,默认值满足要求
#此文件可不改
[root@SonarQube-Server ~]# vim /etc/security/limits.conf
sonarqube - nofile 65536
sonarqube - nproc 4096
root - nofile 65536
root - nproc 4096
#如果以systemd 运行SonarQube,需要在service文件配置
[servcie]
.....
LimitNOFILE=65536
LimitNPROC=4096
......
4.3 安装 SonarQube 服务器
4.3.1 数据库准备
4.3.1.1 安装和配置 PostgreSQL 数据库
4.3.1.1.1 安装和配置 PostgreSQL
[root@ubuntu2004 ~]#apt list postgresql
Listing... Done
postgresql/focal-security,focal-updates 12+214ubuntu0.1 all
N: There is 1 additional version. Please use the '-a' switch to see it
[root@SonarQube-Server ~]#apt-cache madison postgresql
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-
security/main amd64 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-
security/main i386 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-
updates/main amd64 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-
updates/main i386 Packages
postgresql | 10+190 | http://mirrors.aliyun.com/ubuntu bionic/main amd64
Packages
postgresql | 10+190 | http://mirrors.aliyun.com/ubuntu bionic/main i386
Packages
postgresql-common | 190 | http://mirrors.aliyun.com/ubuntu bionic/main
Sources
postgresql-common | 190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-
security/main Sources
postgresql-common | 190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-
updates/main Sources
[root@SonarQube-Server ~]#apt -y install postgresql
[root@SonarQube-Server ~]#systemctl status postgresql
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor
preset: enabled)
Active: active (exited) since Thu 2020-03-1213:36:36 CST; 3min 30s ago
Main PID: 21726(code=exited, status=0/SUCCESS)
Tasks: 0 (limit: 1084)
CGroup: /system.slice/postgresql.service
Mar 1213:36:36 SonarQube-Server systemd[1]: Starting PostgreSQL RDBMS...
Mar 1213:36:36 SonarQube-Server systemd[1]: Started PostgreSQL RDBMS.
[root@SonarQube-Server ~]#id postgres
uid=112(postgres) gid=116(postgres) groups=116(postgres),115(ssl-cert)
#默认监听在127.0.0.1的5432端口,需要修改监听地址
[root@SonarQube-Server ~]#ss -ntlp|grep post
LISTEN 0128127.0.0.1:5432 0.0.0.0:*
users:(("postgres",pid=23337,fd=8))
LISTEN 0128 [::1]:5432 [::]:*
users:(("postgres",pid=23337,fd=7))
#修改监听地址支持远程连接
[root@ubuntu2004 ~]#vim /etc/postgresql/12/main/postgresql.conf
[root@ubuntu1804 ~]#vim /etc/postgresql/10/main/postgresql.conf
listen_addresses ='*'或者'0.0.0.0'
#开启远程访问
[root@ubuntu2004 ~]#vim /etc/postgresql/12/main/pg_hba.conf
[root@ubuntu1804 ~]#vim /etc/postgresql/10/main/pg_hba.conf
# IPv4 local connections:
host all all 127.0.0.1/32 md5
host all all 0.0.0.0/0 md5
[root@SonarQube-Server ~]#grep -n "^[a-Z]" /etc/postgresql/10/main/pg_hba.conf
85:local all postgres peer
90:local all all peer
92:host all all 0.0.0.0/0 md5
94:host all all ::1/128 md5
97:local replication all peer
98:host replication all 127.0.0.1/32 md5
99:host replication all ::1/128 md5
[root@SonarQube-Server ~]#systemctl restart postgresql
[root@SonarQube-Server ~]#ss -ntl|grep 5432
LISTEN 01280.0.0.0:5432 0.0.0.0:*
LISTEN 0128 [::]:5432 [::]:*
说明: /etc/postgresql/10/main/pg_hba.conf
格式:TYPE DATABASE USER ADDRESS METHOD
METHOD有如下值可选
md5:执行SCRAM-SHA-256或MD5身份验证以验证用户的密码。
peer:从操作系统获取客户端的操作系统用户名,并检查它是否与请求的数据库用户名匹配。这仅适用于本地
连接。
trust:允许无条件连接,允许任何PostgreSQL用户身份登录,而无需密码或任何其他身份验证。
reject:拒绝任何条件连接,这对于从组中“过滤掉”某些主机非常有用。
scram-sha-256:执行SCRAM-SHA-256身份验证以验证用户的密码。
password:要提供未加密的密码以进行身份••验证。由于密码是通过网络以明文形式发送的,因此不应在不
受信任的网络上使用。
gss:使用GSSAPI对用户进行身份验证,这仅适用于TCP / IP连接。
sspi:使用SSPI对用户进行身份验证,这仅适用于Windows。
ident:通过联系客户端上的ident服务器获取客户端的操作系统用户名,并检查它是否与请求的数据库用户
名匹配。 Ident身份验证只能用于TCP/IP连接。为本地连接指定时,将使用对等身份验证。
ldap:使用LDAP服务器进行身份验证。
radius:使用RADIUS服务器进行身份验证。
cert:使用SSL客户端证书进行身份验证。
pam:使用操作系统提供的可插入身份验证模块(PAM)服务进行身份验证。
bsd:使用操作系统提供的BSD身份验证服务进行身份验证。
范例: CentOS 安装 postgresql 12
#CentOS7以postresql 12 为例
设置yum仓库
#rpm -i https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-
redhat-repo-latest.noarch.rpm
安装postgresql1,2-server、postgresql12和postgresql12-libs
# yum install postgresql12-server postgresql12 postgresql12-libs
初始化
# postgresql-12-setup initdb
#注意:
配置文件在/var/lib/pgsql/12/data/日录下
服务管理:systemctl start postgresql-12
4.3.1.1.2 创建数据库和用户授权
#使用postgres用户登录(PostgresSQL安装后会自动创建postgres用户)
[root@SonarQube-Server ~]#su - postgres
#登录postgresql数据库
postgres@SonarQube-Server:~$ psql-U postgres
psql (10.12 (Ubuntu 10.12-0ubuntu0.18.04.1))
Type "help"for help.
#安全起见,修改数据库管理员postgres用户的密码
postgres=# ALTER USER postgres WITH ENCRYPTED PASSWORD '123456';
ALTER ROLE
#创建用户和数据库并授权
postgres=# CREATE USER sonar WITH ENCRYPTED PASSWORD '123456';
CREATE ROLE
postgres=# CREATE DATABASE sonarqube OWNER sonar;
CREATE DATABASE
postgres=# GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonar;
GRANT
#前面如果已经指定数据库的OWNER,则可以不执行下面命令
postgres=# ALTER DATABASE sonarqube OWNER TO sonar;
ALTER DATABASE
#查看数据库是否创建
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access
privileges
-----------+----------+----------+-------------+-------------+------------------
-----
postgres | postgres | UTF8 | en_HK.UTF-8 | en_HK.UTF-8 |
sonarqube | sonar | UTF8 | en_HK.UTF-8 | en_HK.UTF-8 | =Tc/sonar
+
| | | | | sonar=CTc/sonar
template0 | postgres | UTF8 | en_HK.UTF-8 | en_HK.UTF-8 | =c/postgres
+
| | | | |
postgres=CTc/postgres
template1 | postgres | UTF8 | en_HK.UTF-8 | en_HK.UTF-8 | =c/postgres
+
| | | | |
postgres=CTc/postgres
(4 rows)
#退出数据库连接
postgres=# \q
4.3.1.2 MySQL 数据库(SonarQube 7.9 以后版本不再需要)
7.9.x 版本以后不再支持 MySQL
[root@SonarQube-Server ~]#apt-get install mysql-server mysql-client
[root@SonarQube-Server ~]#vim /etc/mysql/mysql.conf.d/mysqld.cnf #配置文件路径
[root@SonarQube-Server ~]#mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.26-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
#创建数据库默认编码utf-8并授权
mysql> create database sonar default character set utf8 collate utf8_general_ci;
Query OK, 1 row affected (0.00 sec)
mysql> GRANT ALL PRIVILEGES ON sonar.* TO 'sonar'@'%' IDENTIFIED BY '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)
#测试sonar账户连接mysql
[root@client ~]# mysql -usonar -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.26-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| sonar |
+--------------------+
2 rows inset (0.00 sec)
4.3.2 下载 SonarQube 和修改配置文件
4.3.2.1 下载解压缩
下载链接
https://www.sonarqube.org/downloads/

#8.9版下载
[root@SonarQube-Server ~]#wget -P /usr/local/src
https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-
8.9.2.46101.zip
#7.9版下载
[root@SonarQube-Server ~]#wget -P /usr/local/src
https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-7.9.2.zip
#解压
[root@SonarQube-Server ~]#cd /usr/local/src
[root@SonarQube-Server src]#unzip sonarqube-7.9.2.zip
[root@SonarQube-Server src]#ln -s /usr/local/src/sonarqube-7.9.2
/usr/local/sonarqube
[root@SonarQube-Server ~]#ls /usr/local/sonarqube
bin conf COPYING data elasticsearch extensions lib logs temp web
[root@SonarQube-Server ~]#ls /usr/local/sonarqube/conf/
sonar.properties wrapper.conf
#设置属性
[root@SonarQube-Server ~]#chown -R sonarqube.sonarqube /usr/local/sonarqube/
4.3.2.2 设置 SonarQube 连接数据库
#修改SonarQube配置用于连接postgresql数据库
[root@SonarQube-Server ~]#vim /usr/local/sonarqube/conf/sonar.properties
#修改连接postgresql数据库的账号和密码,和前面的配置必须匹配
sonar.jdbc.username=sonar
sonar.jdbc.password=123456
#修改数据库相关的信息,这里必须和此前配置的postgresql内容相匹配,其中localhost为DB服务器的地
址,而sonarqube为数据库名称
sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube
#设置 SonarQube 的提供的 Web Server监听的地址和端口
sonar.web.host=0.0.0.0 #此为默认值,可不做修改
sonar.web.port=9000#此为默认值,可不做修改
#如有需要可以修改SonarQube存储数据的目录位置,以下两个目录为相对路径,相对于sonarqube的安装目
录,也可以使用绝对路径
sonar.path.data=data #默认值,可不做修改
sonar.path.temp=temp #默认值,可不做修改
4.3.3 启动 SonarQube
注意:SonarQube 需要调用 Elasticsearch,而且默认需要使用普通用户启动,如果以root启动会报错
范例: 以sonarqube用户身份启动
#以sonarqube用户身份启动服务
[root@SonarQube-Server ~]#su - sonarqube
sonarqube@SonarQube-Server:~$ /usr/local/sonarqube/bin/linux-x86-64/sonar.sh
start
Starting SonarQube...
Started SonarQube.
#或者执行下面启动SonarQube
[root@SonarQube-Server ~]#su - sonarqube -c '/usr/local/sonarqube/bin/linux-x86-
64/sonar.sh start'
#查看状态
sonarqube@SonarQube-Server:~$ /usr/local/sonarqube/bin/linux-x86-64/sonar.sh
status
SonarQube is running (11788).
#查看是否9000/tcp端口
sonarqube@ubuntu1804:~$ ss-ntlp
LISTEN 01127.0.0.1:32000 0.0.0.0:* users:(("java",pid=24432,fd=4))
LISTEN 025 *:9000 *:* users:
(("java",pid=24885,fd=14))
LISTEN 0128 [::ffff:127.0.0.1]:9001 *:* users:
(("java",pid=24460,fd=77))
LISTEN 050 [::ffff:127.0.0.1]:36477 *:* users:
(("java",pid=25071,fd=40))
LISTEN 0128 [::ffff:127.0.0.1]:40675 *:* users:
(("java",pid=24460,fd=74))
#如果无法启动,重设目录属性
[root@SonarQube-Server ~]#chown -R sonarqube.sonarqube /usr/local/sonarqube/
#验证日志
[root@SonarQube-Server ~]#tail -n 3 /usr/local/sonarqube/logs/sonar.log
2020.03.12 17:02:18 INFO app[][o.s.a.ProcessLauncherImpl] Launch
process[[key='ce', ipcIndex=3, logFilenamePrefix=ce]] from
[/usr/local/src/sonarqube-7.9.2]: /usr/lib/jvm/java-11-openjdk-amd64/bin/java -
Djava.awt.headless=true-Dfile.encoding=UTF-8 -
Djava.io.tmpdir=/usr/local/src/sonarqube-7.9.2/temp --add-
opens=java.base/java.util=ALL-UNNAMED -Xmx512m-Xms128m-
XX:+HeapDumpOnOutOfMemoryError -Dhttp.nonProxyHosts=localhost|127.*|[::1] -cp
./lib/common/*:/usr/local/src/sonarqube-7.9.2/lib/jdbc/postgresql/postgresql-
42.2.5.jar org.sonar.ce.app.CeServer /usr/local/src/sonarqube-7.9.2/temp/sq-
process13657789573139744918properties
2020.03.12 17:02:39 INFO app[][o.s.a.SchedulerImpl] Process[ce] is up
2020.03.12 17:02:39 INFO app[][o.s.a.SchedulerImpl] SonarQube is up
范例: 以root 身份启动会导致失败
[root@SonarQube-Server sonarqube]#pwd
/usr/local/sonarqube
[root@SonarQube-Server sonarqube]#bin/linux-x86-64/sonar.sh start
Starting SonarQube...
Started SonarQube.
#查看日志无法启动
[root@SonarQube-Server sonarqube]#cat logs/sonar*.log
--> Wrapper Started as Daemon
Launching a JVM...
Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
Copyright 1999-2006 Tanuki Software, Inc. All Rights Reserved.
2020.03.12 16:33:37 INFO app[][o.s.a.AppFileSystem] Cleaning or creating temp
directory /usr/local/src/sonarqube-7.9.2/temp
2020.03.12 16:33:37 INFO app[][o.s.a.es.EsSettings] Elasticsearch listening on
/127.0.0.1:9001
2020.03.12 16:33:37 INFO app[][o.s.a.ProcessLauncherImpl] Launch
process[[key='es', ipcIndex=1, logFilenamePrefix=es]] from
[/usr/local/src/sonarqube-7.9.2/elasticsearch]: /usr/local/src/sonarqube-
7.9.2/elasticsearch/bin/elasticsearch
2020.03.12 16:33:37 INFO app[][o.s.a.SchedulerImpl] Waiting for Elasticsearch
to be up and running
OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in
version 9.0 and will likely be removed in a future release.
2020.03.12 16:33:38 INFO app[][o.e.p.PluginsService] no modules loaded
2020.03.12 16:33:38 INFO app[][o.e.p.PluginsService] loaded plugin
[org.elasticsearch.transport.Netty4Plugin]
2020.03.12 16:33:53 WARN app[][o.s.a.p.AbstractManagedProcess] Process exited
with exit value [es]: 1
2020.03.12 16:33:53 INFO app[][o.s.a.SchedulerImpl] Process[es] is stopped
2020.03.12 16:33:53 INFO app[][o.s.a.SchedulerImpl] SonarQube is stopped
<-- Wrapper Stopped
#查看es日志,提示不能以root启动
[root@SonarQube-Server sonarqube]#cat logs/es.log
2020.03.12 19:42:12 ERROR es[][o.e.b.Bootstrap] Exception
java.lang.RuntimeException: can not run elasticsearch as root
at
org.elasticsearch.bootstrap.Bootstrap.initializeNatives(Bootstrap.java:103) ~
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:170) ~
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:333)
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:159)
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:150)
[elasticsearch-6.8.0.jar:6.8.0]
at
org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.ja
va:86) [elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:124)
[elasticsearch-cli-6.8.0.jar:6.8.0]
at org.elasticsearch.cli.Command.main(Command.java:90) [elasticsearch-cli-
6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:116)
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:93)
[elasticsearch-6.8.0.jar:6.8.0]
2020.03.12 19:42:12 WARN es[][o.e.b.ElasticsearchUncaughtExceptionHandler]
uncaught exception in thread [main]
org.elasticsearch.bootstrap.StartupException: java.lang.RuntimeException: can not
run elasticsearch as root
at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:163) ~
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:150)
~[elasticsearch-6.8.0.jar:6.8.0]
at
org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.ja
va:86) ~[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:124) ~
[elasticsearch-cli-6.8.0.jar:6.8.0]
at org.elasticsearch.cli.Command.main(Command.java:90) ~[elasticsearch-cli-
6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:116) ~
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:93) ~
[elasticsearch-6.8.0.jar:6.8.0]
Caused by: java.lang.RuntimeException: can not run elasticsearch as root
at
org.elasticsearch.bootstrap.Bootstrap.initializeNatives(Bootstrap.java:103) ~
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:170) ~
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:333) ~
[elasticsearch-6.8.0.jar:6.8.0]
at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:159) ~
[elasticsearch-6.8.0.jar:6.8.0]
... 6 more

无法启动的主要的可能原因
用户和权限
-
java 版本不对或没有安装内核参数没有优化
-
数据库及权限
4.3.4 创建 service 文件
官网参考
https://docs.sonarqube.org/8.9/setup/operate-server/
https://docs.sonarqube.org/7.9/setup/operate-server/
范例: 创建 service 文件
#先停止sonarqube
[root@SonarQube-Server ~]#su - sonarqube
sonarqube@SonarQube-Server:~$ /usr/local/sonarqube/bin/linux-x86-64/sonar.sh
stop
sonarqube@SonarQube-Server:~$ /usr/local/sonarqube/bin/linux-x86-64/sonar.sh
status
SonarQube is not running.
sonarqube@SonarQube-Server:~$exit
#创建service文件
[root@SonarQube-Server ~]#vim /etc/systemd/system/sonarqube.service
[Unit]
Description=SonarQube service
After=syslog.target network.target
[Service]
Type=simple
User=sonarqube
Group=sonarqube
PermissionsStartOnly=true
ExecStart=/usr/bin/nohup /usr/bin/java -Xms32m-Xmx32m-
Djava.net.preferIPv4Stack=true-jar /usr/local/sonarqube/lib/sonar-application-
8.9.2.46101.jar
#ExecStart=/usr/bin/nohup /usr/bin/java -Xms32m -Xmx32m -
Djava.net.preferIPv4Stack=true -jar /usr/local/sonarqube/lib/sonar-application-
7.9.6.jar
StandardOutput=syslog
LimitNOFILE=65536
LimitNPROC=4096
TimeoutStartSec=5
Restart=always
[Install]
WantedBy=multi-user.target
[root@SonarQube-Server ~]#systemctl daemon-reload
[root@SonarQube-Server ~]#systemctl enable --now sonarqube.service
[root@SonarQube-Server ~]#systemctl status sonarqube.service
4.3.5 登录到 Web 界面
用浏览器访问地址: http://SonarQube 服务器 IP:9000 新版默认必须登录,不支持匿名访问
默认用户名和密码都是 admin

首次登录必须修改admin用户的密码 注意: 新密码不能使用原密码


旧版默认可以匿名登录


点击有左上角 login 登录,默认用户名和密码都是admin

4.4 管理 SonarQube 服务器
4.4.1 安装中文支持
4.4.1.1 查看本地已安装插件
插件本地路径用于安装相关插件,比如: 中文插件,用于分析不同开发语言的对应的插件
#初始此目录没有插件文件
[root@SonarQube-Server ~]#ll /usr/local/sonarqube/extensions/plugins/
total 12
drwxr-xr-x 2 sonarqube sonarqube 4096 Jul 2706:27 ./
drwxr-xr-x 5 sonarqube sonarqube 4096 Oct 2409:59 ../
-rw-r--r--1 sonarqube sonarqube 737 Jul 2706:27 README.txt
4.4.1.2 安装中文语言插件
administration- Marketplace,在后面的搜索框搜索插件chinese,然后点install安装:
新版需要先理解风险,才能安装插件

安装完后,点 Restart Server


或者通过命令重新启动
[root@SonarQube-Server ~]#su - sonarqube
sonarqube@SonarQube-Server:~$ /usr/local/sonarqube/bin/linux-x86-64/sonar.sh
restart
Gracefully stopping SonarQube...
SonarQube was not running.
Starting SonarQube...
Started SonarQube.
查看到多了一个插件文件
[root@SonarQube-Server ~]#ls /usr/local/sonarqube/extensions/plugins/
README.txt sonar-l10n-zh-plugin-8.9.jar
如果上面方式安装失败,可以下载插件到目录 /usr/local/sonarqube/extensions/plugins/
[root@SonarQube-Server ~]#wget https://github.com/SonarQubeCommunity/sonar-l10n-
zh/releases/download/sonar-l10n-zh-plugin-1.29/sonar-l10n-zh-plugin-1.29.jar -P
/usr/local/sonarqube/extensions/plugins/

4.4.1.3 验证中文界面
重新登录 SonarQube


登录后变成中文

查看安装的插件

4.4.2 安装其他插件
Sonarquebe对代码的扫描都基于插件实现,因此要安装扫描的各种开发语言的插件
默认已安装 Java、Python、Go,Php,javaScript,Html 等语言对应的插件





插件可以在github上找到最新版本
https://github.com/SonarSource


4.4.3 权限管理
4.4.3.1 允许匿名访问
8.9.X 新版默认取消了匿名用户访问,可以在下面配置中打开匿名访问即关闭认证

关闭开关,允许匿名


旧版默认任何匿名用户都可以执行代码分析

#如果取消上面对勾,将禁止匿名用户执行分析,在执行下面代码分析时操作出现失败
[root@jenkins spring-boot-helloWorld]#/usr/local/sonar-scanner/bin/sonar-scanner
.......
INFO: Load project repositories
INFO: ------------------------------------------------------------------------
INFO: EXECUTION FAILURE
INFO: ------------------------------------------------------------------------
INFO: Total time: 5.005s
INFO: Final Memory: 13M/47M
INFO: ------------------------------------------------------------------------
ERROR: Error during SonarScanner execution
ERROR: You're not authorized to run analysis. Please contact the project
administrator.
ERROR:
ERROR: Re-run SonarScanner using the -X switch to enable full debug logging.
[root@jenkins spring-boot-helloWorld]#
构建时会出错

4.4.3.2 不允许匿名访问
如果不允许匿名访问,就需要给 Jenkins 创建相关的访问令牌


4.5 Jenkins 服务器部署扫描器 sonar-scanner
官方文档:
https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/

4.5.1 部署 sonar-scanner
sonarqube 通过调用扫描器sonar-scanner进行代码质量分析,即扫描器的具体工作就是扫描代码
下载地址:
https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/
https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/

下载和配置较新的版本
[root@jenkins-ubuntu ~]#cd /usr/local/src
# 新版
[root@jenkins-ubuntu src]#wget
https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-
cli-4.6.2.2472-linux.zip
[root@jenkins-ubuntu src]#unzip sonar-scanner-cli-4.6.2.2472-linux.zip
[root@jenkins-ubuntu src]#ln -s /usr/local/src/sonar-scanner-4.6.2.2472-linux/
/usr/local/sonar-scanner
# 旧版
#[root@jenkins-ubuntu src]#wget
https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-
cli-4.3.0.2102-linux.zip
#[root@jenkins-ubuntu src]#unzip sonar-scanner-cli-4.3.0.2102-linux.zip
#[root@jenkins-ubuntu src]#ln -s /usr/local/src/sonar-scanner-4.3.0.2102-linux/
/usr/local/sonar-scanner
# 创建软链接方便运行
[root@jenkins-ubuntu ~]#ln -s /usr/local/sonar-scanner/bin/sonar-scanner
/usr/bin/
#配置sonar-scanner连接sonarqube服务器
[root@jenkins-ubuntu ~]#vim /usr/local/sonar-scanner/conf/sonar-
scanner.properties
#指向sonarqube服务器的地址和端口
sonar.host.url=http://sonarqube.wang.org:9000
sonar.sourceEncoding=UTF-8
4.5.2 准备测试代码
测试代码下载
https://github.com/SonarSource/sonar-scanning-examples
范例:
#准备测试代码
[root@jenkins-ubuntu ~]#unzip sonar-examples-master.zip
[root@jenkins-ubuntu ~]#cd sonar-examples-master/
[root@jenkins-ubuntu sonar-examples-master]#pwd
/root/sonar-examples-master
[root@jenkins-ubuntu sonar-examples-master]#ls
plugins projects README.md
[root@jenkins-ubuntu sonar-examples-master]#cd projects/
[root@jenkins projects]#ls
ci-workaround-pom.xml languages multi-module tycho
[root@jenkins-ubuntu projects]#cd languages/
#支持多种语言
[root@jenkins-ubuntu languages]#ls
abap c cpp css flex groovy javascript objc pli python sonar-
project.properties vb6 web android cobol csharp erlang generic-coverage
java multi-language php plsql rpg swift vbnet xml
#以PHP为例
[root@jenkins-ubuntu ~]#cd sonar-examples-master/projects/languages/php/php-
sonar-runner
[root@jenkins-ubuntu php-sonar-runner]#pwd
/root/sonar-examples-master/projects/languages/php/php-sonar-runner
[root@jenkins-ubuntu php-sonar-runner]#ll
total 28
drwxr-xr-x 4 root root 4096 Mar 1412:06 ./
drwxr-xr-x 4 root root 4096 Jul 252016 ../
-rw-r--r--1 root root 453 Jul 252016 README.md
drwxr-xr-x 2 root root 4096 Mar 1412:07 .scannerwork/
-rw-r--r--1 root root 331 Jul 252016 sonar-project.properties
drwxr-xr-x 2 root root 4096 Jul 252016 src/
-rw-r--r--1 root root 272 Jul 252016 validation.txt
#以下为默认生成的配置文件
[root@jenkins-ubuntu php-sonar-runner]#cat sonar-project.properties
# Required metadata
sonar.projectKey=org.sonarqube:php-simple-sq-scanner #自定义项目唯一标识 key 名称
sonar.projectName=PHP :: Simple Project :: SonarQube Scanner #项目名称,此值会显示在
sonarqube的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 #编码格式
范例: Java 代码配置
[root@gitlab spring-boot-helloWorld]#cat sonar-project.properties
#项目的唯一标识
sonar.projectKey=sprint-boot-helloworld
#项目的名称,用于显示在 sonarqube web 界面
sonar.projectName=sprint-boot-helloworld
#项目版本
sonar.projectVersion=1.0
#项目源码所在目录
sonar.sources=.
#项目源码编译生成的二进制文件路径
sonar.java.binaries=.
#编程语言
sonar.language=java
#编码格式
sonar.sourceEncoding=UTF-8
4.5.3 在源代码目录执行扫描
在当前项目代码目录下即sonar-project.properties文件所在目录进行执行扫描,以下是扫描过程的提示信息,扫描的配置文件sonar-project.propertie每个项目都要有
[root@jenkins-ubuntu php-sonar-runner]#pwd
/root/sonar-examples-master/projects/languages/php/php-sonar-runner
[root@jenkins-ubuntu php-sonar-runner]#/usr/local/sonar-scanner/bin/sonar-
scanner
#在源码所有目录下执行上面命令,可以看到如下显示
#注意:默认8.9版本不允许匿名,需要打开允许匿名才能成功

范例: 扫描 Java
[root@jenkins spring-boot-helloWorld]#/usr/local/sonar-scanner/bin/sonar-scanner

4.5.4 SonarQube Web 界面验证扫描结果
根据上面的执行结果,复制上面的链接地址,可以看到下面的信息

可以查看到重新的代码块

范例: java 程序的扫描结果

4.6 Jenkins 和 SonarQube 集成实现代码扫描
4.6.1 Jenkins 和 SonarQube 集成说明

Jenkins借助于SonarQube Scanner插件将SonarQube提供的代码质量检查能力集成到pipeline上,从而确保质量阈检查失败时,能够避免继续进行后续的操作,例如发布等;
一般流程如下
-
Jenkins Pipeline启动
-
SonarQube Scanner分析代码,并将报告发送至SonarQubeServer
-
SonarQube Server分析代码检测的结果是否符合预定义的质量阈
-
SonarQube Server将通过(passed)或者失败(failed)的结果发送回Jenkins上的SonarQube
-
Scanner插件暴露的 Webhook
-
质量域相关的阶段成功通过或可选地失败时Jenkins pipeline继续后面的Stage,否则pipeline将终止
4.6.2 SonarQube 质量阈
质量阙是一组预定义的评估条件
- 代码质量扫描结果可满足这组条件时,项目才会被标记为“passed” 管理员也可以在SonarQube上按需自定义并调用质量阈

范例: 创建新的质量阈

设为默认


# 再次执行代码扫描
[root@jenkins spring-boot-helloWorld]#/usr/local/sonar-scanner/bin/sonar-scanner
如果不合格,会显示下面提示

4.6.3 Jenkins 通过 Shell 实现 sonar scanner 功能
[root@gitlab-ubuntu app1]#cd /data/
[root@gitlab-ubuntu data]#git clone -b develop
http://gitlab.wang.org/magedu/app1.git
[root@gitlab-ubuntu data]#ls
app1
[root@gitlab-ubuntu data]#cd app1
[root@gitlab-ubuntu app1]#ls
index.html
[root@gitlab-ubuntu app1]#vim sonar-project.properties
[root@gitlab-ubuntu app1]#cat sonar-project.properties
sonar.projectKey=job2-develop
sonar.projectName=job2-develop
sonar.projectVersion=2.0
sonar.sources=./
sonar.language=php
sonar.sourceEncoding=UTF-8
[root@gitlab-ubuntu app1]#vim index.html
[root@gitlab-ubuntu app1]#cat index.html
<h1>demo_app1 v20</h1>
[root@gitlab-ubuntu app1]#git add .
[root@gitlab-ubuntu app1]#git commit -m v20
[develop b66c729] v20
2 files changed, 7 insertions(+), 1 deletion(-)
create mode 100644 sonar-project.properties
[root@gitlab-ubuntu app1]#git push
Username for'http://gitlab.wang.org': wang
Password for'http://wang@gitlab.wang.org':
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 402 bytes | 402.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for develop, visit:
remote: http://gitlab.wang.org/magedu/app1/merge_requests/new?
merge_request%5Bsource_branch%5D=develop
remote:
To http://gitlab.wang.org/magedu/app1.git
c5ca637..b66c729 develop -> develop
登录 Jenkins 服务器,修改"执行shell“如下
cd$$WORKSPACE
/usr/local/sonar-scanner/bin/sonar-scanner
tar czvf /data/code.tar.gz *
scp /data/code.tar.gz 10.0.0.104:/data/tomcat/tomcat_appdir/
scp /data/code.tar.gz 10.0.0.105:/data/tomcat/tomcat_appdir/
ssh10.0.0.104 "systemctl stop tomcat && rm -rf
/data/tomcat/tomcat_webdir/myapp/* && cd /data/tomcat/tomcat_appdir && tar xf
code.tar.gz -C /data/tomcat/tomcat_webdir/myapp/ && systemctl start tomcat"
ssh10.0.0.105 "systemctl stop tomcat && rm -rf
/data/tomcat/tomcat_webdir/myapp/* && cd /data/tomcat/tomcat_appdir && tar xf
code.tar.gz -C /data/tomcat/tomcat_webdir/myapp/ && systemctl start tomcat"

立即构建,观察控制台输出结果

登录sonarqube网页,可以看到下信息

4.6.4 Jenkins 安装 SonarQube 插件实现代码扫描
配置Jenkins使用sonar-scanner进行代码质量扫描,并将结果报告给SonarQube Server的主要步骤如下
-
在 Jenkins上安装SonarQube插件
-
配置Jenkins对接到SonarQube Server
-
配置Jenkins的全局工具sonar-scanner
-
在SonarQube上添加回调Jenkins的Webhook
-
在Jenkins项目上调用sonar-scanner进行代码质量扫描通过SonarQube确认扫描结果的评估
4.6.4.1 Jenkins 安装 SonarQube 插件
Jenkins—系统管理--插件管理
安装插件 SonarQube Scanner

4.6.4.2 系统配置中添加 SonarQuebe Server 的地址和验证令牌
Jenkins—系统管理—系统设置--SonarQube servers--输入Name --SonarQube-Server
注意: Name 的大小敏感
4.6.4.2.1 SonarQube 服务器允许匿名访问

4.6.4.2.2 SonarQube服务器不允许匿名访问
如果sonarqube不允许匿名,则还需要添加认证,即前面4.4.3.2创建的令牌


4.6.4.3 Jenkins 添加 Sonar Scanner 扫描器
Jenkins--系统管理-全局工具配置
4.6.4.3.1 手动指定 sonar-scanner 在本地安装的绝对路径
/usr/local/sonar-scanner/

4.6.4.3.2 指定下载路径自动安装
注意:此方式以后用脚本调用sonar scanner的路径要和下面相匹配,如果使用相关插件,可以则不关注路径
https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/

4.6.4.3.3 自动从 Maven 仓库安装

4.6.4.4 在任务构建步骤中添加 Execute Sonarqube Scanner
选择项目---增加构建步骤---选择“Execute Sonarqube Scanner”,并将Execute Sonarqube Scanner 框,拖至执行shell 的前面,即先扫描再执行构建

4.6.4.5 配置项目进行扫描
注意: 必须在源码管理 source code Management 中指定 git仓库路径 ,不能由脚本进行git clone

构建--- Execute Sonarqube Scanner---Analysis properties,将配置文件的内容修改成如下格式
sonar.projectKey=${JOB_NAME}
sonar.projectName=${JOB_NAME}
sonar.sources=./
sonar.projectVersion=1.0 (可选)
sonar.language=php (可选)
sonar.sourceEncoding=UTF-8 (可选)
范例:
#项目的唯一标识
sonar.projectKey=sprint-boot-helloworld
#项目的名称,用于显示在 sonarqube web 界面
sonar.projectName=sprint-boot-helloworld
#项目版本
sonar.projectVersion=1.0
#项目源码所在目录
sonar.sources=.
#项目源码编译生成的二进制文件路径,必须添加,否则会scanner失败
sonar.java.binaries=.
#编程语言
sonar.language=java
#编码格式
sonar.sourceEncoding=UTF-8
范例: shell内容
[root@jenkins ~]#cat /data/jenkins/scripts/spring-boot-helloWorld-deploy-job.sh
#!/bin/bash
HOST_LIST="
10.0.0.8
10.0.0.18
"
mvn clean package -Dmaven.test.skip=true
for host in$HOST_LIST;do
ssh$host"pgrep java && killall java||true "
scp target/spring-boot-helloworld-*.jar $host:/data/tomcat/appdir/
ssh$host"java -jar /data/tomcat/appdir/spring-boot-helloworld-*.jar --
server.port=8888 "&
done

创建任务后可以看到下面出现三条曲线

4.6.4.6 构建项目并测试 sonar-scanner 是否生效
点击项目的立即构建,下图是执行成功的信息:

4.6.4.7 查看项目的构建历史

登录SonarQube网页,可以看到下面信息

4.7 Pipeline 集成 SonarQube 实现代码检测通知 Jenkins
实现当Sonarqube检测失败时,不会继续进行后面的构建编译等步骤
4.7.1 在 SonarQube 添加 Jenkins 的回调接口
在SonarQube上添加webhook(网络调用),以便于Jenkins通过SonarQube Quality Gate插件调用其"质量阈"信息,决定是否继续执行下面的构建步骤
配置 --- 网络调用 --- 创建

输入名称和下面 Jenkins的URL地址
注意: 密码防止攻击使用, 可以随意输入
http://jenkins.wang.org:8080/sonarqube-webhook


4.7.2 准备项目的 Jenkinsfile 文件
在项目所在的目录中准备Jenkinsfile文件
注意: 之后需要git commit 此文件
[root@dev spring-boot-helloWorld]#cat Jenkinsfile
pipeline {
agent any
stages {
stage("SonarQube analysis"){
steps {
//注意:下面的SonarQube-Server和系统配置SonarQube installations的Name必须一致,
大小写敏感
withSonarQubeEnv("SonarQube-Server"){
sh'mvn sonar:sonar'
}
}
}
stage("Quality Gate") {
steps {
//代码检测失败,将不再继续执行后面的任务,直接退出,报告返回的超时时长设为5分钟
timeout(time: 5,unit: 'MINUTES'){
waitForQualityGate abortPipeline: true
}
}
}
stage('Build') {
steps {
sh'mvn clean package -Dmaven.test.skip=true'
}
}
stage('Test') {
steps {
echo"Test"
}
}
stage('Deploy') {
steps {
echo"Deploy"
}
}
}
post {
always {
mail to:"29308620@qq.com",
subject:"Status of pipeline: ${currentBuild.fullDisplayName}",
body:"${env.BUILD_URL} has result ${currentBuild.result}"
}
}
}
4.7.3 准备项目目录中的 sonar-project.properties 文件
准备 sonar scanner 所需的项目目录中 sonar-project.properties 文件
注意: 之后需要git commit 此文件
[root@dev spring-boot-helloWorld]#cat sonar-project.properties
#项目的唯一标识
sonar.projectKey=sprint-boot-helloworld
#项目的名称,用于显示在 sonarqube web 界面
sonar.projectName=sprint-boot-helloworld
#项目版本
sonar.projectVersion=1.0
#项目源码所在目录
sonar.sources=.
#项目源码编译生成的二进制文件路径
sonar.java.binaries=.
#编程语言
sonar.language=java
#编码格式
sonar.sourceEncoding=UTF-8
4.7.4 创建 Pipeline 任务

4.7.5 执行成功构建


4.7.6 执行问题代码构建
4.7.6.1 构建问题代码
修改默认质量阈

4.7.6.2 查看结果





5 常见面试题
简述什么是版本控制系统(VCS)?
简述什么是 DevOps? 简述软件交付过程?

Kubernetes 快速入门
讲师:马永亮(马哥) http://www.magedu.com https://github.com/ikubernetes/


1 Kubernetes系统组件
Kubernetes集群的节点类型
-
由Master和Worker两类节点组成
-
Master:控制节点
-
Worker:工作节点
-

- 运行逻辑