CI/CD及Jenkins入门

前言

在说持续集成之前,回想一下现有的开发模式:

  1. 项目先划分好若干模块,然后分配模块给相应的开发人员;
  2. 开发人员开发好一个模块后进行单元测试;
  3. 所有的模块都开发完成之后,进行代码集成;
  4. 集成后的项目部署到测试服务器上,交由测试人员进行测试;
  5. 测试人员发现 Bug 就把问题记录到 Bug 列表中;
  6. 项目经理分配 Bug 给相应的责任人进行修改;
  7. 修改完成后,再次对项目进行集成,并部署到测试服务器上;
  8. 测试人员在下一次的集成测试中如果没有后续 Bug 则进行回归测试;

在整个的测试过程中,一直重复着 “提交Bug -> 分配 Bug -> 修改 Bug -> 集成代码 -> 部署到测试服务器上 -> 集成测试” 这样的过程。如下图所示:

CI/CD及Jenkins入门_第1张图片
这样的模式存在的问题:

  1. 主分支代码合并变得更复杂。随着项目的开发,代码量也随着提升,往往到了后期进行代码合并时,更容易发生冲突。
  2. 无效的等待变多。开发在等待集成其他人的模块,测试人员在等待开发修复Bug,产品经理在等待新版本上线给客户做演示,项目经理在等待其他人提交代码。
  3. 项目周期时间变长,容易延期交付。早期就存在的 Bug 往往会在最后集成甚至部署的时候才被发现,然而随着时间的推移,Bug 修复的成本也越高,代码可能改动的地方也越大,不仅问题变得难以修复,甚至因为时间太久而不得不从头阅读代码、理解代码。

使用持续集成可以解决这些痛点,然而持续集成带来的好处远不止于此。

一、CICD 概念

持续集成( CI )

什么是集成?集成是指软件个人研发的部分向软件整体部分交付的过程,代码的集成通常要通过编译、测试、打包。

持续集成指的是,频繁的(一天多次)进行集成。并自动完成编译、单元测试和打包构建。和前言中提到的开发流程相比, 持续集成它的好处主要有两点:

  1. 快速发现错误。每完成一个功能就进行集成,可以快速发现错误,定位错误也比较容易。
  2. 防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。
  3. 减少重复过程。

continuous integration (CI) is the practice of merging all developer working copies to a shared mainline several times a day.

持续集成的目的,就是让产品可以快速迭代。与持续集成相关的,还有两个概念,分别是持续交付和持续部署。

持续交付

持续交付指的是,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。注意,持续交付在自动化测试和集成结束后,不一定会自动部署。如果有自动部署,则是持续部署的概念了。

持续部署( CD )

