0
点赞
收藏
分享

微信扫一扫

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题

​xxxxxxxxx

道哥的第 030 篇原创

文章目录

  • ​​一、一个真实的代码泄漏故事​​
  • ​​二、Jenkins 的基本使用​​
  • ​​1. Jenkins 是什么?​​
  • ​​2. 安装 JDK8​​
  • ​​3. 安装 Jenkins​​
  • ​​4. 在浏览器中配置 Jenkins​​
  • ​​5. 在 Jenkins 中配置一个小项目​​
  • ​​6. 手动触发编译一次​​
  • ​​三、git submodule 基本使用​​
  • ​​1. git submodule 是什么?​​
  • ​​2. 利用三个小项目,来测试一下 submodule 的用法​​
  • ​​3. 在一个空目录中来编译、验证一下可行性​​
  • ​​四、在 Jenkins 中使用 git module 来编译所有的模块​​
  • ​​1. 重新配置项目​​
  • ​​五、总结​​
  • ​​1. Jenkins 是如何保持编译历史记录的​​
  • ​​2. 编译后动作​​
  • ​​3. git subtree 功能​​
  • ​​4. 继续研究 Jenkins 中的插件功能​​
  • ​​六、资源下载​​

一、一个真实的代码泄漏故事

事情发生在功能机的时代,我们项目组开发一款手机,软件开发成员大概有 20 人左右吧。结果在手机发布的一周后,另一家小厂就推出了软件界面、功能几乎完全一样的手机,除了开机界面。

因为那个时代,大家几乎都是使用 MTK、高通提供的解决方案,都是统一的菜单式功能,你没法拿出有力的证据来说明别人偷窃了你的代码。

后来内部查明,的确是有开发人员把代码泄漏出去了,于是后来所有的电脑上 USB 口全部被禁掉了。

这是我亲身经历的真实故事,当时每个人负责一个模块,比如:A 负责通话管理和电话簿,B 负责系统设置,C 负责短信和彩信。。。在编译的时候,是需要所有的代码放在一起,统一编译的,这也就意味着所有的软件人员都可以拿到全部源代码,这也就为代码泄漏埋下了隐患,出现了这次严重的事件,毕竟人为财死、鸟为食亡!

那么,是否有一些代码管控方式,来解决这个权限问题呢?

现在项目中,都强调要分层、分模块,这是从软件工程的角度来考虑的。如果再进一步, 把这些模块都划分为一个小的子系统,每个开发人员只负责自己的模块,并且只能有权限拉取自己的代码,这样他就没法获取到一个项目中所有模块的代码了。

只有项目整合人员(管理员),才有全部权限来拉取所有源代码来构建整个系统,这样的话,就可以对代码的安全问题有更好的掌控了。

要实现这样的代码管控,使用 git 工具中的 submodule 就可以完成,这篇文章,我们就来详细的讲解一下 git submodule 的使用。

这篇文章是工具型的,可能比较长,为了提供一站式服务,我会把相关的资源、步骤、遇到的错误信息等细节都记录下来,方便以后查阅。

不论如何,经过这篇文章,你可以学习、了解下面这几个方面的知识点:

  1. Jenkins 的基本使用方法;
  2. git submodule 的基本指令用法;
  3. 通过三个 demo 项目,一步一步操作实现代码的安全管控;
  4. 利用 Jenkins + git submodule 来实现自动化编译;
  5. git subtree 与 submodule 的区别;

如果您需要文中提到的软件和代码资源,在文章末尾可以找到下载方式。

二、Jenkins 的基本使用

1. Jenkins 是什么?

Jenkins是一个开源、由 Java 编写的持续集成工具,也就是说它帮助我们自动构建各类项目。Jenkins 运行在 Servlet 容器中(例如 Apache Tomcat),在 Ubuntu 系统中使用 apt-get 就可以一键安装。

Jenkins 有下面几个特点:

  1. 嵌入在 Web 服务器中,通过浏览器来操作,非常方便;
  2. 可以执行基于Apache Ant和Apache Maven的项目,以及任意的Shell脚本和Windows批处理命令;
  3. 可以通过各种手段触发构建。例如提交给版本控制系统时被触发,通过类似Cron的机制调度,在其他的构建已经完成时,还可以通过一个特定的URL进行请求;
  4. Jenkins强大的插件式,使得Jenkins可以集成很多软件,可能帮助我们持续集成我们的工程项目;
  5. 给用户很大的权限和灵活性来自动发布、部署等等。

