[TOC]

0x00 前言简述

Jenkins 介绍

Q: 什么是Jenkins?

答: Jenkins 是一个开源持续集成的工具(CI&CD)由Java开发而成, 用于自动化各种任务,包括构建、测试和部署软件(自动化服务器); Jenkins 支持各种运行方式,可通过系统包、Docker 或者 通过一个独立的Java程序;
官方介绍 : 全球领先的开源自动化服务器,Jenkins 提供了数以百计的插件来支持构建、部署和自动化任何项目
官方标语 : “Build great things at any scale”-“建造伟大的事情以任何规模”

Tips :个人理解 Jenkins 是一个调度平台,本身不需要处理任何事情,而是通过众多的插件来完成所有的工作;

Q: 为什么要用Jenkins?

答: Jenkins的前身是Hudson, 是基于Java开发的一种持续集成工具,用于监控秩序重复的工作, 它是可以将各个开源的软件进行集成的调度平台,例如( Gitlab/SVN 、Maven、Sonarqube、Shell、钉钉通知、项目监控 )等;

Jenkins 发行线版本说明:

  • TLS 长期支持版本: 每12周从常规版本流中选择,作为该时间段的稳定版本。 每隔 4 周,我们会发布稳定版本,其中包括错误和安全修复反向移植。
  • 每周更新版本: 每周都会发布一个新版本,为用户和插件开发人员提供错误修复和功能。


Jenkins 特性

  • 开源的java语言开发持续集成工具,支持CI,CD;
  • 易于安装部署配置:可通过yum安装,或下载war包以及通过docker容器等快速实现安装部署,可方便web界面配置管理;
  • 消息通知及测试报告:集成RSS/E-mail通过RSS发布构建结果或当构建完成时通过e-mail通知,生成JUnit/TestNG测试报告;
  • 分布式构建:支持Jenkins能够让多台计算机一起构建/测试;
  • 文件识别:Jenkins能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等;
  • 丰富的插件支持:支持扩展插件,你可以开发适合自己团队使用的工具,如git,svn,maven,docker


Jenkins 应用场景

  • 1) 创建一个项目,手动构建,完成简单任务,比如拉取代码进行编译(持续集成)。
  • 2) 编译失败通知用户
  • 3) 参数化构建
  • 4) 代码改动自动触发构建或者定时触发构建
  • 5) 一个项目构建完成后自动调用另一个项目的构建,完成一连串任务
  • 6) 并发构建
  • 7) 集群化部署开发(CI/CD)


Jenkins Job 类型

  • 1) Freestyle project : 自由风格项目,主要的项目类型
  • 2) Maven project : maven项目专有,类似freestyle,更简单
  • 3) Multiconfigration project : 多配置项目,适合大量不同配置(环境、平台等)构建
  • 4) Pipeline : 流水线项目,适合使用pipeline 插件功能构建流水线任务,或者使用freestyle project不容易实现的负责任务
  • 5) Multibranch pipeline : 多分支流水线项目,根据SCM仓库中的分支创建多个pipeline项目

0x01 安装配置

安装方式
安装参考: https://www.jenkins.io/zh/doc/book/installing/

  • Windows(Jar 、War)、Linux(yum|rpm 、apt|dpkg)、Mac
  • Docker

PS : Jenkins通常作为一个独立的应用程序在其自己的流程中运行, 内置Java servlet 容器/应用程序服务器(Jetty)。

系统要求
最低推荐配置:

  • 256MB 可用内存
  • 1GB 可用磁盘空间(作为一个Docker容器运行jenkins的话推荐10GB)

小团队推荐的硬件配置:

  • 1 GB+ 可用内存
  • 50 GB+ 可用磁盘空间

软件配置: Java 8—​无论是Java运行时环境(JRE)还是Java开发工具包(JDK)都可以

Tips : 安装最低配置:不少于256M内存,不低于1G磁盘,JDK版本>=8(openjdk也可以)。

PS : Jenkins 依赖于 Java 环境, 如果是在不使用Docker安装Jenkins时就需要安装配置Java环境;

1
2
3
4
# Jenkins 版本与 Java版本依赖关系
2.164 (2019-02) and newer: Java 8 or Java 11
2.54 (2017-04) and newer: Java 8
1.612 (2015-05) and newer: Java 7


Ubuntu

Jenkins的Debian Package Repository,以自动化安装和升级。要使用此存储库,请先将键添加到系统:
Jenkins Debian Packages:https://pkg.jenkins.io/debian-stable/

官方安装:

1
2
3
4
5
6
7
8
# 添加  gpg key
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -

# 在 /etc/apt/sources.list 中添加以下条目 deb https://pkg.jenkins.io/debian-stable binary/
sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
# 更新您的本地包索引,然后最终安装Jenkins:
sudo apt-get update
sudo apt-get install jenkins

国内安装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Java 环境安装配置 jdk-8u211-linux-x64.tar.gz
# 下载地址: https://www.oracle.com/cn/java/technologies/javase-downloads.html
sudo mkdir /opt/app/ && cd $_
tar -zxvf jdk-8u211-linux-x64.tar.gz -C /usr/local/

# 环境变量设置(临时生效) set oracle jdk environment
ln -s /usr/local/jdk1.8.0_211/bin/java /usr/bin/java
export JAVA_HOME=/usr/local/jdk1.8.0_211 ## 这里要注意目录要换成自己解压的jdk 目录
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

# 环境安装测试
[email protected]:/usr/local/jdk1.8.0_211# java -version
# java version "1.8.0_211"
# Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
# Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)


# Jenkins 下载& 安装
sudo wget https://mirrors.aliyun.com/jenkins/debian-stable/jenkins_2.263.1_all.deb
sudo dpkg -i jenkins_2.263.1_all.deb

# 更新站点配置
sed -i "s#updates.jenkins.io#mirrors.tuna.tsinghua.edu.cn/jenkins/updates/#g" /var/lib/jenkins/hudson.model.UpdateCenter.xml

# 启动 Jenkins 并查看状态
systemctl restart jenkins
systemctl status jenkins
# ● jenkins.service - LSB: Start Jenkins at boot time
# Loaded: loaded (/etc/init.d/jenkins; generated)
# Active: active (exited) since Wed 2020-12-23 14:10:12 UTC; 6s ago
# Docs: man:systemd-sysv-generator(8)
# Process: 357567 ExecStart=/etc/init.d/jenkins start (code=exited, status=0/SUCCESS)

安装后设置向导:
参考地址: https://www.jenkins.io/zh/doc/book/installing/#setup-wizard

1
2
3
# Jenkins控制台日志显示可以获取密码的位置(在Jenkins主目录中)
cat /var/lib/jenkins/secrets/initialAdminPassword
# 23092528120a45488a73ff4e7565e06f
  • (2) 自定义jenkins插件
    解锁 Jenkins之后,在 Customize Jenkins 页面内, 您可以安装任何数量的有用插件作为您初始步骤的一部分。
    两个选项可以设置:
    • 安装推荐的插件 - 安装推荐的一组插件,这些插件基于最常见的用例.
    • 选择插件来安装 - 选择安装的插件集。当你第一次访问插件选择页面时,默认选择建议的插件。(新手首次搭建建议选择此项)
WeiyiGeek.选择安装的插件

WeiyiGeek.选择安装的插件

PS : 如果您不确定需要哪些插件,请选择安装建议的插件 。 您可以通过Jenkins中的Manage Jenkins > Manage Plugins页面在稍后的时间点安装(或删除)其他Jenkins插件 。

  • (3) 不安装任何插件进入插件列表点击右上角的x关闭窗口,显示如下页面则跳过了管理员用户密码重设;
WeiyiGeek.初始化成功页面

WeiyiGeek.初始化成功页面

PS : 一旦初始安装完成后,可通过插件管理器安装其他插件

  • (4) 进入 Jenkins 控制台安装成功,然后第一个管理员用户;
    点击 Dashboard -> admin -> Configure -> Password 进行管理员密码设置;
    从这时起,Jenkins用户界面只能通过提供有效的用户名和密码凭证来访问。

WeiyiGeek.Jenkins


Ubuntu 下 Jenkins 相关文件及其目录(目录结构)一览:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 配置文件
/etc/default/jenkins
# /etc/sysconfig/jenkins # CentOS

# 家目录&插件目录&构建工作目录
/var/lib/jenkins/
/var/lib/jenkins/config.xml # jenkins root configuration
/var/lib/jenkins/userContent # 该目录下的文件将在http://server/userContent/下提供
/var/lib/jenkins/plugins # 插件
/var/lib/jenkins/logs # 存放jenkins相关的日志
/var/lib/jenkins/fingerprints # 存储指纹记录
/var/lib/jenkins/secrets # 密码秘钥所在目录
/var/lib/jenkins/workspace # 各任务的构建工作目录
/var/lib/jenkins/jobs # 浏览器上面创建的任务都会存放在这里
+- [JOBNAME] # 每个作业Job的子目录
+- config.xml # (job configuration file)
+- workspace # (working directory for the version control system)
+- latest # (symbolic link to the last successful build)
+- builds
+- [BUILD_ID] # (for each build)
+- build.xml # (build result summary)
+- log # (log file)
+- changelog.xml # (change log)

# 启动文件 {start|stop|status|restart|force-reload}
/etc/init.d/jenkins

# systemd 管理的serice
/run/systemd/generator.late/jenkins.service
/run/systemd/generator.late/graphical.target.wants/jenkins.service
/run/systemd/generator.late/multi-user.target.wants/jenkins.service


文件内容&目录结构详细说明

  • 1.config.xml 核心配置文件: 包含了Jenkins的版本信息、权限认证规则、workspace目录定义、builds目录定义、视图信息等等。其他的 xml 文件是 Jekins 服务扩展功能的配置信息文件。

  • 2.plugins 插件目录: 已经安装的Jenkins插件都可以在里面找到对应的文件。每一个插件基本是由一个目录和一个与目录同名的文件配对组成。

  • 3.jobs 执行任务存储目录: 该目录是 Jenkins 管理的所有构建任务的配置细节、构建后的产物和数据。Jenkins 服务所有的 Job 都会在这个目录下,创建一个以 Job 名称命名的文件夹。
    job 任务的文件夹中存储的文件有:

    1
    2
    3
    4
    5
    6
    config.xml 任务的XML格式声明信息。
    nextBuildNumber 文件记录下次构建时的 buildNumber
    builds 目录存储此 Job 构建的历史。

    ~ $ ls /var/lib/jenkins/jobs/
    HelloWorld Kubernetes-jenkins-slave pineline-use-node
  • 4.workspace 工作空间目录: 包含了这个构建作业的源代码, Jenkins存放项目的工作空间。进入这个workspace目录,里面就是你之前创建的项目的目录。在构建过程中Jenkins会根据项目中配置的远程代码仓库的地址去拉取源码到项目目录中并在这里完成打包。之前我们在打包的脚本中用到的$WORKSPACE表示的就是workspace下对应项目的目录。

  • 5.tools 工具目录: Jenkins 服务设置安装 tools ,会安装在这个目录中。安装工具的方式是:【Manage Jenkins】 -> 【Global Tool Configuration】 页面。
  • 6.updates 更新目录: 用来存放可用的插件更新。

  • 7.users 用户信息目录: 存储用户的账号信息。

  • 8.nodes 节点目录: Jenkins 在配置了主从或者工作节点之后会在这里有相应的信息。

  • 9.userContent 用户生成的文件: 用于存储在 Jenkins 管理过程中生成的文件;比如使用Convert To Pipeline 插件可以将 JOB 转换成 Pipeline,生成的 Pipeline 的内容会以文件的形式存储在这个文件夹中。

  • 10.fingerprints 文件指纹目录: 文件指纹(fingerprints)是一个简单的MD5校验和。Jenkins维护了一个md5sum数据库,用于文件指纹校验。对于每个md5sum,Jenkins记录了哪些项目的哪些构建使用了他。在每次构建运行和文件被采集指纹时这个数据库会更新。为了避免过多的磁盘使用,Jenkins不存储实际的文件。相反它只存储md5sum和它的使用记录。

  • 11.logs 日志目录: 用于存储 Jenkins 服务的日志,主要是事件日志和工作日志。

  • 12.war 目录: 如果是以WAR包形式运行的Jenkins,该目录下存放的是解压后的WAR包。

  • 13.Jenkins 服务另外的文件目录:

    1
    2
    3
    4
    5
    secrets
    init.groovy.d
    workflow-libs
    scriptler
    config-history

