前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >1.Jenkins入门基础介绍与持续化集成部署

1.Jenkins入门基础介绍与持续化集成部署

作者头像
全栈工程师修炼指南
发布2022-09-29 19:09:24
3.8K0
发布2022-09-29 19:09:24
举报

[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环境;

代码语言:javascript
复制
# 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/

官方安装:

代码语言:javascript
复制
# 添加  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

国内安装:

代码语言:javascript
复制
# 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

# 环境安装测试
root@jenkins:/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

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

WeiyiGeek.选择安装的插件

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

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

WeiyiGeek.初始化成功页面

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

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

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

代码语言:javascript
复制
# 配置文件
/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 任务的文件夹中存储的文件有:

代码语言:javascript
复制
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 服务另外的文件目录:

代码语言:javascript
复制
secrets
init.groovy.d
workflow-libs
scriptler
config-history

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

Docker 安装

描述: 使用容器化的方式部署 Jenkins Master 节点,可以选择自行构建镜像,推荐使用 Jenkins 官方提供的镜像。

Jenkins 服务官方在 dockerhub 平台发布官方镜像https://hub.docker.com/u/jenkins

1.Jenkins Master 镜像基础使用

  • Jenkins Web 服务监听的端口为 8080
  • Jenkins 使用JNLP 连接 Agent 节点使用的端口为 5000
  • Jenkins 在 /var/jenkins_home 目录中保存workspace中的数据,包括插件和配置信息
  • Jenkins 服务默认使用jenkins 用户运行,uid为1000;请注意文件权限问题

2.Jenkins Master 使用和升级 使用 Jenkins 的镜像构建容器时,至少要将端口映射出去,将/var/jenkins_home 目录做持久化。

代码语言:javascript
复制
# 示例:用 jenkins:2.107.3 创建容器并运行。
docker volume create jenkins-data
docker run --name jenkins-production \
           --detach \
           -p 50000:50000 \
           -p 8080:8080 \
           -v jenkins-data:/var/jenkins_home \
           jenkins/jenkins:2.275-alpine
# If run for the first time, just run the following to get the admin
# password once it has finished starting
docker exec jenkins-production bash -c 'cat $JENKINS_HOME/secrets/initialAdminPassword'

在需要对 Jenkins 服务升级时,只需要使用新的镜像替换即可;持久化存储和端口映射操作相同。 示例:将 Jenkins 服务升级到 2.121.3

代码语言:javascript
复制
docker stop jenkins-production
docker rm jenkins-production 
# just temporarily docker rename it instead if that makes you worried
docker run --name jenkins-production \
           --detach \
           -p 50000:50000 \
           -p 8080:8080 \
           -v jenkins-data:/var/jenkins_home \
           jenkins/jenkins:2.277-alpine

3.Jenkins Master 节点配置扩展(了解即可)

3.1 设置Master 节点的执行者 executors 数量 描述: 使用groovy脚本指定并设置Jenkins Master 实例的执行程序数。默认情况下,它设置为2个执行者,但是您可以扩展映像并将其更改为所需的执行者数:

代码语言:javascript
复制
executors.groovy
import jenkins.model.*
Jenkins.instance.setNumExecutors(5)

# 和 Dockerfile

FROM jenkins/jenkins:lts
COPY executors.groovy /usr/share/jenkins/ref/init.groovy.d/executors.groovy

3.2 传递 JVM 的启动参数 描述: 您可能需要自定义运行Jenkins的 JVM,通常是为了传递系统属性(props列表)或调整堆内存设置

代码语言:javascript
复制
# 使用JAVA_OPTS环境变量:
docker run --name myjenkins -p 8080:8080 -p 50000:50000 --env JAVA_OPTS=-Dhudson.footerURL=http://mycompany.com jenkins/jenkins:lts

3.3 给 Jenkins 启动器传递参数 描述: 您传递给运行 Jenkins 镜像的 docker 的参数将传递给 jenkins 启动器 ,例如运行 docker run jenkins/jenkins:lts --version 将显示Jenkins版本

代码语言:javascript
复制
# 通过定义Jenkins参数 JENKINS_OPTS
示例1.Dockerfile使用此选项来强制将HTTPS与映像中包含的证书一起使用。
FROM jenkins/jenkins:lts
COPY https.pem /var/lib/jenkins/cert
COPY https.key /var/lib/jenkins/pk
ENV JENKINS_OPTS --httpPort=-1 --httpsPort=8083 --httpsCertificate=/var/lib/jenkins/cert --httpsPrivateKey=/var/lib/jenkins/pk
EXPOSE 8083

# 通过定义Jenkins参数 JENKINS_SLAVE_AGENT_PORT
示例2.Dockerfile中定义来更改jenkins的默认从属代理端口。
FROM jenkins/jenkins:lts
ENV JENKINS_SLAVE_AGENT_PORT 50001
# 或作为docker的参数
docker run --name myjenkins -p 8080:8080 -p 50001:50001 --env JENKINS_SLAVE_AGENT_PORT=50001 jenkins/jenkins:lts

Tips :此环境变量将用于设置将系统属性添加jenkins.model.Jenkins.slaveAgentPort到JAVA_OPTS的端口 。

3.4 配置日志记录 描述: 可以通过属性文件和java.util.logging.config.fileJava属性来配置Jenkins日志记录。例如:

代码语言:javascript
复制
mkdir data

cat > data/log.properties <<EOF
handlers=java.util.logging.ConsoleHandler
jenkins.level=FINEST
java.util.logging.ConsoleHandler.level=FINEST
EOF

docker run --name myjenkins -p 8080:8080 -p 50000:50000 \
--env JAVA_OPTS="-Djava.util.logging.config.file=/var/jenkins_home/log.properties"\
 - v `pwd`/data:/var/jenkins_home jenkins/jenkins:lts

3.5 调整Jenkins 浏览器访问的路径path 描述: 如果您需要在浏览器中访问 Jenkins 服务时要添加一个 path 路径,则需要添加环境变量JENKINS_OPTS="--prefix=/jenkins"

Tips : 容器中 Docker 客户端配置

1.构建 NodeJS 任务执行镜像的 Dockerfile 文件内容:

代码语言:javascript
复制
FROM docker.io/node:alpine
run apk add --no-cache git docker-cli
RUN yarn config set registry "https://registry.npmmirror.com"

2.配置 Docker 客户端连接远程的 Docker 服务端:使用一个环境变量就可以实现这个配置。

代码语言:javascript
复制
env:
- name: DOCKER_HOST
  value: tcp://docker.example.com:2375

Tips : 配置镜像仓库的认证信息,认证信息一般存储在 /root/.docker/config.json 文件中。这里可以模仿前面 Maven 服务的 settings.xml 文件的配置方式配置, 然后就可以实现了连接 Docker Server 端构建镜像,对镜像打 tag 的操作, 然后将制作好的镜像推送到远程的镜像仓库中,例如Harbor。

Kubernetes 安装

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


0x02 基础知识

Jenkins 环境变量

描述: 环境变量可以被看作是pipeline与Jenkins交互的媒介, 环境变量可以分为Jenkins内置变量自定义变量以及自定义全局环境变量

比如,可以在 pipeline 中通过 BUILD_NUMBER 变量知道构建任务的当前构建次数。

1.内置变量 描述: 在pipeline执行时,Jenkins通过一个名为 env 的全局变量,将Jenkins内置环境变量暴露出来。

代码语言:javascript
复制
${env.BUILD_NUMBER} 方式一,推荐使用
$env.BUILD_NUMBER 方式二,
${BUILD_NUMBER} 方式三,不推荐使用

例如:在实际工作中经常用到的变量。

代码语言:javascript
复制
BUILD_URL:当前构建的页面URL。
BUILD_NUMBER:构建号,累加的数字。
BRANCH_NAME:多分支pipeline项目支持。
GIT_BRANCH:通过git拉取的源码构建的项目才会有此变量。

2.自定义环境变量 描述: 当 pipeline 变得复杂时,我们就会有定义自己的环境变量的需求。声明式 pipeline 提供了environment 指令,方便自定义变量。

另外 environment 指令可以在pipeline中定义,代表变量作用域为整个 pipeline;也可以在 stage 中定义,代表变量只在该阶段有效。

Tips : 如果在environment中定义的变量与env中的变量重名,那么被重名的变量的值会被覆盖掉。

3.自定义全局环境变量 描述: 如果我们需要定义一些全局的跨pipeline的自定义变量。

我们可以进入 Manage Jenkins→Configure System→Global properties 页,勾选“Environment variables”复选框,单击“Add”按钮,在输入框中输入变量名和变量值即可,

Tips : 自定义全局环境变量会被加入 env 属性列表中,所以,使用自定义全局环境变量与使用Jenkins内置变量的方法无异。

Tips : Jenkins 内置变量参考 请看补充说明中的内置环境变量

Jenkins 参数构建类型

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

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

额外的我们需要安装Extended Choice Parameter 和 git Parameter,以便向 Choice 参数添加扩展功能 以及 使用Git参数来获取分支。

使用过程在参数化构建过程 -> 构建参数添加 -> 构建参数的变量 ->通过

WeiyiGeek.构建参数
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.并发构建

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

WeiyiGeek.triggers

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

代码语言:javascript
复制
# * * * * *
# 第一颗*表示分钟,取值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分钟检查一次源码变化有变化就执行;

代码语言:javascript
复制
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.上下游构建

WeiyiGeek.上下游构建

Jenkins 调用API

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

Jenkins API 介绍

1.Jenkins API 从级别上分类

代码语言:javascript
复制
* 站点 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封装包,结合到自己的脚本中,提高开发效率。

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

CURL 调用 API 执行 Job 实例:

代码语言:javascript
复制
# 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 - 视图方式

代码语言:javascript
复制
views视图更加灵活,不改变job的路径
views有多种形式、层级、看板,流水线等多样化

directory - 文件夹方式 (名称空间隔离)

代码语言:javascript
复制
文件夹适合多个团队共用Jenkins
性能更好,执行速度更快
支持RBAC权限管理

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

views - 视图方式 创建流程:

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

WeiyiGeek.views

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

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

WeiyiGeek.插件安装加速

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

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

WeiyiGeek.Jenkins 汉化插件安装

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

WeiyiGeek.Jenkins 汉化界面
WeiyiGeek.Jenkins 汉化界面

WeiyiGeek.Jenkins 汉化界面

WeiyiGeek.Jenkins git 插件安装
WeiyiGeek.Jenkins git 插件安装

WeiyiGeek.Jenkins git 插件安装

Step 3.导入之前服务器已安装的插件进行离线安装;

代码语言:javascript
复制
# (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默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,我们使用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权限管理

WeiyiGeek.jenkins权限管理

构建工具管理

在 Jenkins 服务中运行 Pipeline 等任务过程中,需要依赖一些工具(环境需求);比如 JDK,MAVEN或者golang 或者 python 环境。

构建工具的安装方式有三种:

  • 1) 自行安装工具: 即自行在服务器上安装配置,然后在 Jenkins 服务中配置好这些工具的安装信息就可以使用了。配置路径:Manage Jenkins→Global Tool Configuration
  • 2) Jenkins 自动安装工具: 利用 Jenkins 服务提供的【工具自动安装功能】,实现工具的快速配置。
  • 3) tools 指令安装工具:帮助我们自动下载并安装所指定的构建工具,并将其加入 PATH 变量中。这样,我们就可以在sh步骤里直接使用了, 但在agent none的情况下不会生效。