其他的有点我就不吹了,我觉得很好用,如果有机会,你也可以试一下。另外,我测试用的虚拟机是新安装的 Ubuntu16.04-64,按照下面的流程操作,保证可以顺利运行。

JDK 和 Jenkins 的安装方法,在网络上很多资料,有些过程是有问题的,或者某些关键步骤没写清楚。为了便于你一次就操作成功,我还是记录在这里。

如果你对安装过程已经很熟悉了,可以直接滑到下一个主题。

2. 安装 JDK8

(1) 下载,解压

下载 jdk-8u221-linux-x64.tar.gz,(文末提供下载地址),解压到目录 /home/sewain/OpenSource ,解压指令:

sudo tar -zxvf jdk-8u221-linux-x64.tar.gz -C /opt

(2) 设置环境变量

执行指令:​​vim ~/.bashrc​​,在末尾添加如下内容:

export JAVA_HOME=/opt/jdk1.8.0_221
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=./$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jart

我建议你也用这样的环境变量,以后如果升级 JDK 版本,只需要修改 ​​JAVA_HOME​​ 就可以了。

(3) )重新加载环境变量

执行指令:​​source ~/.bashrc​​,此时环境变量就生效了。

验证一下:​​java -version​​,出现如下信息就说明 OK 了:

java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)

3. 安装 Jenkins

(1) 导入 Jenkins 存储库的 GPG 密钥

sudo wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -

上面的命令应输出 ​​OK​​,这意味着密钥已导入成功,并且来自此存储库的软件包将被视为受信任。

(2) Jenkins存储库添加到系统中

sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'

(3) 使用 apt 安装

sudo apt update
sudo apt install jenkins

Jenkins 服务将在安装过程完成后自动启动,可以通过指令 ​​systemctl status jenkins​​ 进行验证。

​systemctl status jenkins​

(4) 配置端口

Jenkins 是嵌入在一个 tomcat 服务器中的,默认使用端口 8080,容易与其他服务冲突,因此需要修改一下。涉及到 2 个文件:

文件一:/etc/init.d/jenkins

第一行的 PATH 变量中,添加自己的 JDK 地址:

PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/jdk1.8.0_221/bin

文件二:/etc/default/jenkins

把 HTTP_PORT 的值修改为新的端口号,例如: HTTP_PORT=9090 。

(5) Jenkins 的启动和停止指令

sudo service jenkins start
sudo service jenkins stop

如果不幸遇到错误,可以反复使用这两个指令来排除错误。

4. 在浏览器中配置 Jenkins

在浏览器中输入: htpp://localhost:9090,稍等一会,出现界面:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins

按照界面提示,从 ​​/var/lib/jenkins/secrets/initialAdminPassword​​ 文件中复制安全密码(需要 root 权限),填入到浏览器窗口中。

此时出现安装插件窗口,一般只需要安装推荐的插件即可:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_git_02

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_03

插件安装结束后,进入管理员配置界面:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_04

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_版本管理_05

至此,Jenkins 的安装就顺利完成了!

5. 在 Jenkins 中配置一个小项目

(1) 准备一个测试代码 Test1

Jenkins 仅仅是一个构件框架,具体的编译过程是由用户来决定的。 Jenkins 首先通过 git 工具获取远程仓库中的代码,然后执行用户指定的编译指令。

因此,我们需要先提前准备好一份测试代码,并放到 Jenkins 可以访问到的远程仓库中,当然了,你在本地的 Ubuntu 系统中部署一个 git 仓库也是可以的。为了方便,我测试的代码 Test1 放在 gitee 中了。

(2) 创建一个新项目

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_06

(3) 输入项目名称,并选择第一个自由风格(Free project)

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_07

(4) 在第一个标签 General下,输入项目的描述信息(Description)

内容可以随便写。

(5) Source Code Management 源码管理

Jenkins 在构建(编译)的过程中,需要获取到源代码,因此需要配置 git 仓库的地址和账号信息(用户名和密码)。

首先在 Add 下拉按钮下,选择 Jenkins:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_08