Tips: jenkins存放数据不依靠数据库所以在移植时只需要拷贝整个程序主目录即可,需要注意的是jobs和plugins目录比较重要


Docker & Kubernetes 安装

请参考后续的 <(2) 集群搭建Jenkins Master 节点> 章节的文章。


0x02 基础知识

Jenkins 参数构建类型

主要缺省参数类型如下几类:

  • Boolean 参数
  • Choice 参数 (常用)
  • String 参数 (常用)
  • File 参数
  • 密码 参数
  • 凭据 参数
  • 其他 参数
  • 运行时 参数

在参数化构建过程 -> 构建参数添加 -> 构建参数的变量 ->通过 $paramater 或者 ${paramater}的形式使用

WeiyiGeek.构建参数

WeiyiGeek.构建参数

Tips : 环境变量生效的顺序全局环境变量 < slave配置环境变量 < JOB参数 < JOB injected环境变量

官网地址: https://www.jenkins.io/
官方文档: https://www.jenkins.io/zh/doc/


Jenkins 并发构建

描述: 我们创建Job可以进行并发构建,每个并发构建使用单独的workspace,默认是<workspace path>@<num>

WeiyiGeek.并发构建

WeiyiGeek.并发构建

Tips : slave 也可以进行并发构建前提是需要Node and Label parameter plugin插件,并且需要配置node类型参数;


Jenkins 自动化构建

常见的triggers几种:

  • Build periodically : 设定类似cron周期性时间触发构建
  • poll SCM : 设定类似 cron 周期性时间触发检查代码变化,只有代码变动时才触发构建
  • Hooks : 用过SVN的都知道钩子 Github hooks / Gitlab hooks
  • Events : Gerrit event
WeiyiGeek.triggers

WeiyiGeek.triggers

build periodically
描述: H 代表 jenkins 自己分配时间不去指定客观时间, 注意一般都是Jenkins根据监控资源利用率算法分配的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# * * * * *
# 第一颗*表示分钟,取值0~59
# 第二颗*表示小时,取值0~23
# 第三颗*表示一个月的第几天,取值1~31
# 第四颗*表示第几月,取值1~12
# 第五颗*表示一周中的第几天,取值0~7,其中0和7代表的都是周日

1.每30分钟构建一次:H/30 * * * *

2.每2个小时构建一次 H H/2 * * *

3.每天早上8点构建一次: 0 8 * * *

4.每天的8点,12点,22点,一天构建3次 0 8,12,22 * * *

# 多个时间点,中间用逗号隔开


Poll SCM
描述: 他会定时检查源码变更(根据SCM软件的版本号),如果有更新就checkout最新code下来然后执行构建动作;

比如: 你可以如果我想每隔30分钟检查一次源码变化有变化就执行;

1
H/30 * * * *


Jenkins 上下游构建

触发下游构建:

  • 1) 其他项目构建后触发: “Build other projects” under “Post build actions” -> 输入项目名称
  • 2) 利用 Parameterized Trigger 插件 参数化构建 -> 在构建后操作步骤中 -> Trigger Parameterized build on other peoject -> Restrict matrix execuson to a subset
WeiyiGeek.上下游构建

WeiyiGeek.上下游构建


Jenkins 调用API

描述: Jenkins 服务提供了很多类型的API;因为工作需要这里只记录一下执行job的API使用CURL调用的方式。

Jenkins API 介绍

  • 1.Jenkins API 从级别上分类

    1
    2
    3
    * 站点 API:创建Job、复制Job、Build 队列、重启Jenkins等
    * Job API:修改Job、删除Job、获取 Build 信息、Build Job、禁用Job、启用Job
    * Build Job: 根据 Build Number 获取Build 信息,获取Build 控制台的输出日志
  • 2.传输数据格式: POST 传输数据支持的格式有XML,JSON,PYTHON

  • 3.安全处理: 可以找到一些开发语言编写的API封装包,结合到自己的脚本中,提高开发效率。

    1
    2
    * CSRF 跨域攻击保护:可以在全局安全中设置。
    * 用户验证设置:可以使用用户的密码,也可以为用户创建token。

CURL 调用 API 执行 Job 实例:

1
2
3
4
# Curl Api 调用
CURL -X POST ${JOB_URI}
--user ${user_name}:${user_password}|${user_token}
--data-urlencode json="{\"parameter\":${JSON_DATA},\"statusCode\":\"303\",\"redirectTo\":\".\"}"

