0%

DevOps 的第一步,从零掌握 Jenkins

logo

一、安装 Jenkins

Jenkins 是一个 Java 程序,运行前需要先安装 Java。

各版本中对 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

Jenkins 是一个完全插件化的平台,所有功能都是通过插件来完成。

安装主程序

支持 Yum、RPM、War 等多种安装方式。

1、使用 Yum 安装

1
2
3
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
yum install jenkins

启动服务

1
yum install jenkins

添加开启启动,默认不支持 systemd,要使用 chkconfig

1
2
chkconfig --add jenkins
chkconfig --level 2345 jenkins on

2、下载 RPM 包手动安装

长期支持版本 (LTS) Red-Hat 系下载地址。

下载到服务器的相应目录。

1
yum install ./jenkins-2.190.1-1.1.noarch.rpm

启动服务

1
yum install jenkins

添加开启启动,默认不支持 systemd,要使用 chkconfig

1
2
chkconfig --add jenkins
chkconfig --level 2345 jenkins on

3、下载 war 包并直接启动

长期支持版本 (LTS) War 包下载地址。

下载到服务器的相应目录。

可以直接运行 Jenkins。

1
java -jar jenkins.war

开启 JMX

也可以在启动时打开 JMX 以后续提供给 ZABBIX 监控使用。

1
2
3
4
5
6
7
java \
-Dcom.sun.management.jmxremote=true \
-Djava.rmi.server.hostname="Jenkins_SERVER_IP" \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-jar jenkins.war &

二、Jenkins 基础配置

  • /etc/sysconfig/jenkins:主配置文件;
    • JENKINS_HOME="/var/lib/jenkins":定义数据文件存放路径;
    • JENKINS_USER="jenkins":定义使用哪个用户启动服务。要注意在后期构建时,jenkins 账户要拥有对应的权限,或者直接使用 root,不过不太安全;

初始化 Jenkins

从浏览器就可以访问 http://IP:8080/ 登录 Jenkins 了。

第一次登陆时,需要输入管理员的临时密码,保存在 /var/lib/jenkins/secrets/initialAdminPassword 内。

Jenkins_1

之后可以自己 选择插件安装,或者直接 安装推荐的插件,安装过程为在线安装。

Jenkins_2

创建第一个管理员用户,或者点击下方的按钮使用 admin 账户作为管理员账户。

Jenkins_3

配置实例的 URL,这很重要,用于给各种 Jenkins 资源提供绝对路径链接的根地址,

Jenkins_4

添加权限管理模块

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

  1. 先安装角色插件 Role-based Authorization Strategy
  2. 系统管理 -> 全局安全配置 -> 授权策略 选择 Role-Based Strategy
  3. 之后在 系统管理 中就会多出一个配置叫 Manage and Assign Roles,点击进入就可以配置角色了。

Manage Roles 中可以配置角色的详细权限,分为 全局角色项目角色Slave 角色,顾名思义区别就是生效范围不一样。

这里创建了一个角色 manager,只给它分配了可读的权限。
Jenkins_6

然后新建一个账号 monster,并把刚刚创建的角色分配给它。
Jenkins_7

然后就可以使用 monster 登录了,登录之后就会发现此账号只有只读权限。

配置 Jenkins 系统管理员邮箱

系统管理 -> 系统设置 -> Jenkins Location 中的 系统管理员邮件地址 添加管理员用于发送系统邮件的邮箱地址。

之后在最下边的 邮件通知 中配置详细的邮件参数,以 163 邮箱为例:

  • SMTP 服务器:smtp.163.com
  • 用户默认邮件后缀:@163.com
    • 建议:使用 SSL 协议
  • SMTP 端口:465

三、使 Jenkins 基于 SSH Key 从 Gitlab 拉取代码

1. 安装 Gitlab 插件

先安装 Gitlab 的插件,以支持从 Gitlab 拉取代码。

系统管理 -> 插件管理 -> 可选插件 中搜索 Gitlab,安装如下 3 个插件。

Jenkins_5

Gitlab Hook 插件安装失败解决办法

如果 Gitlab Hook 插件安装失败,且显示是因为依赖的 ruby-runtime 无法安装。

编辑 Jenkins 的配置文件 /etc/sysconfig/jenkins,找到 JENKINS_JAVA_OPTIONS,改成:

1
JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true -Dhudson.ClassicPluginStrategy.noBytecodeTransformer=true"

2. 上传 ssh 公钥到 Gitlab