持续部署(continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。持续部署扩展了持续交付。下图是持续部署的全流程图。持续集成只是持续部署的一部分,它只涉及前三个步骤。持续交付和持续部署的区别在于,全面测试到部署的过程是否自动化。

CI/CD及Jenkins入门_第2张图片

二、敏捷开发、CI/CD、DevOps

敏捷开发和 DevOps 都是一种理念,都是为了产品的快速迭代,而 CI/CD 是实现这两者理念的一种方法。

敏捷开发是关于软件开发的过程与模式,它的宗旨在于拥抱变化。下面图的标题是"How Spotify builds a product"很好的诠释了敏捷开发的含义。
CI/CD及Jenkins入门_第3张图片
DevOps 更多的是关于软件部署和运维管理。 DevOps 不会取代敏捷,相反,它非常好地补充了敏捷开发。它通过简化部署等方式来实现这一目标,从而实现更持续的生产部署以及更快的进行产品迭代。

DevOps 希望做到的是软件产品交付过程中IT工具链的打通,使得各个团队减少时间损耗,更加高效地协同工作。在传统方式中,开发人员将开发集成后的项目交给测试人员测试,测试通过之后交给运维人员进行部署,同时还要写繁琐的部署文档。每次部署,都需要开发人员与运维人员一同进行,深夜改 BUG,在线看日志。整个项目的周期以线性方式进行,在持续集成中,项目的开发测试与部署是反复进行的,这依赖于自动化构建和自动化部署。持续集成、持续部署是 DevOps 的技术核心,在没有自动化测试、持续集成、持续部署之下,DevOps 就是空中楼阁。
CI/CD及Jenkins入门_第4张图片
DevOps 的好处:

  • 依托自动化工具把开发、测试、发布、部署的过程整合,实现高度自动化与高效交付。
  • 在保证产品质量的前提下快速、频繁地发布产品。

CI/CD及Jenkins入门_第5张图片

三、开始使用 Jenkins

Jenkins是一个开源的、用于持续集成(CI)、持续部署(CD)的平台。需要注意的是,Jenkins 本身只是一个平台,具体实现 CI/CD 功能的则是 Jenkinis 提供的插件。
CI/CD及Jenkins入门_第6张图片在下载安装 Jenkins 之前,需要确保基本环境:

  • 256 MB 内存,建议大于 512 MB
  • 10 GB 的硬盘空间(用于 Jenkins 和 Docker 镜像)
  • Java 8 ( JRE 或者 JDK 都可以)
  • Docker

下载并运行 Jenkins

  1. 下载 Jenkins,点击下载可以看到下载的 jenkins 其实是个 war 包。 当然,一般情况下官方链接下载的很慢,可以用 清华开源镜像站,这里以 jenkins-2.232为例。

  2. 打开终端进入到下载目录,启动该 war 包。

    [aspire@localhost jenkins]$ ll
    总用量 64728
    -rw-r--r--. 1 aspire aspire 66278639 4月  20 17:23 jenkins.war
    [aspire@localhost jenkins]$ java -jar jenkins.war --httpPort=8080
    
  3. 打开浏览器进入链接 http://localhost:8080,经过漫长的等待后(大约5分钟),终于能看到配置界面了。需要注意的是,在解锁 Jenkins 一步中,提示的文件路径为 Jenkins 工作路径,切记。
    CI/CD及Jenkins入门_第7张图片
    CI/CD及Jenkins入门_第8张图片

  4. 根据提示,输入初始化密码后,进行插件安装,这里选择安装推荐的插件。
    CI/CD及Jenkins入门_第9张图片

  5. 又经过了漫长的等待,插件终于安装完毕,但是部分插件安装失败,这个也不用担心,之后会再次安装,此刻先下一步。
    CI/CD及Jenkins入门_第10张图片

  6. 因为本人是学习用,直接使用 admin 账户。在下一步的实例配置无需更改,点击保存并完成即可。
    CI/CD及Jenkins入门_第11张图片

  7. 新版本的 Jenkins 已经有很好的中文社区支持,可以替换使用中文社区的镜像源。点击 Jenlins 中文社区,复制更新中心的地址,并点击使用。然后点击“设置中心地址”中粘贴该地址即可。
    CI/CD及Jenkins入门_第12张图片CI/CD及Jenkins入门_第13张图片

  8. 如果您无法进行上一步的配置,那也可以配置清华插件源,点击 “管理 Jenkins -> 插件管理 -> 高级 -> 升级站点”,修改内容为:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
    CI/CD及Jenkins入门_第14张图片进入 Jenkins 工作路径,以本人为例 /home/aspire/.jenkins ,进入 /updates目录,将 default.json 文件备份。替换所有 updates.jenkins-ci.org/downloadmirrors.tuna.tsinghua.edu.cn/jenkins。然后把www.google.com 修改成百度 。这种方式比较繁琐,而且每次 Jenkins 更新都会重新覆盖原有的文件。
    在这里插入图片描述

  9. 修复安装时未能安装的插件,将插件名复制到 search 中,点击安装。重新启动后即可正常。
    CI/CD及Jenkins入门_第15张图片
    CI/CD及Jenkins入门_第16张图片

CI/CD及Jenkins入门_第17张图片

四、Jenkins 配置

接下来对 Jenkins 进行一些必要的配置。在 Jenkins-2.233版本中,全局工具配置选择自动安装的话,在实际使用时并没有效果,因此推荐手动安装 Maven 和 Git 工具,然后进行配置。

配置 JDK
  1. 管理 Jenkins -> 全局工具配置
    CI/CD及Jenkins入门_第18张图片
  2. 点击新增 JDK
    CI/CD及Jenkins入门_第19张图片
  3. 取消勾选自动安装,因为在装 Jenkins 之前已经有了 JDK,只需配置即可
    CI/CD及Jenkins入门_第20张图片
  4. 然后填写别名和JAVA_HOME,最后保存
    CI/CD及Jenkins入门_第21张图片
配置 Maven
  1. 下载 Apache Maven ,并解压。

    [aspire@localhost apps]$ wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
    [aspire@localhost apps]$ tar zxvf apache-maven-3.6.3-bin.tar.gz 
    
  2. 修改环境变量。

    [root@localhost aspire]# vi /etc/profile
    # 文件末尾添加 maven
    export MAVEN_HOME=/apps/apache-maven-3.6.3
    export PATH=$PATH:$MAVEN_HOME/bin
    [root@localhost aspire]# source /etc/profile
    
    [root@localhost aspire]# mvn -v
    Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
    Maven home: /apps/apache-maven-3.6.3
    Java version: 1.8.0_144, vendor: Oracle Corporation, runtime: /apps/jdk1.8.0_144/jre
    Default locale: zh_CN, platform encoding: UTF-8
    OS name: "linux", version: "4.18.0-147.8.1.el8_1.x86_64", arch: "amd64", family: "unix"
    [root@localhost aspire]# 
    
  3. 管理 Jenkins -> 全局工具配置
    CI/CD及Jenkins入门_第22张图片

  4. 取消勾选自动安装,填入 MAVEN_HOME 的值。
    CI/CD及Jenkins入门_第23张图片

  5. 安装 Maven Integration 插件
    CI/CD及Jenkins入门_第24张图片

  6. 在新建项目中,看到构建一个 maven 项目,安装即完成。
    CI/CD及Jenkins入门_第25张图片 CI/CD及Jenkins入门_第26张图片

配置 git
  1. 安装 Git

    [root@localhost apps]# yum install -y git
    [root@localhost apps]# git --version
    git version 2.18.2
    
  2. 配置 Git,其中路径可以通过命令 whereis git 来获取
    CI/CD及Jenkins入门_第27张图片

  3. 本人以 gitlab 作为代码源,在此安装 gitlab 相关插件,用以实现通过 hook 自动构建。如果您不需要,可跳过此步骤。
    CI/CD及Jenkins入门_第28张图片CI/CD及Jenkins入门_第29张图片

五、Jenkins 使用

接下来以一个 springboot 项目介绍 Jenkins 的使用。如下代码所示,项目名为 demo ,这是一个最简单的 springboot 项目,该版本为 springboot-2.1.9。代码源将使用 gitlab 。

@RestController
public class BaseController {
    @RequestMapping("/getString")
    public String getString(){
        return "hello world";
    }
}
  1. 新建一个项目
    CI/CD及Jenkins入门_第30张图片

  2. 输入项目名称,选择 maven 项目,点击确定,下一步。
    CI/CD及Jenkins入门_第31张图片

  3. General 部分。
    CI/CD及Jenkins入门_第32张图片

    • 项目描述,多人合作时填写是一个好习惯。
    • Discard old builds,如何抛弃旧的构建。每次构建相关的文件都会保存下来,将会渐渐耗光磁盘空间,为此提供两种方式供选择:保持构建的天数或保持构建的最大个数。
    • This build requires lockable resources,此构建需要锁定的资源。
    • Throttle builds,设置两个build任务之间最小间隔和同一个时间内最大任务数量。Time period可以根据自己的需求选择,分别有:小时、天、周、月、年。
    • This project is parameterized,可以设置用户可输入的参数,没有输入则使用默认值,有字符串,多行字符串,布尔值等可以设置。
  4. 源码管理,这里以 Git 为例,输入 URL 。添加一个安全认证,这里以用户名和密码的方式。
    CI/CD及Jenkins入门_第33张图片
    CI/CD及Jenkins入门_第34张图片

  5. 构建触发器。此处只配置 gitlab 触发器,你还可以配置定时任务等。如果您的 gitlab 插件安装成功,将看到如下界面。
    CI/CD及Jenkins入门_第35张图片
    需要注意的是,默认情况下,会允许所有分支触发。
    CI/CD及Jenkins入门_第36张图片

  6. 在 gitlab 端配置 webhook。在 gitlab 项目中,点击设置。
    CI/CD及Jenkins入门_第37张图片
    在上一步的 Jenkins 配置中,有一个 url ,将那个 url 复制到此处。在这里还可以进行其他配置,例如 token,token 在上一步的 jenkins 高级配置中可以生成。Trigger 可以配置多种触发器,Push events 就是发生 push 事件,还可以根据不同的 profile 进行触发,例如我们通常有 dev 和 test 分支等。 Merge request events 往该分支上进行 merge 操作时触发。
    CI/CD及Jenkins入门_第38张图片

  7. 构建钱操作,这里不作特殊配置。项目的构建配置,您可以根据实际需要进行配置,例如,跳过 test:设置为 package -Dmaven.test.skip=true。构建后的步骤通常选择"Run only if build succeeds"。最后点击保存。
    CI/CD及Jenkins入门_第39张图片

  8. 手动触发构建,点击"立即构建"。
    CI/CD及Jenkins入门_第40张图片CI/CD及Jenkins入门_第41张图片
    具体的构建信息,可以从控制台输出中看到。
    CI/CD及Jenkins入门_第42张图片

  9. 可能发生的问题,在第一次构建时失败,控制台输出内容如下。
    CI/CD及Jenkins入门_第43张图片可以看到,能正常读到 gitlab 中的代码,但是却无法下载 jar 包。请再次检查 JDK 和 maven 配置。本人此次构建失败的原因是因为,maven 安装时采用的用户是 aspire,然而 repository 目录的权限是 root,因此,更改 repository 目录的权限,再次构建即可看到 jar 包开始下载了。
    在这里插入图片描述

    [root@localhost apps]# chown -R aspire:aspire repository/
    

    CI/CD及Jenkins入门_第44张图片 CI/CD及Jenkins入门_第45张图片

  10. 使用 gitlab 测试 push 事件,通过 gitlab 可以模拟一次 push 事件触发 jenkins 自动构建。
    CI/CD及Jenkins入门_第46张图片如果成功则会出现下图,如果出现"hook execution failed: execution expired",说明 git 环境和 jenkins 网络环境有问题。
    在这里插入图片描述

  11. 设置 Jenkins 构建完毕启动项目。

    首先安装 gcc 环境,执行 yum -y install gcc automake autoconf libtool make安装。
    安装 daemonize 工具,git clone git://github.com/bmc/daemonize.git,这个工具的安装需要 gcc 环境

    [aspire@localhost apps]$ cd daemonize
    [aspire@localhost daemonize]$ ./configure 
    [aspire@localhost daemonize]$ make && make install
    

    若能运行 daemonize -v 即可。

    [root@localhost daemonize]# daemonize -v
    daemonize, version 1.7.8
    Usage: daemonize [OPTIONS] path [arg] ...
    
    OPTIONS
    
    -a             Append to, instead of overwriting, output files. Ignored 
                   unless -e and/or -o are specified.
    -c <dir>       Set daemon's working directory to .
    -e     Send daemon's stderr to file <stderr>, instead of /dev/null.
    -E var=value   Pass environment setting to daemon. May appear multiple times.
    -o <stdout>    Send daemon's stdout to file <stdout>, instead of /dev/null.
    -p <pidfile>   Save PID to <pidfile>.
    -u <user>      Run daemon as user <user>. Requires invocation as root.
    -l <lockfile>  Single-instance checking using lockfile <lockfile>.
    -v             Issue verbose messages to stdout while daemonizing.
    

    BUILD_ID=DONTKILLME 防止Jenkins 杀死我们的进程。Jenkins 在构建成功后会使用杀掉所有子进程,而且这是Jenkins的默认行为。

    CI/CD及Jenkins入门_第47张图片
    脚本内容如下:

    project=demo-0.0.1-SNAPSHOT.jar
    cp /home/aspire/.jenkins/workspace/demo/target/$project /apps/develop
    cd /apps/develop
    pid=`ps -ef | grep $project | grep -v grep | awk '{print $2}'`
    if [ -n "$pid" ]
    then
       kill -9 $pid
    fi
    BUILD_ID=dontKillMe nohup java -jar $project >./out.log 2>&1 &
    

    再次进行构建,成功发现项目已自行启动,访问项目,接口返回正常。

    [aspire@localhost develop]$ ps -ef | grep java
    aspire     4220   2780  0 10:43 pts/0    00:02:36 java -jar jenkins.war -port:8080
    aspire    26743   2105  3 15:28 pts/0    00:00:06 java -jar demo-0.0.1-SNAPSHOT.jar
    aspire    26811  25967  0 15:32 pts/2    00:00:00 grep --color=auto java
    

    CI/CD及Jenkins入门_第48张图片

至此为止,持续集成的部分已经结束,可以想象,当开发合并代码到一个分支上,就能自动的进行编译、打包、部署和启动项目,这大大节约了时间,减少了重复操作。


参考资料

[1] 持续集成是什么?- 阮一峰的网络日志
[2] 敏捷开发、持续集成/交付(CI/CD)、DevOps学习笔记
[3] Jenkins 官方文档

你可能感兴趣的:(Jenkins,java,jenkens,ci/cd)