Tips : tools指令默认支持3种工具:JDK、Maven、Gradle。通过安装插件,tools 指令还可以支持更多的工具。


0x04 基础使用

HelloWorld 自由风格软件项目

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

操作流程:

Step 1.项目创建

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

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

(3) Dashboard -> 项目名称 freestyle-helloworld > 构建 > 执行 Shell 命令 echo "FreeStyle - HelloWorld" touch hello-world.txt

WeiyiGeek.自由风格的软件项目
WeiyiGeek.自由风格的软件项目

WeiyiGeek.自由风格的软件项目

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

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

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

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

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

代码语言:javascript
复制
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 所需插件
代码语言:javascript
复制
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关联插件

WeiyiGeek.Gitlab关联插件

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

操作流程:

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

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

代码语言:javascript
复制
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

WeiyiGeek.gitlab

  • Step 2.此处假设您已经按照上面Gitlab 集成配置安装了相应的插件, 并且配置好gitlab域名访问的解析记录;
代码语言:javascript
复制
# 此处由于没有自己搭建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 的方式)
代码语言:javascript
复制
# (1) 在Gitlab中添加当前机器ssh密钥(此处以Jenkins用户为例)
jenkins@jenkins:~$ssh-keygen -t ed25519 -C "jenkins@weiyigeek.top"
~$ ls ~/.ssh/id_ed25519
  # id_ed25519      id_ed25519.pub