输入 Username 和 Password :

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_代码安全_09

账号添加之后,在 Credentials 的下拉框中,选择刚才添加的 gitee 账户,此时可以看到 红色的权限错误提示消失了,说明可以拉取到远程仓库中的源代码了。

(6) Build Triggers 选择编译触发器

可以根据需要选择不同的方式来触发,比如:定时触发,当其他某个项目构建成功之后触发等等。

我们这里不选择任何项目,下面我们会在主界面,手动点击按钮来触发。

(7) Build Environment 编译环境

这部分我用的比较少,利用其他工具来辅助 Jenkins 的功能。

(8) Build 编译

就是告诉 Jenkins 如何来构建系统,也就是说:Jenkins只是一个自动化的构建系统,具体的编译过程,可以由用户自己来决定,有如下选择项目:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_10

我们这里选择直接执行脚本(Execute Shell),输入如下指令:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_代码管控_11

(9) Post-build Actions 编译后操作

告诉 Jenkins: 编译一个工程之后,需要做哪些事情?例如:发送邮件,触发下一个工程的自动编译等等,而且可以添加多个动作。可选项如下:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_版本管理_12

以上步骤配置好之后,Save 保存,此时在主界面就可以看到这个项目的全貌了,如下图:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_代码管控_13

在 Jenkins 后台中,这个项目的保存路径是:/var/lib/jenkins/jobs/Test1。

6. 手动触发编译一次

由于在上面的步骤(6)中,我们没有选择任何触发条件,所以需要我们在项目 Test1 的主界面中,手动单击左侧的 Build Now 按钮来触发。

此时,在左侧的 Build History 中,可以看到编译历史记录,单击某次编译记录编号,可以看到这一次编译的详细信息。

在编译详细信息中,单击左侧的 Console Output 按钮,可以看到编译的输出信息:成功编译得到可执行文件。

我们可以在 Jenkins 后台中看到,源代码被拉到 /var/lib/jenkins/jobs/Test1/workspace 目录中了:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_版本管理_14

到这里,你已经学会了 Jenkins 的最基本操作!

下面我们继续讲一下 git submodule 的使用,这部分才是核心内容!

三、git submodule 基本使用

1. git submodule 是什么?

git submodule 是用于多模块管理的工具,它允许一个项目作为 repository,其他项目作为子模块存在于在父项目中。

父项目和子项目的提交是分开的,也就是说父项目提交的信息只包含子项目的信息,而不会包含子项目的代码;子项目有自己独立的

git submodule 一般用在比较大的项目中,为了便于复用,或者为了代码的安全性,常常需要分成若干个子项目来进行代码管理。

常用的指令包括:

添加子模块: git submodule add
更新子模块: git submodule update
初始化子模块: git submodule init
递归的方式克隆整个项目: git clone --recursive
拉取所有子模块: git submodule foreach git pull

2. 利用三个小项目,来测试一下 submodule 的用法

为了便于演示,我们我们创建 3 个项目,把它们都推送到远程仓库中,这里使用 gitee。

  1. Test1:编译得到一个动态库:libtest1.so;
  2. Test2:编译得到一个动态度:libtest2.so;
  3. Test3:编译得到一个可执行程序,加载、调用上面 2 个动态库中的函数。

为什么要这样设计模块: 安全!

  1. 开发人员A:负责 Test1,没有权限拿到其他模块的代码;
  2. 开发人员B:负责 Test2,没有权限拿到其他模块的代码;
  3. 项目经理:负责 Test3 和 代码整合,能拿到所有的代码;

项目经理需要把 Test1 和 Test2 作为 sub module,添加到 Test3 中,执行下面的指令:

git submodule add https://gitee.com/[你的账号]/test1.git test1
git submodule add https://gitee.com/[你的账号]/test2.git test2

把 Test1 和 Test2 作为子模块添加到 Test3 中之后,看一下文件有什么变化:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_git_15

你还可以看一下 .gitmodules 文件中的内容,可以看出,git 工具就是通过这个配置文件来管理子模块的。

管理员需要对所有的模块进行整合、编译,因此,我们在 Test3 目录下添加一个脚本 build.sh,所有的编译指令,都写在这个脚本中,内容如下:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_16

内容都是最最基本的,直接调用 make 指令即可,执行一下,输出:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_版本管理_17