先在客户端生成 ssh 的密钥对,然后登录你要设置免密的 Gitlab 账户后,点击 右上角的头像 -> 设置 -> SSH 秘钥,把刚才生成的公钥贴进去。

然后在客户端就可以直接免密进行克隆,或推送仓库了,不过记得要使用 SSH 协议的仓库地址才可以。

3. 创建 Job

现在可以创建任务了,创建任务时,Jenkins 可以自动从 Gitlab 拉取代码,然后自动执行指定的操作,比如构建、打包等,所以要把 Gitlab 仓库中公钥的对应私钥上传到 Jenkins 中,在 首页 -> 凭据 里添加即可。

创建好的任务在 /var/lib/jenkins/workspace 目录下会生成和任务名一样的目录,以后拉取的源码也都存在这里。

可以根据实际情况,在创建 Job 时勾选 Delete workspace before build starts,实现删除本地旧的仓库代码。而且删除操作还可以选择在 构建环境 前还是 构建环境 后。

四、如何添加 Slave 节点

slave 节点的部署是由 master 通过 SSH,连接到 Slave 节点中自动安装的,人为只需要做一些准备工作即可。

准备工作

先保证 Master 和 Slave 做好时间同步,然后在 Slave 节点上安装依赖的 java 环境:

1
yum install java

并在 Slave 服务器上创建工作数据目录:

1
2
3
mkdir -p /var/lib/jenkins/slave
mkdir -pv /var/lib/jenkins/slave/jdk/bin
ln -s /usr/bin/java /var/lib/jenkins/slave/jdk/bin/java

部署 Slave 节点

之后回到 Jenkins 的 web 中,点击 系统管理 -> 节点管理 -> 新建节点 来添加 slave 节点:
因为 Master 要通过 SSH 连接至 Slave,所以添加节点时要配置连接凭据。可以使用 root 加密码的方式,也可以使用 SSH 的密钥对。

五、使用 Pipline 流水线

Pipline 是什么?

Pipline 是帮助 Jenkins 实现 CI 到 CD 转变的重要角色,是运行在 jenkins 2.X 版本的核心插件。

简单来说 Pipline 就是一套运行于 Jenkins 上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂发布流程,从而实现单个任务很难实现的复杂流程编排和任务可视化,Pipeline 的实现方式是一套 Groovy DSL,任何发布流程都可以表述为一段 Groovy 脚本。

Pipline 的优势

  • 可持续性:jenkins 的重启或者中断后不影响已经执行的 Pipline Job
  • 支持暂停:Pipline 可以选择停止并等待人工输入或批准后再继续执行。
  • 可扩展:通过 groovy 的编程更容易的扩展插件。
  • 并行执行:通过 groovy 脚本可以实现 step,stage 间的并行执行,和更复杂的相互依赖关系。

Pipline 语法

  • Stage:阶段,一个 Pipline 可以划分为若干个 stage,每个 stage 都是一个操作,比如 clone 代码、代码编译、代码测试和代码部署,阶段是一个逻辑分组,可以跨多个 node 执行。
  • Node:节点,每个 node 都是一个 jenkins 节点,可以是 jenkins master 也可以是 jenkins agent,node 是执行 step 的具体服务器。
  • Step:步骤,step 是 jenkins Pipline 最基本的操作单元,从在服务器创建目录到构建容器镜像,由各类 Jenkins 插件提供实现,例如调用 shell 插件来执行命令的写法为:sh "date"

和 Job 的不同:从代码拉取,到编译打包、部署的全过程,都需要写在 Pepline 脚本中。

创建 Pipeline

在创建任务的界面中,点击 流水线的语法 可以自动生成常用动作的脚本,比如从 Git 拉取仓库、删除旧工作目录等。

示例:创建一个 Pipline 脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
node("slave_1"){      # 括号内写 slave 名字,就指定使用哪个 slave 节点运行,如果 ("slave") 不写则在主节点
stage("delete dir"){
deleteDir()
}
stage("code clone"){
echo "git clone"
git credentialsId: 'b695c060-6a99-4ee3-bd4c-730bd4dd36ec', url: 'git@192.168.8.3:testservice/test-project.git' # 使用“流水线语法”可以自动生成
sh "cd /root/.jenkins/workspace/pipline-test && tar czvf code.tar.gz ./*"
}
stage("code build"){
echo "code build"
}
stage("code test"){
echo "code test"
}
stage("code deploy"){
echo "code deploy"
}
}

六、代码质量测试