# (2) 添加公钥到gitlab中 
# > 用户设置 -> SSH Keys -> jenkins-CI
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINFb2ALOnOpePb7e/tss4/ZKxNHb3srh7NXntW5jAWSf jenkins@weiyigeek.top

# (3) 主机认证指纹绑定
jenkins@jenkins:~$ git ls-remote -h -- git@gitlab.weiyigeek.top: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

WeiyiGeek.SSH Keys

  • Step 4.Jenkins > FreeStyle 项目 > 源码管理 > Git > Repositories 设置 > Credentials 设置 PS : 如果是非Jenkins用户下公钥对Gitlab该项目有访问权限时,可以通过 Credentials 添加其认证的密钥即可;
代码语言:javascript
复制
# (1) Weiyigeek 用户密钥 (此时假设Gitlab已经添加该公钥)
weiyigeek@jenkins:~$ 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 用户密钥

WeiyiGeek.Weiyigeek 用户密钥

Step 5.首先手动实现设置NFS共享存储以及 Kubernetes 部署 StatefulSet 资源清单,通过Nginx访问我们的blog; 基础配置:

代码语言:javascript
复制
# (1) NFS 服务器配置
root@nfs$ 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/

资源清单:

代码语言:javascript
复制
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

部署资源清单:

代码语言:javascript
复制
~/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