参数解析:

  • JOB_URL: 就是Job 的访问URL地址。在Job 页面中点击”Build with Parameters”就可以获取到地址。一般以”build?delay=0sec“结尾; 示例: http://192.168.1.1/job/HelloWorld/build?delay=0sec
  • user_name,user_password,user_token 用户验证信息
  • JSON_DATA:Job 运行时,需要传递的参数,由Json 结构封装;示例:[{\"name\":\"branchName\",\"value\":\"origin/dev\"},{\"name\":\"projectName\",\"value\":\"helloworld\"}]

0x03 基础配置

视图管理

描述: 当Job创建数量达到一定时我们需要在Jenkins中建立视图(分类),可以帮助我们快速找到某个所需Job;
实际上Job的视图类似于我们电脑上的文件夹可以通过一些过滤规则,将已经创建好的Job过滤到视图之中,也可以在视图中直接创建我们的Job;

我们可以采用View或者directory文件两种方式进行管理:

  • views - 视图方式
    1
    2
    views视图更加灵活,不改变job的路径
    views有多种形式、层级、看板,流水线等多样化
  • directory - 文件夹方式 (名称空间隔离)
    1
    2
    3
    文件夹适合多个团队共用Jenkins
    性能更好,执行速度更快
    支持RBAC权限管理

两则异同说明: 文件夹创建一个可以嵌套存储的容器利用它可以进行分组,而视图仅仅是一个过滤器,其次文件夹则是一个独立的命名空间,因此你可以有多个相同名称的的内容,只要它们在不同的文件夹里即可。


views - 视图方式
创建流程:

  • Step 1.我的视图 -> 点击所有旁边 + 号 -> 设置视图名称 -> 选择三种类型列表视图/包括全局视图/我的视图
    列表视图 : 显示简单列表。你可以从中选择任务来显示在某个视图中
    包括全局视图 : Shows the content of a global view.
    我的视图 : 该视图自动显示当前用户有权限访问的任务

  • Step 2.此处设置列表视图为例 -> 选择任务列表 -> 增加或者删除指定显示列

WeiyiGeek.views

WeiyiGeek.views


directory - 文件夹方式
创建流程:

  • Step 1.创建Job -> 选择文件夹 -> 输入任务名称directory-test
  • Step 2.在directory-test文件夹下 -> 可以继续创建视图(+ ) -> 选择(列表视图/包括全局视图/我的视图)
WeiyiGeek.directory

WeiyiGeek.directory


插件管理

(1) 插件安装加速
Q: 在安装插件时如何进行配置安装加速?

答: 选择国内清华大学的Jenkins插件更新源 https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

配置位置: Dashboard > Plugin Manager > Advanced > Update Site

WeiyiGeek.插件安装加速

WeiyiGeek.插件安装加速


(2)插件安装的几种方式

  • Step 1.采用插件更新源搜索进行在线安装,例如下面对Jenkins进行汉化插件的安装, 搜索 Localization: Chinese (Simplified) 插件安装即可;
    WeiyiGeek.Jenkins 汉化插件安装

    WeiyiGeek.Jenkins 汉化插件安装

当安装插件安装完成时候可以选择重启 Jenkins 或 跳转到首页, 此处我重启 Jenkins 如下图所示汉化成功;

WeiyiGeek.Jenkins 汉化界面

WeiyiGeek.Jenkins 汉化界面

WeiyiGeek.Jenkins git 插件安装

WeiyiGeek.Jenkins git 插件安装

  • Step 3.导入之前服务器已安装的插件进行离线安装;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # (1) Jenkins 已安装的插件目录
    /var/lib/jenkins/plugins$ ls
    # apache-httpcomponents-client-4-api display-url-api jdk-tool localization-zh-cn script-security trilead-api
    # apache-httpcomponents-client-4-api.jpi display-url-api.jpi jdk-tool.jpi localization-zh-cn.jpi script-security.jpi trilead-api.jpi
    # command-launcher git jsch mailer ssh-credentials workflow-scm-step
    # command-launcher.jpi git-client jsch.jpi mailer.jpi ssh-credentials.jpi workflow-scm-step.jpi
    # credentials git-client.jpi localization-support scm-api structs workflow-step-api
    # credentials.jpi git.jpi localization-support.jpi scm-api.jpi structs.jpi workflow-step-api.jpi


    # (2) 打包插件目录并上传到另外一台同版本的Jenkins服务器(PS:不同版本间可能会出现插件不兼容的情况)
    tar -zcvf jenkins_2.263.1_plugins.tar.gz /var/lib/jenkins/plugins

    # (3) 解压插件目录并进行所属者组修改
    tar -zxvf jenkins_2.263.1_plugins.tar.gz
    chown -R jenkins:jenkins /var/lib/jenkins/plugins

    # (4) 启动 Jenkins 服务
    systemctl stop jenkins
    systemctl start jenkins

    # (5) 启动 日志 查看
    tail -f /var/log/jenkins/jenkins.log


升级&迁移

描述: 在使用 Jenkins 时候显示新版本的 Jenkins (2.272) 可以下载 (变更记录),正好可以实践一哈Jenkins的升级&迁移。
PS : 如果是是在生产环境中升级建议慎重,可能会导致插件和升级版本不兼容的情况;

操作流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# (1) 下载更新包 
wget https://updates.jenkins.io/download/war/2.272/jenkins.war

# (2) 停止 Jenkins 服务
jenkins:/usr/share/jenkins# systemctl stop jenkins && ls
# jenkins.war

# (3) 备份上一个版本
jenkins:/usr/share/jenkins# mv jenkins.war jenkins.war.2.263.1.bak
jenkins:/usr/share/jenkins# cp /home/weiyigeek/jenkins.war jenkins.war
jenkins:/usr/share/jenkins# ls -alh
# -rw-r--r-- 1 root root 67M Dec 24 02:38 jenkins.war
# -rw-r--r-- 1 root root 65M Dec 2 13:56 jenkins.war.2.263.1.bak

# (4) 启动 Jenkins 服务
jenkins:/usr/share/jenkins# systemctl start jenkins
jenkins:/usr/share/jenkins# systemctl status jenkins
# ● jenkins.service - LSB: Start Jenkins at boot time
# Loaded: loaded (/etc/init.d/jenkins; generated)
# Active: active (exited) since Thu 2020-12-24 02:38:50 UTC; 4s ago
# Docs: man:systemd-sysv-generator(8)
# Process: 448375 ExecStart=/etc/init.d/jenkins start (code=exited, status=0/SUCCESS)

# Dec 24 02:38:48 gitlab systemd[1]: Starting LSB: Start Jenkins at boot time...
# Dec 24 02:38:48 gitlab jenkins[448375]: Correct java version found
# Dec 24 02:38:48 gitlab jenkins[448375]: * Starting Jenkins Automation Server jenkins
# Dec 24 02:38:48 gitlab su[448432]: (to jenkins) root on none
# Dec 24 02:38:48 gitlab su[448432]: pam_unix(su-l:session): session opened for user jenkins by (uid=0)
# Dec 24 02:38:49 gitlab su[448432]: pam_unix(su-l:session): session closed for user jenkins
# Dec 24 02:38:50 gitlab jenkins[448375]: ...done.
# Dec 24 02:38:50 gitlab systemd[1]: Started LSB: Start Jenkins at boot time.

# (5) 访问 Jenkins UI 界面验证升级版本
http://jenkins.weiyigeek.top:8080/about/

WeiyiGeek.Jenkins UI

WeiyiGeek.Jenkins UI


权限管理

描述: 由于jenkins默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,我们使用Role-based Authorization Strategy插件,安装请参考前面插件管理章节。

插件功能特点:

  • 按角色分权限
  • 按项目分权限


  • Step 1.插件安装后我们先启用该插件管理Jenkins权限 -> 面板 -> 全局安全配置(Global Security)-> 授权策略 -> 找到并选中 Role-Based Strategy -> 然后应用保存 。

  • Step 2.管理Jenkins -> 安全 -> Manage and Assign Roles -> 可以进行角色权限管理与分配 -> 此处添加一个test角色并设置其权限 -> 应用 -> 保存;
    ·

  • Step 3.Assign Roles -> Global roles(按角色)、Item roles(按项目)、Node roles(按节点) -> 用户添加(同时您需要在Jenkins用户中新增一个该用户) -> 保存应用
    • 添加用户和组。默认情况下用户/组名是区分大小写的,因此它需要与您在Configure Global Security->Access Control->Security Realm下的用户/组定义匹配。
WeiyiGeek.jenkins权限管理

WeiyiGeek.jenkins权限管理


0x04 基础使用

HelloWorld 自由风格软件项目

Q: Jenkins Free Style 基本使用?
目的: 构建一个自由风格的软件项目, 这是Jenkins的主要功能Jenkins将会结合任何SCM和任何构建系统来构建你的项目, 甚至可以构建软件以外的系统.

操作流程:

Step 1.项目创建

(1) 面板 -> 新建一个任务 -> 任务名称 freestyle-helloworld -> 保存
(2) Dashboard -> 项目名称 freestyle-helloworld -> General

1
2
3
# 重要的配置项
丢弃旧的构建:(保持构建的天数 / 保持构建的最大个数)
参数化构建过程: 比如添加的环境变量或者API密钥等等

(3) Dashboard -> 项目名称 freestyle-helloworld > 构建 > 执行 Shell 命令

1
2
echo "FreeStyle - HelloWorld"
touch hello-world.txt

WeiyiGeek.自由风格的软件项目

WeiyiGeek.自由风格的软件项目


Step 2.工程 freestyle-helloworld 构建与控制台输出查看;

WeiyiGeek.工程构建与控制台输出

WeiyiGeek.工程构建与控制台输出

PS : 如果是蓝色圆点表示构建成功, 如果是红色圆点表示构建失败!


Step 3.构建后的工作区存放目录

1
2
3
jenkins:/var/lib/jenkins/workspace/freestyle-helloworld$ ls
# hello-world.txt
jenkins:/var/lib/jenkins/workspace/freestyle-helloworld$ cat hello-world.txt


Gitlab 集成配置与实践

简单说明:
Q: Jenkins 为啥要集成Gitlab?

答:由于我们需要依托于Jenkins将Gitlab上的项目获取至本地,为后续网站的代码发布工作做好准备;

Q: Jenkins 如何集成Gitlab?

答: 由于Jenkins 只是一个调度平台,所以需要安装和Gitlab相关的插件即可完成集成;

Jenkins 与 Gitlab 集成思路

  • 1.开发提交代码 至 Gitlab

  • 2.Jenkins 安装 Gitlab 所需插件

1
2
3
4
5
6
Credentials Plugin (2.3.14) - This plugin allows you to store credentials in Jenkins.
Git client plugin (3.6.0) - Utility plugin for Git support in Jenkins
Git plugin (4.5.0) - This plugin integrates Git with Jenkins.
Gitlab Authentication plugin (1.10) - This is the an authentication plugin using gitlab OAuth.
Gitlab Hook Plugin (1.4.2) - Enables Gitlab web hooks to be used to trigger SMC polling on Gitlab projects
GitLab Plugin (1.5.13) - This plugin allows GitLab to trigger Jenkins builds and display their results in the GitLab UI.
WeiyiGeek.Gitlab关联插件

WeiyiGeek.Gitlab关联插件

  • 3.Jenkins 创建 FreeStyle 项目,然后配置Gitlab仓库对应的地址;


操作流程:

  • Step 1.首先需要将我们所用的项目代码推送到Gitlab(此处假设您已安装Gitlab)之中;

(1) 管理中心 -> 群组 -> 新建群组 -> 完善信息 -> 创建群组
(2) 管理中心 -> 项目 -> 创建项目 -> 完善仓库信息 -> 创建项目
(3) 推送现有文件夹到Gitlab之中

1
2
3
4
5
6
7
8
9
10
cd existing_folder
git init
git remote add origin http://gitlab.weiyigeek.top/ci-cd/blog.git
git add .
git commit -m "Initial commit"
git push -u origin master
# remote: Resolving deltas: 100% (829/829), done.
# To http://gitlab.weiyigeek.top/ci-cd/blog.git
# * [new branch] master -> master
# Branch 'master' set up to track remote branch 'master' from 'origin'.
WeiyiGeek.gitlab

WeiyiGeek.gitlab

  • Step 2.此处假设您已经按照上面Gitlab 集成配置安装了相应的插件, 并且配置好gitlab域名访问的解析记录;
1
2
3
4
5
# 此处由于没有自己搭建DNS,则将其写入到Jenkins 服务器的hosts文件中进行相应的IP与域名绑定
cat /etc/hosts
# 127.0.0.1 localhost
# 127.0.1.1 gitlab
# 10.10.107.201 gitlab.weiyigeek.top
  • Step 3.Jenkins 创建 FreeStyle 项目,然后配置Gitlab仓库对应的地址(ssh 的方式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# (1) 在Gitlab中添加当前机器ssh密钥(此处以Jenkins用户为例)
[email protected]:~$ssh-keygen -t ed25519 -C "[email protected]"
~$ ls ~/.ssh/id_ed25519
# id_ed25519 id_ed25519.pub

# (2) 添加公钥到gitlab中
# > 用户设置 -> SSH Keys -> jenkins-CI
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINFb2ALOnOpePb7e/tss4/ZKxNHb3srh7NXntW5jAWSf [email protected]

# (3) 主机认证指纹绑定
[email protected]:~$ git ls-remote -h -- [email protected]:ci-cd/blog.git HEAD
# The authenticity of host 'gitlab.weiyigeek.top (10.10.107.201)' can't be established.
# ECDSA key fingerprint is SHA256:cmG5Ces+96qG9EEaU1b/tJuTR1re7XDXUU4jg7asna4.
# Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
WeiyiGeek.SSH Keys

WeiyiGeek.SSH Keys

  • Step 4.Jenkins > FreeStyle 项目 > 源码管理 > Git > Repositories 设置 > Credentials 设置
    PS : 如果是非Jenkins用户下公钥对Gitlab该项目有访问权限时,可以通过 Credentials 添加其认证的密钥即可;
1
2
3
4
5
6
7
8
9
10
11
# (1) Weiyigeek 用户密钥 (此时假设Gitlab已经添加该公钥)
[email protected]:~$ cat /home/weiyigeek/.ssh/id_ed25519
# -----BEGIN OPENSSH PRIVATE KEY-----
# b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
# QyNTUxOQAAACAIxH1a4EivkJOSAXqd6LUE8tUvRfgPwwn1Erb7r728cwAAAJgANcy8ADXM
# vAAAAAtzc2gtZWQyNTUxOQAAACAIxH1a4EivkJOSAXqd6LUE8tUvRfgPwwn1Erb7r728cw
# AAAECLw4Wnle7Md7fc5NQN6EohejUx0XMHKfdYXejLAw2/NwjEfVrgSK+Qk5IBep3otQTy
# 1S9F+A/DCfUStvuvvbxzAAAAFG1hc3RlckB3ZWl5aWdlZWsudG9wAQ==
# -----END OPENSSH PRIVATE KEY-----

# (2) 进行 Credentials 相应的设置
WeiyiGeek.Weiyigeek 用户密钥

WeiyiGeek.Weiyigeek 用户密钥

  • Step 5.首先手动实现设置NFS共享存储以及 Kubernetes 部署 StatefulSet 资源清单,通过Nginx访问我们的blog;
    基础配置:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # (1) NFS 服务器配置
    [email protected]$ showmount -e
    # /nfs/data4 *
    /nfs/data4# ls -alh /nfs/
    # drwxrwxrwx 2 weiyigeek weiyigeek 4.0K Nov 19 13:27 data4
    /nfs/data4# mkdir /nfs/data4/tags/
    /nfs/data4# ln -s /nfs/data4/tags/ /nfs/data4/web
    /nfs/data4# chown -R nobody:weiyigeek /nfs/data4/

    # (2) Node 1 && Node 2
    sudo mkdir -pv /nfs/data4/
    sudo chown -R weiyigeek:weiyigeek /nfs/data4/
    sudo mount.nfs -r 10.10.107.202:/nfs/data4/ /nfs/data4/
    k8s-node-4:/nfs/data4$ ls -alh # 权限查看
    # total 12K
    # drwxrwxrwx 3 weiyigeek weiyigeek 4.0K Dec 24 15:44 .
    # drwxr-xr-x 3 root root 4.0K Dec 24 15:47 ..
    # drwxr-xr-x 2 weiyigeek weiyigeek 4.0K Dec 24 15:44 tags
    # lrwxrwxrwx 1 weiyigeek weiyigeek 16 Dec 24 15:44 web -> /nfs/data4/tags/

资源清单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
cat > jenkins-gitlab-ci.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
name: deploy-blog-svc
spec:
type: NodePort # Service 类型
selector:
app: blog-html # 【注意】与deployment资源控制器创建的Pod标签进行绑定;
release: stabel # Service 服务发现不能缺少Pod标签,有了Pod标签才能与之SVC对应
ports: # 映射端口
- name: http
port: 80 # cluster 访问端口
targetPort: 80 # Pod 容器内的服务端口
nodePort: 30088
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: deploy-blog-html
spec:
serviceName: "deploy-blog-svc"
replicas: 3 # 副本数
selector: # 选择器
matchLabels:
app: blog-html # 匹配的Pod标签非常重要
release: stabel
template:
metadata:
labels:
app: blog-html # 模板标签
release: stabel
spec:
volumes: # 关键点
- name: web
hostPath: # 采用hostPath卷
type: DirectoryOrCreate # 卷类型DirectoryOrCreate: 如果子节点上没有该目录便会进行创建
path: /nfs/data4/web # 各主机节点上已存在的目录此处是NFS共享
- name: timezone # 容器时区设置
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
containers:
- name: blog-html
image: harbor.weiyigeek.top/test/nginx:v3.0 # 拉取的镜像
imagePullPolicy: IfNotPresent
ports:
- name: http # 此端口在服务中的名称
containerPort: 80 # 容器暴露的端口
volumeMounts: # 挂载指定卷目录
- name: web
mountPath: /usr/share/nginx/html
- name: logs
mountPath: /var/log/nginx
- name: timezone
mountPath: /usr/share/zoneinfo/Asia/Shanghai
volumeClaimTemplates: # 卷的体积要求模板此处采用StorageClass存储类
- metadata: # 根据模板自动创建PV与PVC并且进行一一对应绑定;
name: logs
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: managed-nfs-storage # StorageClass存储类
resources:
requests:
storage: 1Gi
EOF

部署资源清单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
~/K8s/Day12$ kubectl apply -f jenkins-gitlab-ci.yaml
service/deploy-blog-svc unchanged
statefulset.apps/deploy-blog-html configured

~/K8s/Day12$ kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
deploy-blog-svc NodePort 10.104.74.36 <none> 80:30088/TCP 5m9s app=blog-html,release=stabel
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 49d <none>

~/K8s/Day12$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-blog-html-0 1/1 Running 0 72s 10.244.0.193 Master
deploy-blog-html-1 1/1 Running 0 57s 10.244.1.182 k8s-node-4
deploy-blog-html-2 1/1 Running 0 49s 10.244.2.84 k8s-node-5

效果查看:

1
2
curl http://10.10.107.202:30088/host.html
# Hostname: deploy-blog-html-0 ,Image Version: 3.0, Nginx Version: 1.19.4

  • Step 6.采用Tag方式发布和回退项目

Q: 为什么要让项目支持Tag版本方式上线?

答: 采用 Tag 的方式可以直观的知道我们部署的项目版本,同时也便于进行回退;
比如: 第一次上线v1.1第二次上线v1.2,如果此时上线的v1.2出现文件,那么我们可以快速回退至上一个版本v1.1;

使用Tag方式发布与回退思路:

1.开发如果需要发布新版本,必须将当前版本打上一个标签。
2.Jenkins需要让其脚本支持传参,比如用户传递v1.1则拉取项目的v1.1标签。


实践操作:

(1) 首先需要安装 Git Parameter 插件(增加了从项目中配置的git存储库中选择分支、标记或修订的能力。),然后配置Jenkins参数化构建过程,让用户在构建时选择对应的Tag版本;
丢弃旧的构建 > 保持构建的最大个数 为 10 个
参数化构建过程 > Git 参数 > git_version (变量) -> 参数类型 Tags -> 默认值 (origin/master) -> 排序方式 (DESCENDING SMART) 倒序 防止 Tags 顺序乱;
选项参数 (选择) > deploy_option (变量) -> 选项 deploy|rollback
源码管理 > Git > Repository URL:[email protected]:ci-cd/blog.git > Credentials (密钥认证) -> 分支机构建设 (指定分支(为空时代表any))-> 引入 ${git_version} 变量
构建 > 执行shell > /bin/sh -x /tmp/script/blog-script.sh
应用 > 保存

WeiyiGeek.jenkins项目创建

WeiyiGeek.jenkins项目创建

(2) 部署和回退脚本以及自动化发布重复构建的问题处理编写

touch /tmp/script/blog-script.sh && chmod a+x $_

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
# Description: Jenkins CI & Kubernetes & Gitlab -> Deploy or Rollback Blog HTML
DATE=$(date +%Y%m%d-%H%M%S)
TAG_PATH="/nfs/data4/tags"
WEB_PATH="/nfs/data4/web"
WEB_DIR="blog-${DATE}-${git_version}"
K8S_MATER="[email protected]"
K8S_MATER_PORT="20211"


# 部署
deploy () {
# 1.打包工作目录中的项目
cd ${WORKSPACE}/ && \
tar -zcf /tmp/${WEB_DIR}.tar.gz ./*

# 2.上传打包的项目到master之中
scp -P ${K8S_MATER_PORT} /tmp/${WEB_DIR}.tar.gz [email protected]:${TAG_PATH}

# 3.解压&软链接
ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "mkdir -p ${TAG_PATH}/${WEB_DIR} && \
tar -xf ${TAG_PATH}/${WEB_DIR}.tar.gz -C ${TAG_PATH}/${WEB_DIR} && \
rm -rf ${WEB_PATH} && \
ln -s ${TAG_PATH}/${WEB_DIR} ${WEB_PATH} && \
kubectl delete pod -l app=blog-html"
}

# 回退
rollback () {
Previous_Version=$(ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "find ${TAG_PATH} -maxdepth 1 -type d -name blog-*-${git_version}")
ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "rm -rf ${WEB_PATH} && \
ln -s ${Previous_Version} ${WEB_PATH} && \
kubectl delete pod -l app=blog-html"
}


# 部署 & 回退 入口(坑-==两边没有空格)
if [[ "${deploy_option}" = "deploy" ]]; then
# 坑 (防止字符串为空)
if [[ "v${GIT_COMMIT}" = "v${GIT_PREVIOUS_SUCCESSFUL_COMMIT}" ]];then
echo -e "您已经部署过 ${git_version} 版本"
exit 1
else
deploy
fi
elif [[ "${deploy_option}" = "rollback" ]];then
rollback
else
exit 127
fi

(3) Jenkins 服务器 与 Kubernetes Master 机器中的普通用户进行 ssh 公钥认证登录;

1
2
3
4
5
6
7
8
9
# copy 公钥 到 对端主机
ssh-copy-id -p 20211 [email protected]
# /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/var/lib/jenkins/.ssh/id_ed25519.pub"
# authorized only. All activity will be monitored and reported.
# [email protected]'s password:

# Number of key(s) added: 1

# Now try logging into the machine, with: "ssh -p '20211' '[email protected]'" and check to make sure that only the key(s) you wanted were added.

(4) 为我们的Blog打三个Tag并验证构建脚本

1
2
3
4
5
6
7
8
9
10
11
12
$ cd ~/workspace/freestyle-blog
jenkins:~/workspace/freestyle-blog$ git config --global user.email "[email protected]"
jenkins:~/workspace/freestyle-blog$ git config --global user.name "Weiyigeek"
vim index.html
git add .
git commit -m "v1.1"
git tag v1.1 -m "Jenkins CI test - v1.1"
git push origin HEAD:master
git push origin v1.1
# Total 0 (delta 0), reused 0 (delta 0)
# To gitlab.weiyigeek.top:ci-cd/blog.git
# * [new tag] v1.1 -> v1.1

(5) 进行项目构建 -> Build With Paramters 查看 部署的版本以及是部署还是回退 -> 如下图所示拉取的指定 Tags ;

WeiyiGeek.项目构建

WeiyiGeek.项目构建

(6) 项目构建部署验证 访问http://10.10.107.202:30088/博客地址

1
2
3
4
5
6
7
8
9
10
Built Branches
v1.3: Build #4 of Revision 4f80504ee142cb9866e4a0988cdc1e1693cfd7aa (v1.3)
v1.2: Build #3 of Revision 4e1dd6eded12d7cad3740d2461c3e784ad712632 (v1.2)
v1.1: Build #2 of Revision cd2d5778292ff2cbb7d4ac1b82c684223a38761b (v1.1)

# 如果已经部署过该项目则显示:
# + '[' deploy==deploy ']'
# + [[ v4f80504ee142cb9866e4a0988cdc1e1693cfd7aa = \v\4\f\8\0\5\0\4\e\e\1\4\2\c\b\9\8\6\6\e\4\a\0\9\8\8\c\d\c\1\e\1\6\9\3\c\f\d\7\a\a ]]
# + echo -e '您已经部署过 v1.3 版本'
# 您已经部署过 v1.3 版本
WeiyiGeek.项目构建部署验证

WeiyiGeek.项目构建部署验证

(6) 项目回退验证 > 请选择您要部署的RELEASE版本v1.1, 然后选择部署或是回退;

WeiyiGeek.项目回退验证

WeiyiGeek.项目回退验证


Maven 集成配置与实践

基本概述:
Q: 什么是Java项目?

答:简单来说就是使用Java编写的代码,我们将其称为Java项目;

Q: 为什么Java项目需要使用Maven编译?

答: 由于Java编写的Web服务代码是无法直接在服务器上运行,需要使用Maven工具进行打包;
简单理解: Java 源代码就像汽车的一堆散件,必须经过工厂的组装才能完成一辆完整的汽车,这里组装汽车可以理解是 Maven 编译过程;

Q: 在实现自动化构建Java项目时,先实现手动构建Java项目;

答: 因为想要实现自动化发布代码,就必须手动进行一次构建,既是熟悉过程又是优化我们的部署脚本;
大致流程: 源码 -> gitlab -> Maven 手动构建 -> 最后推送构建 -> 发布;

1
2
3
4
# Maven 拉取 Jar 的几种途径
-> 国外 Maven Jar 服务器
Gitlab -> Maven -> 国内 Maven Jar 镜像服务器
-> 企业 内部 Maven Jar 私服服务器 (可以双向同步)


自动部署 Java 项目至 kubernetes 集群流程步骤:

  • (1) Jenkins 安装 Maven Integration 插件,使Jenkins支持Maven项目的构建
  • (2) Jenkins 配置 JDK 路径以及 Maven 路径
  • (3) Jenkins 创建 Maven 项目然后进行构建
  • (4) 编写自动化上线脚本推送至 kubernetes 集群
  • (5) 优化部署脚本使其支持上线与回滚以及,相同版本重复构建


基础环境配置:

  • Step 1. Jenkins 服务器中 Java 与 Maven 环境配置与 Maven 插件安装;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    # Java 环境
    ~$ ls /usr/local/jdk1.8.0_211/
    ~$ java -version
    # java version "1.8.0_211"
    # Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
    # Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

    # Maven 环境 (两种方式)
    # ~$ sudo apt install maven # 方式1
    ~$ wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
    ~$ sudo tar -zxvf apache-maven-3.6.3-bin.tar.gz -C /usr/local
    ~$ ls /usr/local/apache-maven-3.6.3/
    # bin boot conf lib LICENSE NOTICE README.txt
    ~$ sudo ln -s /usr/local/apache-maven-3.6.3/ /usr/local/maven # 非常值得学习(变版本却不变执行路径)
    ~$ /usr/local/maven/bin/mvn -v
    # Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
    # Maven home: /usr/local/maven
    # Java version: 1.8.0_211, vendor: Oracle Corporation, runtime: /usr/local/jdk1.8.0_211/jre
    # Default locale: en_US, platform encoding: UTF-8
    # OS name: "linux", version: "5.4.0-46-generic", arch: "amd64", family: "unix"
    ~$ export PATH=/usr/local/maven/bin/:$PATH # 临时
    ~$ export PATH=${JAVA_HOME}/bin:/usr/local/maven/bin/:$PATH # 加入 /etc/Profile永久
    ~$ mvn -v

    # Maven Integration 插件 安装
    # PS : 提供了Jenkins和Maven的深度集成:根据快照在项目之间自动触发,各种Jenkins发布者的自动配置(Junit)。

    # Jenkins 中 Maven 集成配置
    > 面板 -> 全局工具配置 -> JDK 配置 -> 新增JDK -> 别名 jdk_env -> JAVA_HOME /usr/local/jdk1.8.0_211/
    -> 新增Maven -> 别名 maven_env -> MAVEN_HOME /usr/local/jdk1.8.0_211/
    WeiyiGeek.Maven 集成配置

    WeiyiGeek.Maven 集成配置

  • Step 2.手动我们的Java的Maven项目, 测试Jenkins服务器上的Maven是否可以正常编译War包并运行在单机的Tomcat8 之中;

Maven 镜像配置(您也可选择阿里云的Maven仓库地址加快拉取速度):

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- # (1) 修改官方的Maven仓库地址为本地私服; -->
158 <mirrors>
159 <!-- Maven 私服地址配置 -->
160 <mirror>
161 <id>weiyigeek-maven</id>
162 <mirrorOf>central</mirrorOf>
163 <name>Private maven</name>
164 <url>http://maven.weiyigeek.top:8081/repository/maven-public/</url>
165 </mirror>
166 </mirrors>

<!-- # (2) Default: ${user.home}/.m2/repository 缓存目录 -->
53 <localRepository>/path/to/local/repo</localRepository>

Maven代码项目程序拉取:

1
2
3
4
5
$ git clone [email protected]:ci-cd/java-maven.git
# Cloning into 'java-maven'...
# The authenticity of host 'gitlab.weiyigeek.top (10.10.107.201)' can't be established.
$ ~/code/java-maven$ ls
pom.xml src target

构建与运行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
~/code/java-maven$ mvn clean package -Dmaven.test.skip=true   # 跳过测试用例
# [INFO] Building war: /home/weiyigeek/code/java-maven/target/hello-world.war
# [INFO] WEB-INF/web.xml already added, skipping
# [INFO] ------------------------------------------------------------------------
# [INFO] BUILD SUCCESS
# [INFO] ------------------------------------------------------------------------
# [INFO] Total time: 7.225 s
# [INFO] Finished at: 2020-12-25T09:23:20Z
# [INFO] ------------------------------------------------------------------------

~/code/java-maven$ ls -alh /home/weiyigeek/code/java-maven/target/hello-world.war # 生成的war
-rw-r--r-- 1 weiyigeek weiyigeek 2.0M Dec 25 09:23 /home/weiyigeek/code/java-maven/target/hello-world.war

# 将生成的 hello-world.war 复制到本地的 Tomcat 的Wabapps目录之中他会自动解压

WeiyiGeek.Maven-hello-world

WeiyiGeek.Maven-hello-world

  • Step 3.在 Kubernets 上 准备接受 Jenkins 推送过来的war包的项目环境;
    基础配置:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    # (1) NFS 服务器上配置 (PS:由于测试资源有限 则 nfs 与 k8s master 在同一台机器上)
    [email protected]$ showmount -e
    # /nfs/data4 *
    /nfs/data4# ls -alh /nfs/
    # drwxrwxrwx 2 weiyigeek weiyigeek 4.0K Nov 19 13:27 data4
    /nfs/data4# mkdir /nfs/data4/{war,webapps}/
    /nfs/data4# ln -s /nfs/data4/war/ROOT /nfs/data4/webapps/ROOT
    /nfs/data4# chown -R weiyigeek:weiyigeek /nfs/data4/

    # (2) Node 1 && Node 2 都要执行
    sudo mkdir -pv /nfs/data4/
    sudo chown -R weiyigeek:weiyigeek /nfs/data4/
    sudo mount.nfs -r 10.10.107.202:/nfs/data4/ /nfs/data4/

    # (3) master 节点拉取 tomcat 此处选择 8.5.61-jdk8-corretto 并上传到内部私有harbor之中
    master$ docker pull tomcat:8.5.61-jdk8-corretto
    # 8.5.61-jdk8-corretto: Pulling from library/tomcat
    # ...
    # Status: Downloaded newer image for tomcat:8.5.61-jdk8-corretto
    # docker.io/library/tomcat:8.5.61-jdk8-corretto
    master$ docker tag tomcat:8.5.61-jdk8-corretto harbor.weiyigeek.top/test/tomcat:8.5.61-jdk8-corretto
    master$ docker push harbor.weiyigeek.top/test/tomcat:8.5.61-jdk8-corretto
    # The push refers to repository [harbor.weiyigeek.top/test/tomcat]
    # f13244e4918b: Pushed
    # 536f15f78828: Pushed
    # 1c98b6d16fad: Pushed
    # fdef502bf282: Pushed
    # cee8d35c645b: Pushed
    # 8.5.61-jdk8-corretto: digest: sha256:110d7391739e868daf8c1bdd03fcb7ffe9eaf2b134768b9162e2cd47d58f7255 size: 1368

    # (4) 节点拉取验证
    k8s-node-4:~$ docker pull harbor.weiyigeek.top/test/tomcat:8.5.61-jdk8-corretto
    k8s-node-5:~$ docker pull harbor.weiyigeek.top/test/tomcat:8.5.61-jdk8-corretto

    # (5) 将 jenkins 中构建好的war包 上传到 Master 节点 的 /nfs/data4/war 目录之中
    jenkins$ scp -P 20211 /var/lib/jenkins/workspace/Maven-HelloWorld/target/hello-world.war [email protected]:/nfs/data4/war
    # **************WARNING**************
    # Authorized only. All activity will be monitored and reported.
    # hello-world.war

    # (6) 解压war并建立软链接
    master$ /nfs/data4/war$ unzip hello-world.war -d hello-world-v1.0
    # Archive: hello-world.war
    master$ /nfs/data4/war$ ls
    # hello-world-v1.0 hello-world.war
    master$ /nfs/data4$ ln -s /nfs/data4/war/hello-world-v1.0/ /nfs/data4/webapps && ls /nfs/data4/webapps # 坑太多该目录不能存在
    # index.jsp META-INF WEB-INF

资源清单: (同样此处采用了HostPath的Volumns卷(war项目)与StorageClass存储类(访问日志))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
cat > jenkins-ci-gitlab-to-kubernetes.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
name: deploy-maven-svc
spec:
type: NodePort # Service 类型
selector:
app: java-maven # 【注意】与deployment资源控制器创建的Pod标签进行绑定;
release: stabel # Service 服务发现不能缺少Pod标签,有了Pod标签才能与之SVC对应
ports: # 映射端口
- name: http
port: 8080 # cluster 访问端口
targetPort: 8080 # Pod 容器内的服务端口
nodePort: 30089
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: deploy-java-maven
spec:
serviceName: "deploy-maven-svc"
replicas: 3 # 副本数
selector: # 选择器
matchLabels:
app: java-maven # 匹配的Pod标签非常重要
release: stabel
template:
metadata:
labels:
app: java-maven # 模板标签
release: stabel
spec:
volumes: # 关键点
- name: webapps # 卷名称
hostPath: # 采用hostPath卷
type: DirectoryOrCreate # 卷类型DirectoryOrCreate: 如果子节点上没有该目录便会进行创建
path: /nfs/data4/webapps # 各主机节点上已存在的目录此处是NFS共享
- name: timezone # 容器时区设置
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
containers:
- name: java-maven
image: harbor.weiyigeek.top/test/tomcat:8.5.61-jdk8-corretto # 拉取的镜像
imagePullPolicy: IfNotPresent
ports:
- name: http # 此端口在服务中的名称
containerPort: 8080 # 容器暴露的端口
volumeMounts: # 挂载指定卷目录
- name: webapps # Tomcat 应用目录
mountPath: /usr/local/tomcat/webapps/ROOT
- name: logs # Tomcat 日志目录
mountPath: /usr/local/tomcat/logs
- name: timezone # 镜像时区设置
mountPath: /usr/share/zoneinfo/Asia/Shanghai
volumeClaimTemplates: # 卷的体积要求模板此处采用StorageClass存储类主要针对于应用日志的存储;
- metadata: # 根据模板自动创建PV与PVC并且进行一一对应绑定;
name: logs
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: managed-nfs-storage # StorageClass存储类
resources:
requests:
storage: 1Gi
EOF

资源清单构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# (1) svc 与 stafefulset 资源创建
~/K8s/Day12$ kubectl apply -f jenkins-ci-gitlab-to-kubernetes.yaml
# service/deploy-maven-svc created
# statefulset.apps/deploy-java-maven created

# (2) 查看创建的资源
~/K8s/Day12$ kubectl get svc | grep "deploy-maven-svc" && kubectl get pod -l app=java-maven -o wide
# deploy-maven-svc NodePort 10.101.97.223 8080:30089/TCP 7m24s
# NAME READY STATUS RESTARTS AGE IP NODE
# deploy-java-maven-0 1/1 Running 0 10s 10.244.0.212 weiyigeek-ubuntu
# deploy-java-maven-1 1/1 Running 0 25s 10.244.1.199 k8s-node-4
# deploy-java-maven-2 1/1 Running 0 29s 10.244.2.102 k8s-node-5

# (3) 访问验证
master$ curl -s http://10.101.97.223:8080 | grep "<p>"
# <p> Server : Apache Tomcat/8.5.61 | 10.244.2.102 </p>
# <p> Client : 10.244.0.0 | 10.244.0.0</p>
# <p> Document_Root : /usr/local/tomcat/webapps/ROOT/ <br/><br/> URL : 10.101.97.223/index.jsp </p>
master$ curl -s http://10.101.97.223:8080 | grep "<p>"
# <p> Server : Apache Tomcat/8.5.61 | 10.244.0.212 </p>
# <p> Client : 10.244.0.1 | 10.244.0.1</p>
# <p> Document_Root : /usr/local/tomcat/webapps/ROOT/ <br/><br/> URL : 10.101.97.223/index.jsp </p>
master$ curl -s http://10.101.97.223:8080 | grep "<p>"
# <p> Server : Apache Tomcat/8.5.61 | 10.244.1.199 </p>
# <p> Client : 10.244.0.0 | 10.244.0.0</p>
# <p> Document_Root : /usr/local/tomcat/webapps/ROOT/ <br/><br/> URL : 10.101.97.223/index.jsp </p>

  • Step 4.下面正餐开始了,在 Jenkins 控制台 点击新建任务 -> 输入任务名称(Maven-HelloWorld) -> 选择构建一个Maven项目

常规设置: 丢弃旧的构建 10 个、参数化构建过程 Git 参数 git_version | 选项参数 deploy_option (deploy|rollback|redeploy) (设置与上面相同 PS 注意排序方式为智能排序)

关键点: Maven Build -> Goals and options : clean package -Dmaven.test.skip=true

构建后脚本设置: Post Steps -> 执行 Shell 命令 -> /bin/bash -x /tmp/script/maven-jenkins-ci-script.sh-> 应用并保存

构建测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 项目拉取
Running as SYSTEM
Building in workspace /var/lib/jenkins/workspace/Maven-HelloWorld
The recommended git tool is: NONE
using credential b4c8b4e9-2777-44a1-a1ed-e9dc21d37f4f
Cloning the remote Git repository
Cloning repository [email protected]:ci-cd/java-maven.git

<===[JENKINS REMOTING CAPACITY]===>channel started
Executing Maven: -B -f /var/lib/jenkins/workspace/Maven-HelloWorld/pom.xml clean package -Dmaven.test.skip=true
# 扫描项目并下载依赖
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.weiyigeek.main:hello-world >-------------------
[INFO] Building hello-world Maven Webapp 1.1-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO] Downloading from weiyigeek-maven: http://maven.weiyigeek.top:8081/repository/maven-public/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom

# 打包应用
[INFO] Packaging webapp
[INFO] Assembling webapp [hello-world] in [/var/lib/jenkins/workspace/Maven-HelloWorld/target/hello-world]
[INFO] Processing war project
[INFO] Copying webapp resources [/var/lib/jenkins/workspace/Maven-HelloWorld/src/main/webapp]
[INFO] Webapp assembled in [26 msecs]
[INFO] Building war: /var/lib/jenkins/workspace/Maven-HelloWorld/target/hello-world.war
[INFO] WEB-INF/web.xml already added, skipping
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.756 s
[INFO] Finished at: 2020-12-25T13:55:45Z
[INFO] ------------------------------------------------------------------------
Waiting for Jenkins to finish collecting data
[JENKINS] Archiving /var/lib/jenkins/workspace/Maven-HelloWorld/pom.xml to com.weiyigeek.main/hello-world/1.1-SNAPSHOT/hello-world-1.1-SNAPSHOT.pom
[JENKINS] Archiving /var/lib/jenkins/workspace/Maven-HelloWorld/target/hello-world.war to com.weiyigeek.main/hello-world/1.1-SNAPSHOT/hello-world-1.1-SNAPSHOT.war
channel stopped
Finished: SUCCESS

  • Step 5.Jenkins CI 部署Shell脚本编写,脚本需求部署、回退、可重复构建;
    脚本与权限: su - "jenkins" -c "touch /tmp/script/maven-jenkins-ci-script.sh && chmod a+x /tmp/script/maven-jenkins-ci-script.sh"

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #!/bin/bash
    # Description: Jenkins CI & Kubernetes & Gitlab -> Deploy or Rollback or Redeploy Java Maven Project
    DATE=$(date +%Y%m%d-%H%M%S)
    WAR_PATH="/nfs/data4/war"
    WEBROOT_PATH="/nfs/data4/webapps"
    WEB_DIR="${JOB_NAME}-${DATE}-${git_version}"
    WAR_DIR="${WAR_PATH}/${WEB_DIR}"
    WAR_NAME="${WEB_DIR}.war"
    K8S_MATER="[email protected]"
    K8S_MATER_PORT="20211"

    # 部署
    deploy () {
    # 1.上传Maven打包的war包到master之中
    scp -P ${K8S_MATER_PORT} ${WORKSPACE}/target/*.war [email protected]:${WAR_PATH}/${WAR_NAME}

    # 2.解压&软链接
    ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "unzip ${WAR_PATH}/${WAR_NAME} -d ${WAR_DIR} && \
    rm -rf ${WEBROOT_PATH} && \
    ln -s ${WAR_PATH}/${WEB_DIR} ${WEBROOT_PATH} && \
    kubectl delete pod -l app=java-maven"
    }

    # 回退
    rollback () {
    History_Version=$(ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "find ${WAR_PATH} -maxdepth 1 -type d -name ${JOB_NAME}-*-${git_version}")
    ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "rm -rf ${WEBROOT_PATH} && \
    ln -s ${History_Version} ${WEBROOT_PATH} && \
    kubectl delete pod -l app=java-maven"
    }


    # 重部署
    redeploy () {
    # 如果是以前部署过则删除以前部署的项目目录,否则重新部署;
    if [[ "v${GIT_COMMIT}" = "v${GIT_PREVIOUS_SUCCESSFUL_COMMIT}" ]];then
    echo -e "曾经部署过 ${git_version} 版本,现在正在重新部署!"
    History_Version=$(ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "find ${WAR_PATH} -maxdepth 1 -type d -name ${JOB_NAME}-*-${git_version}")
    ssh -p ${K8S_MATER_PORT} ${K8S_MATER} "rm -rf ${History_Version}"
    fi
    # 物理如何都要重新部署
    deploy
    }

    # 部署 & 回退 入口(坑-==两边没有空格)
    if [[ "${deploy_option}" = "deploy" ]]; then
    # 坑 (防止字符串为空)
    if [[ "v${GIT_COMMIT}" = "v${GIT_PREVIOUS_SUCCESSFUL_COMMIT}" ]];then
    echo -e "您已经部署过 ${git_version} 版本"
    exit 1
    else
    deploy
    fi
    elif [[ "${deploy_option}" = "rollback" ]];then
    rollback
    elif [[ "${deploy_option}" = "redeploy" ]];then
    redeploy
    else
    echo -e "无任何操作!停止执行脚本"
    exit 127
    fi
  • Step 6.修改h1标签为我们的项目打几个Tag标签然后Push到仓库;

WeiyiGeek.show tags

WeiyiGeek.show tags

  • Step 7.验证我们的构建的Maven项目以及推送构建的war到kubernetes集群之中(激动人心的时刻即将到来);

PS: 查看任务控制台输出信息确定脚本部署没有任何问题,之后访问http://10.10.107.202:30089/查看编译的war运行在kunbernets中部署Tomcat应用的结果;

WeiyiGeek.jenkins-ci-deploy

WeiyiGeek.jenkins-ci-deploy

  • Step 8.回滚测试 构建参数: deploy_option->rollback , git_version -> v1.1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    # 构建推送反馈
    [Maven-HelloWorld] $ /bin/sh -xe /tmp/jenkins6930799554885763742.sh
    + /bin/bash -x /tmp/script/maven-jenkins-ci-script.sh
    ++ date +%Y%m%d-%H%M%S
    + DATE=20201227-021208
    + WAR_PATH=/nfs/data4/war
    + WEBROOT_PATH=/nfs/data4/webapps
    + WEB_DIR=Maven-HelloWorld-20201227-021208-v1.1
    + WAR_DIR='/nfs/data4/war/Maven-HelloWorld-20201227-021208-v1.1'
    + WAR_NAME=Maven-HelloWorld-20201227-021208-v1.1.war
    + [email protected]
    + K8S_MATER_PORT=20211
    + [[ rollback = \d\e\p\l\o\y ]]
    + [[ rollback = \r\o\l\l\b\a\c\k ]] # 进行回滚操作
    + rollback
    ++ ssh -p 20211 [email protected] 'find /nfs/data4/war -maxdepth 1 -type d -name Maven-HelloWorld-*-v1.1'
    **************WARNING**************
    Authorized only. All activity will be monitored and reported.
    + History_Version=/nfs/data4/war/Maven-HelloWorld-20201227-020140-v1.1 # 历史版本
    + ssh -p 20211 [email protected] 'rm -rf /nfs/data4/webapps && ln -s /nfs/data4/war/Maven-HelloWorld-20201227-020140-v1.1 /nfs/data4/webapps && kubectl delete pod -l app=java-maven'
    **************WARNING**************
    Authorized only. All activity will be monitored and reported.
    pod "deploy-java-maven-0" deleted
    pod "deploy-java-maven-1" deleted
    pod "deploy-java-maven-2" deleted
    Finished: SUCCESS

    # 应用反馈
    http://10.10.107.202:30089/
    # Maven - Hello World - v1.1
    # 访问时间: Sun Dec 27 2020 10:12:18 GMT+0800 (中国标准时间)
    # Server : Apache Tomcat/8.5.61 | 10.244.1.203
    # Client : 10.244.0.0 | 10.244.0.0
    # Document_Root : /usr/local/tomcat/webapps/ROOT/
    # URL : 10.10.107.202/index.jsp
  • Step 9.重部署测试 构建参数: deploy_option->redeploy , git_version -> v1.2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    # (1) 我们先来看看 war 目录的v1.2版本的文件与目录名称
    /nfs/data4/war$ ls -alh | grep "-v1.2"
    drwxrwxr-x 4 weiyigeek weiyigeek 4.0K Dec 27 10:09 Maven-HelloWorld-20201227-020939-v1.2
    -rw-r--r-- 1 weiyigeek weiyigeek 2.0M Dec 27 10:09 Maven-HelloWorld-20201227-020939-v1.2.war

    # (2) 项目重部署控制台信息输出
    [Maven-HelloWorld] $ /bin/sh -xe /tmp/jenkins8520069315177369772.sh
    channel stopped
    + /bin/bash -x /tmp/script/maven-jenkins-ci-script.sh
    ++ date +%Y%m%d-%H%M%S
    + DATE=20201227-021934
    + WAR_PATH=/nfs/data4/war
    + WEBROOT_PATH=/nfs/data4/webapps
    + WEB_DIR=Maven-HelloWorld-20201227-021934-v1.2
    + WAR_DIR='/nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2'
    + WAR_NAME=Maven-HelloWorld-20201227-021934-v1.2.war
    + [email protected]
    + K8S_MATER_PORT=20211
    + [[ redeploy = \d\e\p\l\o\y ]]
    + [[ redeploy = \r\o\l\l\b\a\c\k ]]
    + [[ redeploy = \r\e\d\e\p\l\o\y ]]
    + redeploy # 进入了重部署脚本选择
    + [[ ve8d88cf3e222b79259edcfb7ca48cee7b079ee08 = \v\e\8\d\8\8\c\f\3\e\2\2\2\b\7\9\2\5\9\e\d\c\f\b\7\c\a\4\8\c\e\e\7\b\0\7\9\e\e\0\8 ]]
    + echo -e '曾经部署过 v1.2 版本,现在正在重新部署!'
    曾经部署过 v1.2 版本,现在正在重新部署!
    ++ ssh -p 20211 [email protected] 'find /nfs/data4/war -maxdepth 1 -type d -name Maven-HelloWorld-*-v1.2'
    + History_Version=/nfs/data4/war/Maven-HelloWorld-20201227-020939-v1.2
    + ssh -p 20211 [email protected] 'rm -rf /nfs/data4/war/Maven-HelloWorld-20201227-020939-v1.2' # 删除了原来v1.2版本的war解压目录

    # 重新构建
    + deploy
    + scp -P 20211 /var/lib/jenkins/workspace/Maven-HelloWorld/target/hello-world.war [email protected]:/nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2.war
    # 解压上传的war 并创建软连接
    + ssh -p 20211 [email protected] 'unzip /nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2.war -d /nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2 && rm -rf /nfs/data4/webapps && ln -s /nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2 /nfs/data4/webapps && kubectl delete pod -l app=java-maven'
    Archive: /nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2.war
    creating: /nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2/META-INF/
    ....
    inflating: /nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2/META-INF/maven/com.weiyigeek.main/hello-world/pom.properties
    pod "deploy-java-maven-0" deleted
    pod "deploy-java-maven-1" deleted
    pod "deploy-java-maven-2" deleted

    Finished: SUCCESS

    # (3) 应用反馈
    Maven - Hello World - v1.2
    访问时间: Sun Dec 27 2020 10:20:03 GMT+0800 (中国标准时间)
    Server : Apache Tomcat/8.5.61 | 10.244.2.107
    Client : 10.244.0.0 | 10.244.0.0
    Document_Root : /usr/local/tomcat/webapps/ROOT/
    URL : 10.10.107.202/index.jsp

PS : 至此 Maven 与 Jenkins 集成实践完成


SonarQube 集成配置与实践

描述: 在Jenkins持续集成中中可以在构建代码前对我们项目进行一个代码质量扫描检测, 此处我们引入SonarQube进行实现;

操作流程:

  • Step 0.在 SonarQube Web中进行认证 Token 生成:(手工设置)_添加项目 -> 项目标识 -> 创建一个令牌 (Jenkins) -> 得到Token;

    1
    2
    Jenkins: 755eeb453cb28f96aa9d4ea14334da7287c2e840
    # 此令牌用于执行分析时认证时使用,如果这个令牌存在问题,可以随时在你的用户账号下取消这个令牌。
  • Step 1.插件安装: 系统管理 -> 插件管理 -> SonarQube Scanner for Jenkins()

WeiyiGeek.SonarQube Scanner for Jenkins

WeiyiGeek.SonarQube Scanner for Jenkins

  • Step 2.在Jenkins系统管理->系统设置以及全局工具管理->上配置SonarQube相关配置(服务端地址,以及客户端工具地址);
    1
    2
    3
    4
    5
    # (1) 服务端
    Dashboard -> 配置 -> SonarQube servers -> Add SonarQube 设置名称和SonarQube地址 -> 添加Token凭据(类型:Secret Text) -> Jenklins-Connet-Sonarqube-Token

    # (2) 客户端
    Dashboard -> 全局工具配置 -> SonarQube Scanner -> 名称(sonarqube-scanner) -> 工具路径 (/usr/local/sonar)-> 保存应用
WeiyiGeek.Jenkins上SonarQube配置

WeiyiGeek.Jenkins上SonarQube配置

  • Step 3.应用项目分析实战在分析项目中配置Analysis Properties->保存和应用-> 此时项目中会多一个SonarQube的图标;
    PS : 下述图中有误应该是在Pre Steps阶段(Execute SonarQube Scanner,其次 Build 构建即可)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 构建前进行分析配置(名称、唯一标识、检测目录)
    sonar.projectName=${JOB_NAME}
    sonar.projectKey=Jenkis
    sonar.source=.


    # 已配置不需要了
    # sonar.host.url=http://sonar.weiyigeek.top:9000 \
    # sonar.login=755eeb453cb28f96aa9d4ea14334da7287c2e840
    WeiyiGeek.SonarQube Analysis Properties

    WeiyiGeek.SonarQube Analysis Properties

  • Step 4.新建立一个V1.7Tag并上传到Gitlab之中,之后进行检测与构建操作->返回工程点击SonarQube 图标进行项目检测结果页面;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [email protected] MINGW64 /e/EclipseProject/hello-world (master)
    $ git add .
    $ git commit -m "v1.7"
    # [master 0f50b10] v1.7
    # 1 file changed, 1 insertion(+), 1 deletion(-)
    $ git tag -a "v1.7" -m "v1.7"
    $ git push
    # Enumerating objects: 11, done.
    # Counting objects: 100% (11/11), done.
    # .....
    # To http://gitlab.weiyigeek.top/ci-cd/java-maven.git
    # 3bfb942..0f50b10 master -> master

    $ git push origin v1.7
    # ...
    # To http://gitlab.weiyigeek.top/ci-cd/java-maven.git
    # * [new tag] v1.7 -> v1.7
WeiyiGeek.SonarQube项目检测结果

WeiyiGeek.SonarQube项目检测结果

  • Step 5.项目在K8s集群中部署结果
    1
    2
    3
    4
    5
    6
    7
    # https://10.10.107.202:30089/
    Maven - Hello World - v1.7
    访问时间: Sun Jan 03 2021 13:20:34 GMT+0800 (中国标准时间)
    Server : Apache Tomcat/8.5.61 | 10.244.2.111
    Client : 10.244.0.0 | 10.244.0.0
    Document_Root : /usr/local/tomcat/webapps/ROOT/
    URL : 10.10.107.202/index.jsp


邮箱&钉钉&微信消息通知 集成配置与实践

描述: 在Jenkins中我们还有最重要的一步还没有完成, 即消息通知(让我们知道是构建成功还是、构建失败)等等, 常规的方式有邮箱通知、Shell自定义脚本通知,WebHook通知等;

通知插件插件安装:

1
2
DingTalk : 钉钉 Jenkins 插件 2.4.3 (https://github.com/jenkinsci/dingtalk-plugin)
Qy Wechat Notification Plugin : 这个插件是一个机器人,可以发布构建状态和发送消息给qy微信. 1.0.2 (https://www.jenkins.io/doc/pipeline/steps/qy-wechat-notification/)

(0) 邮箱通知实践配置
描述: 此处以腾讯企业邮箱为例进行配置,首先需要登陆将要被使用的邮箱,注意必须要使用微信绑定后才能正常生成客户端专用密码,然后开启SMTP服务;

1
2
3
4
5
# 客户端设置方法
接收服务器:
imap.exmail.qq.com(使用SSL,端口号993)
发送服务器:
smtp.exmail.qq.com(使用SSL,端口号465)

WeiyiGeek.腾讯企业邮箱

WeiyiGeek.腾讯企业邮箱

Step 1.在 Dashboard -> 系统配置 -> Jenkins Location进行配置系统管理员邮件地址,注意此处管理员邮箱地址必须与smtp服务发信地址一致否则将会报出501 mail from address must be same as authorization user错误;

Step 2.设置发信邮箱相关配置,点击 Dashboard -> 系统配置 -> 邮件通知 填入 SMTP 发信服务器地址以及企业邮箱后缀,采用SSL协议并输入认证的账号与客户端专用密码,最后测试发信;

WeiyiGeek.发信邮箱相关配置

WeiyiGeek.发信邮箱相关配置

Step 3.构建项目通信发信测试,点击 Dashboard -> Maven-HelloWorld -> 构建设置 -> 启用E-mail Notification

1
2
3
4
5
# 收信人:Recipients
# 什么场景发送信息:
- 构建失败给每一个人发送发送电子邮件 : Send e-mail for every unstable build
- 谁构建失败给谁发送邮件: Send separate e-mails to individuals who broke the build
- 为每个失败的模块发送电子邮件 : Send e-mail for each failed module

WeiyiGeek.项目通信发信测试

WeiyiGeek.项目通信发信测试

补充方式:
描述: 由于Jenkins自带的邮件功能比较鸡肋,因此这里推荐安装专门的邮件插件(Email Extension)并介绍如何配置Jenkins自带的邮件功能作用。

插件安装: 系统管理→管理插件→可选插件选择Email Extension Plugin插件进行安装
系统设置:

  • 1) 通过系统管理→系统设置,进行邮件配置 -> Extended E-mail Notification -> 输入 SMTP Server 相关信息以及Authentication相关设置(注意:密码一般是邮箱授权码)
  • 2) 设置其编码格式以及默认内容类型,以及邮件模板配置在 Extended E-mail的 default content -;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    <!-- ^\s*(?=\r?$)\n 正则替换空行 -->
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
    </head>
    <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
    <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
    <tr>
    <td>(本邮件由程序自动下发,请勿回复!)</td>
    </tr>
    <tr>
    <td>
    <h2><font color="#FF0000">构建结果 - ${BUILD_STATUS}</font></h2>
    </td>
    </tr>
    <tr>
    <td><br />
    <b><font color="#0B610B">构建信息</font></b>
    <hr size="2" width="100%" align="center" />
    </td>
    </tr>
    <tr><a href="${PROJECT_URL}">${PROJECT_URL}</a>
    <td>
    <ul>
    <li>项目名称:${PROJECT_NAME}</li>
    <li>GIT路径:<a href="${GIT_URL}">${GIT_URL}</a></li>
    <li>构建编号:${BUILD_NUMBER}</li>
    <li>触发原因:${CAUSE}</li>
    <li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
    </ul>
    </td>
    </tr>
    <tr>
    <td>
    <b><font color="#0B610B">变更信息:</font></b>
    <hr size="2" width="100%" align="center" />
    </td>
    </tr>
    <tr>
    <td>
    <ul>
    <li>上次构建成功后变化 : ${CHANGES_SINCE_LAST_SUCCESS}</a></li>
    </ul>
    </td>
    </tr>
    <tr>
    <td>
    <ul>
    <li>上次构建不稳定后变化 : ${CHANGES_SINCE_LAST_UNSTABLE}</a></li>
    </ul>
    </td>
    </tr>
    <tr>
    <td>
    <ul>
    <li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
    </ul>
    </td>
    </tr>
    <tr>
    <td>
    <ul>
    <li>变更集:${JELLY_SCRIPT,template="html"}</a></li>
    </ul>
    </td>
    </tr>
    <!--
    <tr>
    <td>
    <b><font color="#0B610B">Failed Test Results</font></b>
    <hr size="2" width="100%" align="center" />
    </td>
    </tr>
    <tr>
    <td>
    <pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
    <br />
    </td>
    </tr>
    <tr>
    <td>
    <b><font color="#0B610B">构建日志 (最后 100行):</font></b>
    <hr size="2" width="100%" align="center" />
    </td>
    </tr>-->
    <!-- <tr>
    <td>Test Logs (if test has ran): <a
    href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip">${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a>
    <br />
    <br />
    </td>
    </tr> -->
    <!--
    <tr>
    <td>
    <textarea cols="80" rows="30" readonly="readonly" style="font-family: Courier New">${BUILD_LOG, maxLines=100,escapeHtml=true}</textarea>
    </td>
    </tr>-->
    <hr size="2" width="100%" align="center" />
    </table>
    </body>
    </html>
  • 3) 设置Default Triggers触发机制,例如下面是失败时候和成功时候发送;
WeiyiGeek.设置

WeiyiGeek.设置

  • 4) 在Job任务调用中选择构建后操作进行设置Email Notification进行设置通知
WeiyiGeek.Email-Notification

WeiyiGeek.Email-Notification


(1) 钉钉消息通知实践配置
Step 0.在钉钉中建立一个群聊并且创建一个群机器人生成一个Webhook地址,操作如下图所示:

1
例如:https://oapi.dingtalk.com/robot/send?access_token=95f707645db08794166ed3aad3eaad363bb1475bf7c91635b7456a0a8c8893c6

WeiyiGeek.钉钉群聊机器人添加

WeiyiGeek.钉钉群聊机器人添加

Step 1.设置钉钉消息通知参数, 点击 Dashboard -> 系统配置 -> 钉钉 选择通知时机以及代理通信(当该主机无法正常连接网络时可采用此方法) -> 点击新增(填入唯一的id、以及名称和webhook地址,注意如果在创建机器人时指定了关键字和加密字符串需要填写上)->然后测试发信;

WeiyiGeek.钉钉消息通知参数

WeiyiGeek.钉钉消息通知参数

Step 2.在FreeStyle风格的项目是可以在通用设置卡点选钉钉消息通知的,而Maven的项目是没有该点选选项,因为该插件只支持FreeStyle和PIPELINE流水线(这里有巨坑所以有的时候还是老版本的插件好用),注意网上博客中关于大多数此问题都是不适用的官方文档才是第一手;

参考连接: https://jenkinsci.github.io/dingtalk-plugin/examples/freestyleAdvanced.html#%E8%AF%A6%E7%BB%86%E6%97%A5%E5%BF%97

WeiyiGeek.FreeStyle风格构建的钉钉通知

WeiyiGeek.FreeStyle风格构建的钉钉通知

PS : 对于其它项目风格的项目在后面我们将使用流水线PIPEline进行实现钉钉的消息通知;


(2) 企业微信通知实践配置

  • Step 1.设置企业微信通知全局参数,点击 Dashboard -> 系统配置 -> 企业微信通知配置设置构建环境名称(会在信息中显示)以及默认Webhook地址(全局的)、通知用户的Uid(@ALL表示全部)
WeiyiGeek.企业微信全局参数

WeiyiGeek.企业微信全局参数

  • Step 2.在构建任务中设置相应的通知参数,点击 Dashboard -> Maven-HelloWorld(项目名称) -> 构建后的操作 -> 选择企业微信

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # PS:此处输入的Webhook优先级高于全局的企业微信Webhook这样做的好处是便于为每个任务分配不同的Webhook;
    Webhook地址: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=c222f3fc-f645-440a-ad24-0ce8d9626f11
    情况通知:
    仅失败才@
    发送开始构建信息
    仅失败才发送
    仅成功才发送
    仅构建中断才发送
    仅不稳定构建才发送
    通知UserID: @ALL
    通知手机号码: 选填
  • Step 3.对 Maven-HelloWorld 项目进行构建并查看控制台输出,消息推送;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 构建前发送
    > git config core.sparsecheckout # timeout=10
    > git checkout -f e8d88cf3e222b79259edcfb7ca48cee7b079ee08 # timeout=10
    Commit message: "v1.2"
    > git rev-list --no-walk e8d88cf3e222b79259edcfb7ca48cee7b079ee08 # timeout=10
    推送通知 {"markdown":{"content":"Jenkins-Notify<font color=\"info\">【Maven-HelloWorld】<\/font>开始构建\n >构建参数:<font color=\"comment\">git_version=v1.2, deploy_option=rollback <\/font>\n >预计用时:<font color=\"comment\">0分钟<\/font>\n >[查看控制台](http://jenkins.weiyigeek.top:8080/job/Maven-HelloWorld/16/console)"},"msgtype":"markdown"}
    通知结果 {"errcode":0,"errmsg":"ok"}

    # 构建部署后发送
    + ssh -p 20211 [email protected] 'rm -rf /nfs/data4/webapps && ln -s /nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2 /nfs/data4/webapps && kubectl delete pod -l app=java-maven'
    **************WARNING**************
    Authorized only. All activity will be monitored and reported.
    pod "deploy-java-maven-0" deleted
    pod "deploy-java-maven-1" deleted
    pod "deploy-java-maven-2" deleted
    推送通知{"markdown":{"content":"Jenkins-Notify<font color=\"info\">【Maven-HelloWorld】<\/font>构建<font color=\"info\">成功~<\/font>👌\n >构建用时:<font color=\"comment\">28 sec<\/font>\n >[查看控制台](http://jenkins.weiyigeek.top:8080/job/Maven-HelloWorld/16/console)"},"msgtype":"markdown"}
    通知结果{"errcode":0,"errmsg":"ok"}
    项目运行结果[SUCCESS]
    Finished: SUCCESS
WeiyiGeek.企业微信通知实现效果

WeiyiGeek.企业微信通知实现效果


0x05 补充说明

(1) 内置环境变量

PS : Jenkins 默认的环境变量列表 http://jenkins.weiyigeek.top:8080/env-vars.html/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
BUILD_NUMBER 
#The current build number, such as "153"
BUILD_ID
# The current build ID, identical to BUILD_NUMBER for builds created in 1.597+, but a YYYY-MM-DD_hh-mm-ss timestamp for older builds
BUILD_DISPLAY_NAME
# The display name of the current build, which is something like "#153" by default.
JOB_NAME
# Name of the project of this build, such as "foo" or "foo/bar".
JOB_BASE_NAME
# Short Name of the project of this build stripping off folder paths, such as "foo" for "bar/foo".
BUILD_TAG
# String of "jenkins-${JOB_NAME}-${BUILD_NUMBER}". All forward slashes ("/") in the JOB_NAME are replaced with dashes ("-"). Convenient to put into a resource file, a jar file, etc for easier identification.
EXECUTOR_NUMBER
# The unique number that identifies the current executor (among executors of the same machine) that’s carrying out this build. This is the number you see in the "build executor status", except that the number starts from 0, not 1.
NODE_NAME
# Name of the agent if the build is on an agent, or "master" if run on master
NODE_LABELS
# Whitespace-separated list of labels that the node is assigned.
WORKSPACE
# The absolute path of the directory assigned to the build as a workspace.
WORKSPACE_TMP
# A temporary directory near the workspace that will not be browsable and will not interfere with SCM checkouts. May not initially exist, so be sure to create the directory as needed (e.g., mkdir -p on Linux). Not defined when the regular workspace is a drive root.
JENKINS_HOME
# The absolute path of the directory assigned on the master node for Jenkins to store data.
JENKINS_URL
# Full URL of Jenkins, like http://server:port/jenkins/ (note: only available if Jenkins URL set in system configuration)
BUILD_URL
# Full URL of this build, like http://server:port/jenkins/job/foo/15/ (Jenkins URL must be set)
JOB_URL
# Full URL of this job, like http://server:port/jenkins/job/foo/ (Jenkins URL must be set)
GIT_COMMIT
# The commit hash being checked out.
GIT_PREVIOUS_COMMIT
# The hash of the commit last built on this branch, if any.
GIT_PREVIOUS_SUCCESSFUL_COMMIT
# The hash of the commit last successfully built on this branch, if any.
GIT_BRANCH
# The remote branch name, if any.
GIT_LOCAL_BRANCH
# The local branch name being checked out, if applicable.
GIT_CHECKOUT_DIR
# The directory that the repository will be checked out to. This contains the value set in Checkout to a sub-directory, if used.
GIT_URL
# The remote URL. If there are multiple, will be GIT_URL_1, GIT_URL_2, etc.
GIT_COMMITTER_NAME
# The configured Git committer name, if any, that will be used for FUTURE commits from the current workspace. It is read from the Global Config user.name Value field of the Jenkins Configure System page.
GIT_AUTHOR_NAME
# The configured Git author name, if any, that will be used for FUTURE commits from the current workspace. It is read from the Global Config user.name Value field of the Jenkins Configure System page.
GIT_COMMITTER_EMAIL
# The configured Git committer email, if any, that will be used for FUTURE commits from the current workspace. It is read from the Global Config user.email Value field of the Jenkins Configure System page.
GIT_AUTHOR_EMAIL
# The configured Git author email, if any, that will be used for FUTURE commits from the current workspace. It is read from the Global Config user.email Value field of the Jenkins Configure System page.

测试环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/bin/bash
echo BUILD_NUMBER: ${BUILD_NUMBER }

echo BUILD_ID: ${BUILD_ID}

echo BUILD_DISPLAY_NAME: $BUILD_DISPLAY_NAME:

echo JOB_NAME: $JOB_NAME

echo JOB_BASE_NAME: $JOB_BASE_NAME

echo BUILD_TAG: $BUILD_TAG

echo EXECUTOR_NUMBER: $EXECUTOR_NUMBER

echo NODE_NAME: $NODE_NAME

echo NODE_LABELS: $NODE_LABELS

echo WORKSPACE: $WORKSPACE

echo WORKSPACE_TMP: $WORKSPACE_TMP

echo JENKINS_HOME: $JENKINS_HOME

echo JENKINS_URL: $JENKINS_URL

echo BUILD_URL: $BUILD_URL

echo JOB_URL: $JOB_URL

echo GIT_COMMIT: $GIT_COMMIT

echo GIT_PREVIOUS_COMMIT: $GIT_PREVIOUS_COMMIT

echo GIT_PREVIOUS_SUCCESSFUL_COMMIT: $GIT_PREVIOUS_SUCCESSFUL_COMMIT

echo GIT_BRANCH: $GIT_BRANCH

echo GIT_LOCAL_BRANCH: $GIT_LOCAL_BRANCH

echo GIT_CHECKOUT_DIR: $GIT_CHECKOUT_DIR

echo GIT_URL: $GIT_URL

echo GIT_COMMITTER_NAME: $GIT_COMMITTER_NAME

echo GIT_AUTHOR_NAME: $GIT_AUTHOR_NAME

echo GIT_COMMITTER_EMAIL: $GIT_COMMITTER_EMAIL

echo GIT_AUTHOR_EMAIL: $GIT_AUTHOR_EMAIL

测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
+ /bin/bash /tmp/script/env.sh
BUILD_NUMBER: 22
BUILD_ID: 22
BUILD_DISPLAY_NAME: #22:
JOB_NAME: Maven-HelloWorld
JOB_BASE_NAME: Maven-HelloWorld
BUILD_TAG: jenkins-Maven-HelloWorld-22
EXECUTOR_NUMBER: 0
NODE_NAME: master
NODE_LABELS: master
WORKSPACE: /var/lib/jenkins/workspace/Maven-HelloWorld
WORKSPACE_TMP: /var/lib/jenkins/workspace/[email protected]
JENKINS_HOME: /var/lib/jenkins
JENKINS_URL: http://jenkins.weiyigeek.top:8080/
BUILD_URL: http://jenkins.weiyigeek.top:8080/job/Maven-HelloWorld/22/
JOB_URL: http://jenkins.weiyigeek.top:8080/job/Maven-HelloWorld/
GIT_COMMIT: 0f50b10b09c160a86972178d94ca1f0a704dd767
GIT_PREVIOUS_COMMIT: 0f50b10b09c160a86972178d94ca1f0a704dd767
GIT_PREVIOUS_SUCCESSFUL_COMMIT: 0f50b10b09c160a86972178d94ca1f0a704dd767
GIT_BRANCH: v1.7
GIT_URL: [email protected]:ci-cd/java-maven.git
GIT_AUTHOR_NAME:
GIT_AUTHOR_EMAIL:
GIT_COMMITTER_NAME:
GIT_COMMITTER_EMAIL:
GIT_LOCAL_BRANCH:
GIT_CHECKOUT_DIR:
Finished: SUCCESS


(2) Jenkins 管理员密码忘记重置

1.找到用户的路径

1
2
3
4
5
6
7
8
9
10
11
12
[[email protected] ~]# cd /var/lib/jenkins/users/
[[email protected] users]# tree
.
├── 552408925_8628634723176281851
│ └── config.xml
├── admin_8092868597319509744
│ └── config.xml
├── jenkins_3327043579358903316 #我使用的jenkins作为管理员(如果你是admin就进admin目录)
│ └── config.xml #修改config.xml
└── users.xml

3 directories, 4 files

2.修改jenkins用户目录下的config.xml,定位到<passwordHash>那行删除,改为如下内容-

1
2
[[email protected] users]# vim config.xml
<passwordHash>#jbcrypt:$2a$10$slYx6.2Xyss6w9LnuiwnNOReuvkcSkaI.Y.Z2AC6Sp7hdF7hhxlsK</passwordHash>

3.新密码为bgx.com 记得重启jenkins生效


0x06 入坑&出坑

问题1.jenkins depends on daemon; however Package daemon is not installed.
问题描述: 在Ubuntu 采用 dpkg 安装 jenkins_2.263.1_all.deb 时报错提示 daemon 包未安装
问题复原:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ sudo dpkg -i jenkins_2.263.1_all.deb
Selecting previously unselected package jenkins.
(Reading database ... 115038 files and directories currently installed.)
Preparing to unpack jenkins_2.263.1_all.deb ...
Unpacking jenkins (2.263.1) ...
dpkg: dependency problems prevent configuration of jenkins:
jenkins depends on daemon; however:
Package daemon is not installed.

dpkg: error processing package jenkins (--install):
dependency problems - leaving unconfigured
Processing triggers for systemd (245.4-4ubuntu3.2) ...
Errors were encountered while processing:
jenkins

解决办法:
1
sudo apt install -y daemon


问题2:Jenkins 启动时显示 ERROR: No Java executable found in current PATH: /bin:/usr/bin:/sbin:/usr/sbin
问题复原:

1
2
3
4
5
6
7
$ systemctl status jenkins
Dec 23 14:02:57 gitlab systemd[1]: Starting LSB: Start Jenkins at boot time...
Dec 23 14:02:57 gitlab jenkins[356298]: ERROR: No Java executable found in current PATH: /bin:/usr/bin:/sbin:/usr/sbin
Dec 23 14:02:57 gitlab jenkins[356298]: If you actually have java installed on the system make sure the executable is in the aforementioned path and that 'type -p ja>
Dec 23 14:02:57 gitlab systemd[1]: jenkins.service: Control process exited, code=exited, status=1/FAILURE
Dec 23 14:02:57 gitlab systemd[1]: jenkins.service: Failed with result 'exit-code'.
Dec 23 14:02:57 gitlab systemd[1]: Failed to start LSB: Start Jenkins at boot time.

问题原因: 未找寻到有效的Java执行环境;
解决流程:
1
2
3
4
5
6
7
8
①.先执行echo $PATH 看看环境变量运行结果如下:
/usr/maven/maven/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/java/jdk1.8/bin
如果连这都没有的话重新安装Java。

②.建立软连接:ln -s /usr/java/jdk1.8/bin/java /usr/bin/java(换成你自己的路径)
Please wait while Jenkins is getting ready to work (jenkins)
如果界面提示Jenkins正在启动,请稍后…或者提示
Please wait while Jenkins is getting ready to work…


问题3.安装Jenkins后或者安装插件时候一直在加载;
问题描述: 由于Jenkins官方插件下载地址没被墙但是网速很慢,下载时间也长;
解决方法:换清华的镜像进去之后下载插件即可 (http://updates.jenkins-ci.org/download/)
操作流程: 需要你进入jenkins的工作目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 打开 hudson.model.UpdateCenter.xml 把 http://updates.jenkins-ci.org/update-center.json 改成 http://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
sed -i "s#updates.jenkins.io#mirrors.tuna.tsinghua.edu.cn/jenkins/updates#g" /var/lib/jenkins/hudson.model.UpdateCenter.xml

# 上面的命令就是将将安装目录下的 hudson.model.UpdateCenter.xml 中改成
<?xml version='1.1' encoding='UTF-8'?>
<sites>
<site>
<id>default</id>
<url>https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json</url>
</site>
</sites>


# (2) 将updates文件夹下的default.json 中所有 http://updates.jenkins-ci.org/download/替换为 https://mirrors.tuna.tsinghua.edu.cn/jenkins/ PS: 也可以在后台进行设置
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json


# (3) 修改完成后重启 Jenkins 即可

WeiyiGeek.Jenkins Please wait

WeiyiGeek.Jenkins Please wait


问题4: 未正确配置Jenkins基础URL等相关信息;
问题描述: Jenkins的根URL是空的,但是需要Jenkins的许多特性的正确操作,如电子邮件通知、PR状态更新和环境变量,如BUILD_URL。
请提供Jenkins配置中的准确值。

1
2
3
Jenkins root URL is empty but is required for the proper operation of many Jenkins features like email notifications, PR status update, and environment variables such as BUILD_URL.

Please provide an accurate value in Jenkins configuration.

解决办法: Dashboard -> 配置 -> Jenkins Location -> Jenkins 地址 & 邮箱


问题5.无法连接仓库:Command “git ls-remote -h – [email protected]:ci-cd/blog.git HEAD” returned status code 128:
问题复原:

1
2
3
4
stdout:
stderr: Host key verification failed.
fatal: Could not read from remote repository.
# Please make sure you have the correct access rights and the repository exists.

问题原因: 由于采用SSH协议进行代码的拉取和信息的查看,在利用公密钥首次链接时候未绑定其机器的公钥信息, 将会导致 Host key verification failed.
解决办法: 在连接的机器上先执行git -T [email protected]保存其主机的公钥信息;
1
2
3
4
5
6
7
8
9
# 例如 首次连接Gitlab时候需要进行主机于公钥绑定
ssh -T [email protected]
# 无法建立主机“gitlab.com(172.65.251.78)”的真实性。
The authenticity of host 'gitlab.com (172.65.251.78)' can\'t be established.
ECDSA key fingerprint is SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

$ cat ~/.ssh/known_hosts
gitlab.com,172.65.251.78 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAABFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QOLXBpQ6KWjbjTDTdDkoohFzgbEYI=


问题6.Jenkins 内置邮件通知发信测试 Failed to send out e-mail javax.mail.AuthenticationFailedException: 535 Error:
错误信息:

1
2
3
4
5
6
7
Failed to send out e-mail
javax.mail.AuthenticationFailedException: 535 Error: ÇëʹÓÃÊÚȨÂëµÇ¼¡£ÏêÇéÇë¿´: http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256

at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:947)
at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:858)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:762)
at javax.mail.Service.connect(Service.java:364)

错误原因: 配置STMP的邮箱账号,输入的认证字符串是邮箱密码而并非生成的客户端密码, 在 腾讯企业邮箱、163邮箱都需要使用生成的客户端密码进行登录;


问题7.Jenkins 内置邮件通知发信测试 com.sun.mail.smtp.SMTPSenderFailedException: 501 mail from address must be same as authorization user
错误信息:

1
2
3
4
5
6
7
8
9
10
11
Failed to send out e-mail
com.sun.mail.smtp.SMTPSenderFailedException: 501 mail from address must be same as authorization user
at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1817)
Caused: com.sun.mail.smtp.SMTPSendFailedException: 501 mail from address must be same as authorization user
;
nested exception is:
com.sun.mail.smtp.SMTPSenderFailedException: 501 mail from address must be same as authorization user
at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2374)
at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1808)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1285)
at javax.mail.Transport.send0(Transport.java:231)

错误原因: 最后发现是jenkins url下面的系统管理员邮件地址没有填写或者与STMP发信邮箱不一致
解决办法: 填写系统管理员邮箱与STMP发信邮箱地址一致就可以了。

问题8.Jenkins 内置邮件通知发信测试com.sun.mail.smtp.SMTPAddressFailedException: 501 Bad address syntax

错误信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ERROR: Invalid Addresses
javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
com.sun.mail.smtp.SMTPAddressFailedException: 501 Bad address syntax
at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:2064)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1286)
at javax.mail.Transport.send0(Transport.java:231)
at javax.mail.Transport.send(Transport.java:100)
at hudson.tasks.MailSender.run(MailSender.java:130)
at hudson.tasks.MailSender.execute(MailSender.java:105)
at hudson.maven.MavenModuleSetBuild$MavenModuleSetBuildExecution.cleanUp(MavenModuleSetBuild.java:1093)
at hudson.model.Run.execute(Run.java:1954)
at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:543)
at hudson.model.ResourceController.execute(ResourceController.java:97)
at hudson.model.Executor.run(Executor.java:429)
Caused by: com.sun.mail.smtp.SMTPAddressFailedException: 501 Bad address syntax

at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1917)
... 10 more
Finished: FAILURE
`

错误原因: 输入的接收邮箱地址是无效的格式;