到这里,我们就完成了子模块的添加功能。

3. 在一个空目录中来编译、验证一下可行性

我们在另一个空目录中,clone 一下 Test3 这个项目,可以发现:克隆下来的 test1 和 test2 文件夹中是空的,如下所示:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_18

需要手动获取所有的子模块,执行指令:

git submodule update --init --recursive

此时,再使用 tree 命令看一下文件变化,可以看到 test1 和 test2 的文件都被拉取下来了。这里有一个问题需要注意:虽然子模块的代码被拉取下来了,但是其 head 并没有指向 master 分支,需要手动处理一下,如图:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_代码安全_19

这个时候,我们在 test3 目录下再次执行脚本 build.sh,就可以顺利编译所有的子模块了。

以上这几个步骤,我们是在本地的一个临时目录,手动测试 submodule 的编译过程。

下一个章节我们把这个过程部署到 Jenkins 系统中,所以刚才执行的这几个指令,就需要写在 build.sh 脚本中了。build.sh 的内容变为:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_版本管理_20

四、在 Jenkins 中使用 git module 来编译所有的模块

下面的操作,都是在浏览器的 Jenkins 面板中来操作的。

1. 重新配置项目

因为我们是在 Test3 中,来编译整个项目(Test1 和 Test2 被作为子模块包括进来),因此首先把之前添加的 Test1 项目删除掉,如图:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_21

然后重新添加项目 Test3,复习一下步骤:

  1. 输入描述信息,选择自由风格项目;
  2. 输入 git 仓库地址和账户信息,选择 master 分支;
  3. 触发器不设置;
  4. 编译环境不设置;
  5. 编译:选择 Execute shell 执行脚本,输入编译指令:./build.sh。(刚才说了,Jenkins 这是一个自动化构建框架,具体的编译过程由用户决定,所以我们这里的编译过程就是执行 Test3 下的 build.sh 这个脚本。);
  6. 编译后动作不设置;

当然,也可以直接在之前的 Test1 项目基础上进行修改。

此时,我们在 Jenkins 中直接点击 Build Now 按钮,如果不出意外的话,会提示编译错误(左侧的 Build History 下面出现红色的错误圆圈)。

点进去,看一下输出信息(Console Output 按钮),提示错误:

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_jenkins_22

原因正如前文所说,子模块在获取之后,head 没有指向 master 分支,需要我们在第一次编译时手动修改一下(我没有找到其它方法,如果你知道的话,请不吝赐教!)

手动解决:在命令行窗口中,进入 Jenkins 系统的 Test3 目录 /var/lib/jenkins/jobs/Test3/workspace ,执行如下几条指令:

git submodule update --init --recursive
cd test1/
git checkout master
cd -
cd test2/
git checkout master
cd -

此时,重新触发编译一次,一定可以成功的!

五、总结

这篇文章是属于工具型的,一旦部署好之后,每次编译只需要在浏览器中点一下按钮就行,再也不用 ssh 登录到远程电脑中去手动操作了。

如果你还想继续深入一下的话,下面几件事情可以研究一下:

1. Jenkins 是如何保持编译历史记录的

在目录 /var/lib/jenkins/jobs/Test3/builds 下面,可以看到很多以数字命名的文件夹,记录了每一次的编译信息。

2. 编译后动作

在我们的编译脚本 build.sh 文件中,仅仅是生成了可执行文件,你还可以继续扩充功能,例如:自动部署。

或者在项目配置的 [Post-build Actions] 中,重新写一个专门用来自动部署的脚本文件。

3. git subtree 功能

它与 git submodule 很类似,但是本质不一样。

  1. subtree直接把子模块代码拷贝到主模块中,使用命令简单;
  2. submodule 使用的是“指针”指向子模块,使用命令相对复杂一些,功能也更强大;

4. 继续研究 Jenkins 中的插件功能

六、资源下载

文中用到的资源,放在了网盘中。如果需要的话,请在公众号留言区发送数字:030,即可收到下载地址。

文章,要转发;越分享,越幸运!

使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题_代码管控_23

如果您的网站想转载这篇文章,只要保留作者、文章来源和上图二维码即可。

如果您的公众号想转载这篇文章,请私信或留言,我给您开长白。

举报

相关推荐

0 条评论