效果查看:

代码语言:javascript
复制
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:git@gitlab.weiyigeek.top:ci-cd/blog.git > Credentials (密钥认证) -> 分支机构建设 (指定分支(为空时代表any))-> 引入 ${git_version} 变量 构建 > 执行shell > /bin/sh -x /tmp/script/blog-script.sh 应用 > 保存

WeiyiGeek.jenkins项目创建
WeiyiGeek.jenkins项目创建

WeiyiGeek.jenkins项目创建

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

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

代码语言:javascript
复制
#!/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="weiyigeek@10.10.107.202"
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  weiyigeek@10.10.107.202:${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 公钥认证登录;

代码语言:javascript
复制
# copy 公钥 到 对端主机
ssh-copy-id -p 20211 weiyigeek@10.10.107.202
  # /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.
  # weiyigeek@10.10.107.202's password:

  # Number of key(s) added: 1

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

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

代码语言:javascript
复制
$ cd ~/workspace/freestyle-blog
jenkins:~/workspace/freestyle-blog$ git config --global user.email "jenkins@weiygeek.top"
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.项目构建

WeiyiGeek.项目构建

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

代码语言:javascript
复制
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.项目构建部署验证

WeiyiGeek.项目构建部署验证

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

WeiyiGeek.项目回退验证
WeiyiGeek.项目回退验证

WeiyiGeek.项目回退验证

Maven 集成配置与实践

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

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

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

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

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

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

代码语言:javascript
复制
# 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 插件安装;

代码语言:javascript
复制
# 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 集成配置

WeiyiGeek.Maven 集成配置

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

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

代码语言:javascript
复制
<!-- # (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代码项目程序拉取:

代码语言:javascript
复制
$ git clone git@gitlab.weiyigeek.top: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

构建与运行测试:

代码语言:javascript
复制
~/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

WeiyiGeek.Maven-hello-world

Step 3.在 Kubernets 上 准备接受 Jenkins 推送过来的war包的项目环境; 基础配置:

代码语言:javascript
复制
# (1) NFS 服务器上配置 (PS:由于测试资源有限 则 nfs 与 k8s master 在同一台机器上)
root@nfs$ 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 weiyigeek@10.10.107.202:/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存储类(访问日志))

代码语言:javascript
复制
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

资源清单构建:

代码语言:javascript
复制
# (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-> 应用并保存

构建测试结果:

代码语言:javascript
复制
# 项目拉取
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 git@gitlab.weiyigeek.top: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"

代码语言:javascript
复制
#!/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="weiyigeek@10.10.107.202"
K8S_MATER_PORT="20211"