代码质量七宗罪:

  • 编码规范:是否遵守了编码规范,遵循了最佳实践。
  • 潜在的 BUG:可能在最坏情况下出现问题的代码,以及存在安全漏洞的代码。
  • 文档和注释:过少(缺少必要信息)、过多(没有信息量)、过时的文档或注释。
  • 重复代码:违反了 Don’t Repeat Yourself 原则。
  • 复杂度:代码结构太复杂(如圈复杂度高),难以理解、测试和维护。
  • 测试覆盖率:编写单元测试,特别是针对复杂代码的测试覆盖是否足够。
  • 设计与架构:是否高内聚、低耦合,依赖最少。

SonarQube 是什么?

sonar

SonarQube 是一个开源的用于代码质量管理、代码测试的开放平台,通过插件机制,SonarQube 可以集成不同的测试工具,如代码分析工具、持续集成工具等。

与持续集成工具不同(例如 Hudson/Jenkins 等),SonarQube 并不是简单地把不同的代码检查工具结果(例如 FindBugs,PMD 等)直接显示在 Web 页面上,而是通过不同的插件对这些结果进行再加工处理,通过量化的方式度量代码质量的变化,从而可以方便地对不同规模和种类的工程进行代码质量管理。

在对其他工具的支持方面,Sonar 不仅提供了对 IDE 的支持,可以在 Eclipse 和 IntelliJ IDEA 这些工具里联机查看结果;同时 Sonar 还对大量的持续集成工具提供了接口支持,可以很方便地在持续集成中使用 SonarQube。此外,SonarQube 的插件还可以对 Java 以外的其他编程语言提供支持,对国际化以及报告文档化也有良好的支持。

安装方法

下载 sonarqube

官方下载页面:https://www.sonarqube.org/downloads/
当前社区版本为:SonarQube 7.9.x LTS(2019年7月)

环境依赖:

  • 需要 Java 11
  • 数据库需要 PostgreSQL 10、9.3–9.6。注意:从版本7.9开始,SonarQube 将不再支持 MySQL。

配置文件最大打开限制

1
2
3
4
5
6
7
8
~]# vim /etc/sysctl.conf
vm.max_map_count=262144
fs.file-max=65536

~]# vim /etc/systemd/system.conf
DefaultLimitNOFILE=65536
DefaultLimitNPROC=4096
~]# system -p

安装 Java-11

1
systemctl install java-11

安装 Postgresql-11

创建 Sonar 数据库

1
2
3
4
5
6
7
8
9
10
11
12
su - postgres
psql

# 配置管理员账号的密码
ALTER USER postgres with encrypted password 'postgres';

# 创建 sonarqube 库并赋予用户 sonarqube 所有权限
create user sonarqube with password 'sonarqube';
create database sonarqube owner sonarqube;
grant all on database sonarqube to sonarqube;
create schema my_schema;
\q

为 postgresql 开启远程访问权限

1
2
3
4
5
6
7
8
9
10
11
12
13
vim /var/lib/pgsql/9.6/data/postgresql.conf   
#listen_addresses = '*'
vi /var/lib/pgsql/9.6/data/pg_hba.conf
# IPv4 local connections:
host all all 0.0.0.0/0 trust
# IPv6 local connections:
host all all ::1/128 ident
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local replication postgres peer
#host replication postgres 127.0.0.1/32 ident
#host replication postgres ::1/128 ident
host all all 0.0.0.0/0 ident

新建用户

1
2
useradd sonarqube
echo 'sonarqube' | passwd sonarqube --stdin

安装程序

  • 把安装包上传到 Jenkins 服务器的 /usr/local/src 目录下并解压,要注意文件夹修改为 sonarqube 账户的权限。
1
2
3
4
5
cd /usr/local/src
unzip sonarqube-7.9.1.zip
chown -R sonarqube:sonarqube /usr/local/src/sonarqube-7.9.1
ln -sv /usr/local/src/sonarqube-7.9.1 /usr/local/sonarqube
‘sonarqube’ -> ‘sonarqube-7.9.1’

编辑配置文件

  • 编辑主配置文件:vim usr/local/sonarqube/conf/sonar.properties
  • 配置数据库信息,把与所安装的数据库对应的配置段注释解除,我使用的是 PostgreSQL。
1
2
3
4
5
sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonarqube

# localhost 要改成数据库的地址,我这里是本地就保持原样了
sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube?currentSchema=my_schema

最后,启动 Sonarqube

  • 使用脚本启动 sonarqube 服务。
