1. 平台选择
目前支持CI/CD的平台有:
- gitlab-ci:git官方的持续集成工具,在Git工程管理页面上,也有专门的CI配置和展示页;
- Travis CI:只支持 Github,并且绑定了Github上的项目,不支持其他代码托管服务;
- TeamCity:由JetBrains创建的基于Java的CI / CD工具;
- Jenkins:开源的、提供友好操作界面的持续集成(CI)工具,主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。可在Tomcat等流行的servlet容器 中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。常用的版本控制工具有SVN、GIT,构建工具有Maven、Ant、Gradle。
虽然Jenkins只是支持持续集成的众多工具之一,Jenkins ≠ 持续集成,但目前只要一提到Jenkins,人们就会联想到持续集成、CI&CD,可见其使用范围之广,用户之多。同时资料也最为丰富、社区最活跃,所以选择Jenkins也没有什么好犹豫的。
2. 技术选型
工具 | 说明 |
---|---|
Jenkins | 基础平台 |
Sonar&Sonarqube | 静态代码扫描 |
Python3+Allure+Pytest+Requests(接口)+Selenium(web)+UiAutomator2(APP) | 自动化测试环境 |
docker | 容器引擎 |
Harbor/dockerhub | 官方的docker镜像注册服务器(可以在本地搭建Harbor代替) |
Kubernetes | 容器编排管理工具,用于部署应用程序 |
Gitlab/Github | 源代码仓库(可以在本地搭建gitlab代替) |
NodeJS | 前端构建环境 |
Java+Maven | 后端构建环境 |
3. 阶段性目标
CI 阶段目标
-
阶段目标一:自动化构建
先解决“人工拉取代码-执行编译-通知团队”这个原本手动执行效率低下的问题,最终效果:研发提交代码–>触发webhook–>Jenkins自动拉取代码–>编译打包–>通过插件实时企微群通知,后续的发布替换还是由手动完成,一定程度上达到了节约时间,降本增效的目的。工具:jenkins、gitlab、gerrit
-
阶段目标二:静态代码扫描
在CI阶段,自动化拉取代码、自动编译只是过程,不是目的,重要的是要能够实现快速检验、快速反馈。这其中很重要的一个手段就是单元测试。但就目前团队现状而言,单元测试不现实。工具:sonar/sonarqube
我们采取的是接入自动化静态代码扫描来替代单元测试,最终效果:研发提交代码–>触发webhook–>Jenkins自动拉取代码–>静态代码扫描–>编译打包,实现最基本的静态代码扫描,代码覆盖率检测,避免出现低级语法规范和一些安全隐患。
-
阶段目标三:自动发布
解决手动替换发包的问题:自动编译打包后,通过shell脚本自动将发布包发布到开发、测试等各个环境。工具:docker、shell、python、harbor
CD 阶段目标
-
阶段目标四:自动化冒烟测试
应当说持续交付这个阶段最考验的就是交付产物交付到各个环境以后的自动化测试能力,需要具备完善的自动化测试手段,以此来保障快速反馈,否则很难体现CD的效果。除了前面提到的单元测试、静态代码扫描,还包括如:组件集成测试、接口测试、UI测试、性能测试、安全测试等等。工具:Allure、Pytest
在阶段目标四中,我们主要实现两个类型的自动化测试:
接口测试:校验各个接口是否连通,接口业务场景是否能够正常串联执行; UI测试:校验系统是否能够正常登录,一些基本的冒烟测试用例是否正常执行;
-
阶段目标五:Pipeline流水线改造
将以上流程全部通过自动化手段实现以后,再利用Pipeline流水线语法进行改造,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂发布流程。工具:jenkins-pipeline
4. 搭建示例
本节搭建的目标是:
- 在本地提交python代码,jenkins自动触发拉取,编译(由于是python代码,所以只是执行供演示)
- 自动触发sonarqube检测代码
- 自动触发docker制作镜像推送到harbor
- 在指定节点运行服务
服务器规划
服务器 | IP | 用途 |
---|---|---|
node-252 | 192.168.71.252 | jenkins agent,sonarqube,docker |
node-253 | 192.168.71.253 | jenkins master,harbor |
node-249 | 192.168.70.249 | jenkins agent,gitlab |
4.1 环境准备(节点机)
1. java版本升级
由于笔者jenkins安装的版本较高(Jenkins 2.401.2),所以要求java版本至少是11或以上的,笔者这里重新装java
注意:这里不光是安装jenkins的服务器需要较高版本的java,节点机也需要较高版本,否则无法连接节点
参考 CHAPTER 1 Jenkins部署与基础配置 1.1.2 红帽系安装
2. 编译安装git
参考 gitlab/gerrit 2.1 环境准备
3. docker安装
参考 CHAPTER 1 Docker入门 1.3.1 yum安装
4. docker-compose安装
参考 CHAPTER 12 Compose(一)12.2.2 二进制包
5. sonarqube安装
参考 CHAPTER 5 Jenkins & SonarQube
账号:admin
密码:yurq
6. harbor安装
6bDg3XQ81Y3NDWJhtIVacMDyqeNzj3oO
7. gitlab私服
参考 CHAPTER 3 Jenkins SVN GItlab 3.2.1 搭建gitlab服务器(使用官方镜像搭建)
4.2 示例一(手动)
步骤简述:
- 在gitlab创建项目
- 编写代码、python插件(用于flask)和Dockerfile上传至gitlab
- jenkins拉取代码及相关文件
- 检查代码
- 打包代码机相关文件到docker镜像,上传到harbor
- 下载并运行镜像
- 测试服务
1. 创建项目
在gitlab创建项目
2. 编码
[root@node-252 mypython]# cat mypython.py
#!/usr/bin/env python
from flask import Flask
app=Flask(__name__)
@app.route('/')
def index():
return 'welcome to my webpage!'
if __name__=="__main__":
app.run(port=8080,host="0.0.0.0",debug=True)
3. Dockerfile
[root@node-252 mypython]# cat Dockerfile
FROM lmurawsk/python2.7:latest
LABEL maintainer="mrhelloworld.com"
WORKDIR /usr/local
RUN mkdir -p /plugins
COPY package/*.whl /plugins/
RUN pip install /plugins/click-3.0-py2.py3-none-any.whl
RUN pip install /plugins/itsdangerous-1.1.0-py2.py3-none-any.whl
RUN pip install /plugins/MarkupSafe-1.1.0-cp27-cp27mu-manylinux1_x86_64.whl
RUN pip install /plugins/Werkzeug-0.16.0-py2.py3-none-any.whl
RUN pip install /plugins/Jinja2-2.11.0-py2.py3-none-any.whl
RUN pip install /plugins/Flask-0.12.5-py2.py3-none-any.whl
COPY ./mypython.py /usr/local/
EXPOSE 8080
CMD python /usr/local/mypython.py
4. 拷贝python插件文件
由于我们要使用python flask的web功能,但是镜像中没有相关插件,所以需要把插件打包到镜像中
[root@node-252 mypython]# cp ../mypython_bak/*.whl .
[root@node-252 mypython]# ll
total 648
-rw-r--r-- 1 root root 11 Jul 10 05:43 blog.txt
-rw-r--r-- 1 root root 57939 Jul 10 20:34 click-3.0-py2.py3-none-any.whl
-rw-r--r-- 1 root root 1104 Jul 10 20:32 Dockerfile
-rw-r--r-- 1 root root 81748 Jul 10 20:34 Flask-0.12.5-py2.py3-none-any.whl
-rw-r--r-- 1 root root 16743 Jul 10 20:34 itsdangerous-1.1.0-py2.py3-none-any.whl
-rw-r--r-- 1 root root 126742 Jul 10 20:34 Jinja2-2.11.0-py2.py3-none-any.whl
-rw-r--r-- 1 root root 24542 Jul 10 20:34 MarkupSafe-1.1.0-cp27-cp27mu-manylinux1_x86_64.whl
-rw-r--r-- 1 root root 208 Jul 10 05:43 mypython.py
-rw-r--r-- 1 root root 6161 Jul 10 05:43 README.md
-rw-r--r-- 1 root root 327277 Jul 10 20:34 Werkzeug-0.16.0-py2.py3-none-any.whl
后续可以制作python2.7+flask相关插件的镜像
5. 上传gitlab
上传代码
[root@node-252 mypython]# cat ~/.gitconfig
[user]
name = yurq
email = yurq@qq.com
[credential]
helper = store
[http]
sslVerify = false
[root@node-252 MyPython]# git commit mypython.py
[detached HEAD 6182db3] flask
1 file changed, 8 insertions(+), 2 deletions(-)
[root@node-252 mypython]# git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 396 bytes | 396.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
To http://192.168.70.249:9980/devs/mypython.git
f3047fb..0249dc8 main -> main
上传dockerfile
[root@node-252 mypython]# git add Dockerfile
[root@node-252 mypython]# git commit Dockerfile
[main 059968e] add dockerfile
1 file changed, 25 insertions(+)
create mode 100644 Dockerfile
[root@node-252 mypython]# git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 657 bytes | 657.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To http://192.168.70.249:9980/devs/mypython.git
0249dc8..059968e main -> main
6. jenkins拉取代码
创建jenkins项目,配置节点和下载相关插件
配置sonar
由于网络原因,docker-build-step插件一直下载不了,所以手动写了构建/推送命令
7. 查看代码检查结果
8. 查看harbor镜像
9. 模拟发布
由于网络原因,有些插件下载不了,所以笔者又创建了一个jenkins项目并在其他节点运行,以模拟生产场景
10. 示例演示
该示例中有很多步骤都是手动运行的,其原因是很多jenkins插件由于网络原因无法下载,在下例中将逐步改进
4.3 示例二(自动)
说明:在该示例中,我们将在示例一的基础上实现更多功能,包括:
- 代码提交后,自动触发jenkins任务
- jenkins任务整合,通过multi job顺序执行
- docker镜像通过插件打tag,上传到harbor及在指定节点执行(而非通过命令行)
- 更新base镜像,把python插件打包进镜像中,不在执行任务期间安装插件
本节中,我们需要安装的jenkins的插件有:
- docker-build-step
- CloudBees Docker Build and Publish
- multi job
- gitlab
1. 创建multi job
- 记录下gitlab钩子的URL
- 编排任务序列,让任务顺序执行
2. 配置gitlab webhook
- 配置webhook,选择事件类型,当有事件发生时才能自动触发jenkins执行任务
注意:如果添加webhook提示
Url is blocked: Requests to the local network are not allowed
的问题,在gitlab->menu->admin area->Setting->network->Outbound requests
勾选:Allow requests to the local network from web hooks and services即可解决
3. 更新base镜像
- 我们把python插件打包进基础镜像中,后续使用新的镜像进行打包
- 在harbor建好仓库python2.7
[root@node-252 mypython]# cat dockerfile2
FROM lmurawsk/python2.7:latest
LABEL maintainer="mrhelloworld.com"
WORKDIR /usr/local
RUN mkdir -p /plugins
COPY package/*.whl /plugins/
RUN pip install /plugins/click-3.0-py2.py3-none-any.whl
RUN pip install /plugins/itsdangerous-1.1.0-py2.py3-none-any.whl
RUN pip install /plugins/MarkupSafe-1.1.0-cp27-cp27mu-manylinux1_x86_64.whl
RUN pip install /plugins/Werkzeug-0.16.0-py2.py3-none-any.whl
RUN pip install /plugins/Jinja2-2.11.0-py2.py3-none-any.whl
RUN pip install /plugins/Flask-0.12.5-py2.py3-none-any.whl
[root@node-252 mypython]# docker build -f dockerfile2 -t yurq/python2.7:latest .
[root@node-252 mypython]# docker tag yurq/python2.7:latest 192.168.71.253:80/python2.7/yurq_python2.7:latest
[root@node-252 mypython]# docker push 192.168.71.253:80/python2.7/yurq_python2.7:latest
4. jenkins任务修改
- 子任务MyPython 修改
插件excute docker command
不太好用,直接用命令行替代
Docker build and publish
可以使用
- 子任务 Mypython2 修改
添加了判断,如果容器已经启动,则停止/删除,启动新的容器
5. 示例演示
- 修改代码
[root@node-252 mypython]# cat mypython.py
#!/usr/bin/env python
from flask import Flask
app=Flask(__name__)
@app.route('/')
def index():
return 'welcome to my webpage! power by python!'
if __name__=="__main__":
app.run(port=8080,host="0.0.0.0",debug=True)
[root@node-252 mypython]# git commit -m "add power by" mypython.py
[main 9f4af70] add power by
1 file changed, 1 insertion(+), 1 deletion(-)
[root@node-252 mypython]# git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 293 bytes | 293.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
To http://192.168.70.249:9980/devs/mypython.git
de86dd3..9f4af70 main -> main
- 可以看到本次由gitlab启动
- 访问网址
5. 小结
- 本次初步搭建的CD简易流程,还缺少测试环节,笔者这边安装allure出现了状况,后续改善之后再进行完善
- devops更多的用在微服务的发布流程中,后续笔者会推出java开发的程序+k8s部署服务的更完整的流程
- 后续可能还会在除jenkins之外的平台进行尝试