# 部署
deploy () {
  # 1.上传Maven打包的war包到master之中
  scp -P ${K8S_MATER_PORT} ${WORKSPACE}/target/*.war  weiyigeek@10.10.107.202:${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

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

WeiyiGeek.jenkins-ci-deploy

Step 8.回滚测试 构建参数: deploy_option->rollback , git_version -> v1.1

代码语言:javascript
复制
# 构建推送反馈
[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
+ K8S_MATER=weiyigeek@10.10.107.202
+ K8S_MATER_PORT=20211
+ [[ rollback = \d\e\p\l\o\y ]]
+ [[ rollback = \r\o\l\l\b\a\c\k ]]  # 进行回滚操作
+ rollback
++ ssh -p 20211 weiyigeek@10.10.107.202 '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 weiyigeek@10.10.107.202 '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

代码语言:javascript
复制
# (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
+ K8S_MATER=weiyigeek@10.10.107.202
+ 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 weiyigeek@10.10.107.202 '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 weiyigeek@10.10.107.202 '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 weiyigeek@10.10.107.202:/nfs/data4/war/Maven-HelloWorld-20201227-021934-v1.2.war
# 解压上传的war 并创建软连接
+ ssh -p 20211 weiyigeek@10.10.107.202 '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 集成实践完成

补充介绍: 除了上面在项目的Pom.xml中设置内部Maven服务器,我们可以可以采样下面两种方式指定配置文件

方式1.通过 curl 在构建前下载 Git 版本控制的 Maven 自定义的 setting.xml 配置文件(在我后面K8s中构建时会看见)。

方式2.采用 Managed file(可以配置 Maven 的全局配置文件和用户配置文件)Maven Integration 插件

代码语言:javascript
复制
// Config File Provider 插件使用配置文件
configFileProvider([configFile(fileId:'maven-global-settings',variable:'MAVEN_GLOBAL_ENV')]) {
  sh "mvn -s $MAVEN_GLOBAL_ENV clean install"
}

// Pipeline Maven Integration 插件使用配置文件
withMaven(
  // Maven installation declared in the Jenkins "Global Tool Configuration"
  maven: 'maven-3',
  // Maven settings.xml file defined with the Jenkins Config File Provider Plugin
  // We recommend to define Maven settings.xml globally at the folder level using 
  // navigating to the folder configuration in the section "Pipeline Maven Configuration / Override global Maven configuration"
  // or globally to the entire master navigating to  "Manage Jenkins / Global Tools Configuration"
  mavenSettingsConfig: 'my-maven-settings') {
    // Run the maven build
    sh "mvn clean verify"

  } // withMaven will discover the generated Maven artifacts, JUnit Surefire & FailSafe & FindBugs & SpotBugs reports...

SonarQube 集成配置与实践

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

操作流程:

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

代码语言:javascript
复制
Jenkins: 755eeb453cb28f96aa9d4ea14334da7287c2e840
# 此令牌用于执行分析时认证时使用,如果这个令牌存在问题,可以随时在你的用户账号下取消这个令牌。

Step 1.插件安装: 系统管理 -> 插件管理 -> SonarQube Scanner for Jenkins()

WeiyiGeek.SonarQube Scanner for Jenkins
WeiyiGeek.SonarQube Scanner for Jenkins

WeiyiGeek.SonarQube Scanner for Jenkins

Step 2.在Jenkins系统管理->系统设置以及全局工具管理->上配置SonarQube相关配置(服务端地址,以及客户端工具地址);

代码语言:javascript
复制
# (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配置

WeiyiGeek.Jenkins上SonarQube配置

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

代码语言:javascript
复制
# 构建前进行分析配置(名称、唯一标识、检测目录)
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

WeiyiGeek.SonarQube Analysis Properties

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

代码语言:javascript
复制
WeiyiGeek@WeiyiGeek 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项目检测结果

WeiyiGeek.SonarQube项目检测结果

Step 5.项目在K8s集群中部署结果

代码语言:javascript
复制
# 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通知等;

通知插件插件安装:

代码语言:javascript
复制
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服务;

代码语言:javascript
复制
# 客户端设置方法
接收服务器:
imap.exmail.qq.com(使用SSL,端口号993)
发送服务器:
smtp.exmail.qq.com(使用SSL,端口号465)
WeiyiGeek.腾讯企业邮箱
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.发信邮箱相关配置

WeiyiGeek.发信邮箱相关配置

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

代码语言:javascript
复制
# 收信人: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.项目通信发信测试

WeiyiGeek.项目通信发信测试

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

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

1) 通过系统管理→系统设置,进行邮件配置 -> Extended E-mail Notification -> 输入 SMTP Server 相关信息以及Authentication相关设置(注意:密码一般是邮箱授权码)

2) 设置其编码格式以及默认内容类型,以及邮件模板配置在 Extended E-mail的 default content -;

代码语言:javascript
复制
<!-- ^\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.设置

WeiyiGeek.设置

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

WeiyiGeek.Email-Notification

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

代码语言:javascript
复制
例如:https://oapi.dingtalk.com/robot/send?access_token=95f707645db08794166ed3aad3eaad363bb1475bf7c91635b7456a0a8c8893c6
WeiyiGeek.钉钉群聊机器人添加
WeiyiGeek.钉钉群聊机器人添加

WeiyiGeek.钉钉群聊机器人添加

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

WeiyiGeek.钉钉消息通知参数
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风格构建的钉钉通知

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

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

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

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

WeiyiGeek.企业微信全局参数

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

代码语言:javascript
复制
# 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 项目进行构建并查看控制台输出,消息推送;

代码语言:javascript
复制
# 构建前发送
> 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 weiyigeek@10.10.107.202 '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.企业微信通知实现效果

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


0x05 补充说明

(1) 内置环境变量

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

代码语言:javascript
复制
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.

测试环境变量:

代码语言:javascript
复制
#!/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

测试结果:

代码语言:javascript
复制
+ /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/Maven-HelloWorld@tmp
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: git@gitlab.weiyigeek.top: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.找到用户的路径

代码语言:javascript
复制
[root@jenkins-node1 ~]# cd /var/lib/jenkins/users/
[root@jenkins-node1 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>那行删除,改为如下内容-

代码语言:javascript
复制
[root@jenkins-node1 users]# vim config.xml
<passwordHash>#jbcrypt:$2a$10$slYx6.2Xyss6w9LnuiwnNOReuvkcSkaI.Y.Z2AC6Sp7hdF7hhxlsK</passwordHash>

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

(3) Jenkins 升级迁移

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

操作流程:

代码语言:javascript
复制
# (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

WeiyiGeek.Jenkins UI


0x06 入坑&出坑

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

代码语言:javascript
复制
$ 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

解决办法:

代码语言:javascript
复制
sudo apt install -y daemon

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

代码语言:javascript
复制
$ 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执行环境;

解决流程:

代码语言:javascript
复制
①.先执行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的工作目录

代码语言:javascript
复制
# 打开 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

WeiyiGeek.Jenkins Please wait

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

代码语言:javascript
复制
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 – git@gitlab.weiyigeek.top:ci-cd/blog.git HEAD” returned status code 128: 问题复原:

代码语言:javascript
复制
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 git@gitlab.weiyigeek.top保存其主机的公钥信息;

代码语言:javascript
复制
# 例如 首次连接Gitlab时候需要进行主机于公钥绑定
ssh -T git@gitlab.com
# 无法建立主机“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: 错误信息:

代码语言:javascript
复制
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 错误信息:

代码语言:javascript
复制
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

错误信息:

代码语言:javascript
复制
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
`

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 前言简述
    • Jenkins 介绍
      • Jenkins 特性
        • Jenkins 应用场景
          • Jenkins Job 类型
          • 0x01 安装配置
            • Ubuntu
              • Docker 安装
                • Kubernetes 安装
                • 0x02 基础知识
                  • Jenkins 环境变量
                    • Jenkins 参数构建类型
                      • Jenkins 并发构建
                        • Jenkins 自动化构建
                          • Jenkins 上下游构建
                            • Jenkins 调用API
                            • 0x03 基础配置
                              • 视图管理
                                • 插件管理
                                  • 权限管理
                                    • 构建工具管理
                                    • 0x04 基础使用
                                      • HelloWorld 自由风格软件项目
                                        • Gitlab 集成配置与实践
                                          • Maven 集成配置与实践
                                            • SonarQube 集成配置与实践
                                              • 邮箱&钉钉&微信消息通知 集成配置与实践
                                              • 0x05 补充说明
                                                • (1) 内置环境变量
                                                  • (2) Jenkins 管理员密码忘记重置
                                                    • (3) Jenkins 升级迁移
                                                    • 0x06 入坑&出坑
                                                    相关产品与服务
                                                    容器服务
                                                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                    领券
                                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档