1
/usr/local/sonarqube/bin/linux-x86-64/sonar.sh start

在浏览器登录 192.168.50.12:9000,默认是没有登录的状态,点击右上角 Login 登录,默认账号 admin/admin

开启中文界面的方法

Administrator -> Marketplace -> PluginsAll 的搜索框中,输入 chinese pack 并安装。

安装好后在弹出的通知栏中点重启,等重启后系统界面就变成中文的了。

扫描器 sonar-scanner

sonarqube 通过调用扫描器 sonar-scanner 进行代码质量分析,即扫描器的具体工作就是扫描代码

部署

下载安装

1
2
3
wget -P /usr/local/src https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.0.0.1744-linux.zip
unzip sonar-scanner-cli-4.0.0.1744-linux.zip
ln -sv /usr/local/src/sonar-scanner-4.0.0.1744-linux /usr/local/sonar-scanner

编辑配置文件

  • 编辑全局配置文件,解除注释,以指向 SonarQube 服务器。
1
2
3
4
5
6
vim /usr/local/sonar-scanner/conf/sonar-scanner.properties
#----- Default SonarQube server
sonar.host.url=http://localhost:9000

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

添加命令到搜索目录

1
ln -sv /usr/local/sonar-scanner/bin/sonar-scanner /usr/sbin

验证安装

  • 验证安装,打开新的 shell 并执行命令 sonar-scanner -h,应该获得如下输出:
1
2
3
4
5
6
7
8
9
-> # sonar-scanner -h
INFO:
INFO: usage: sonar-scanner [options]
INFO:
INFO: Options:
INFO: -D,--define <arg> Define property
INFO: -h,--help Display help information
INFO: -v,--version Display version information
INFO: -X,--debug Produce execution debug output

开始扫描

  • 在需要被扫描的源码的项目目录中,创建一个配置文件:vim ./sonar-project.properties
1
2
3
4
5
6
7
8
9
10
11
12
# 定义在 SonarQube 中的唯一 Key
sonar.projectKey=my:project

# 定义在 SonarQube 中展示时使用的信息
sonar.projectName=My project
sonar.projectVersion=1.0

# 指定源码存放的相对路径,相对于本配置文件,默认为 .
sonar.sources=.

# 默认的系统编码
sonar.sourceEncoding=UTF-8

然后执行命令 sonar-scanner 即可开始扫描。

扫描源码

官方提供了一堆的包含语法错误的示例源码,下载地址:
https://github.com/SonarSource/sonar-scanning-examples/archive/master.zip

  1. 下载后解压 unzip sonar-scanning-examples-master.zip
  2. 进入任意一个源码目录 cd sonar-scanning-examples-master/sonarqube-scanner/
  3. 可以看到已经给了示例配置文件 sonar-project.properties,直接执行 sonar-scanner 即可扫描。
  4. 扫描完成后回到 sonarqube 的 web 中,就可以看到项目中有了新的扫描结果。

将 jenkins 关联到 SonarQube

  1. 首先安装插件,在 jenkins 插件安装界面安装 Sonar 插件 SonarQube Scanner
  2. 系统管理 -> 系统设置 中,找到 SonarQube servers 配置段,点击 Add SonarQube,并填写名字和 URL 路径,保存即可。
  3. 添加扫描器:
    • 系统管理 -> 全局工具配置 中,找到 SonarQube Scanner 配置段,点击 新增 SonarQube Scanner,可以选择一个版本号让 Jenkins 自动安装,也可以使用本地已经装好的 sonar-scanner, 指定好目录即可。

在 Job 中添加代码扫描器

在一个 Job 中,添加一种 Execute SonarQube Scanner 类型的构建,然后只填写 Analysis properties 里的信息即可,格式和 sonar-scanner 扫描代码时源码目录中的配置文件 sonar-project.properties 一样。

要注意代码扫描在 Job 中的所处顺序,一般情况下,应该处于拉取代码后,编译部署前。

语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
# 定义在 SonarQube 中的唯一 Key
sonar.projectKey=my:project

# 定义在 SonarQube 中展示时使用的信息
sonar.projectName=My project
sonar.projectVersion=1.0

# 指定源码存放的相对路径,相对于本配置文件,默认为 .
sonar.sources=.

# 默认的系统编码
sonar.sourceEncoding=UTF-8

然后就可以进行构建了,之后可以在构建历史中,点击当前任务旁边的 SonarQube 的 Logo 图标,即可跳转到 SonarQube 去查看代码扫描的结果了。