很幸运作为前端可以参与 DevOps 小组,流水线

CI/CD核心:Tekton(为什么选Tekton:云原生、轻量级、扩展性好、有API接口,GitHub社区ok)

第一部分:发布平台

完整的流程:

  1. 创建发布单
  2. 初始化:Tekton 从 GitLab 上拉取代码,从最新 master 分支上切出 release 分支
  3. 持续集成 CI
    1. 代码检查
    2. 单元测试
    3. 报告生成
    4. 打包
    5. 制作镜像
    6. 镜像检测
  4. 测试
  5. 发布产线
  6. 完成

以上的流程可以统一运用于 Java, Python, Node, 静态页面


简单介绍一下界面

界面

界面设计的原则是提供详细的信息,有效的 UI 目的是提升使用者(开发、测试、运维..)的工作效率。发布详情页包含了发版过程需要了解的所有信息,不用再点开很多个页面。

1. 设计 + 开发:

发布单界面
发布单界面(接入代码质量检测)
pods 实时日志

2. 页面信息:

  • 发布单信息(每次上线进行的一次发布)
    • 常规发布:走完整的 CI/CD 流程
    • 镜像发布:本地制作 docker 镜像后直接发布镜像
    • 回滚发布:直接发布之前发布单的镜像
  • 操作记录
  • 实时流量监控(QPS、5xx)
  • 测试报告(测试人员填写,支持添加外链到完整的报告内容)
  • 本次发布涉及的 git commits
  • k8s 各容器的实时状态
  • 各CI/CD和流水线步骤的日志
  • k8s 服务配置

第二部分:前端 CI/CD

CI / CD 的所有步骤都将会用 Tekton 来执行命令,具体执行的内容如下,可以在本地先确保都可以跑通。

1. 静态代码检测

这个就肯定是 ESLint 没跑了。推荐使用 AirbnbStandard 的标准(接入说明),和插件
使用 SonarQube 进行其他规范的检测。

统一的静态代码检测命令:

  • cnpm run lint
  • cnpm run lint-html

1. cnpm run lint

在 Package.json 中添加:

1
2
3
"scripts": {
"lint": "eslint -f json -o reports/eslint.json src/.",
},

lint:在/reports目录下生成eslint.json文件,用于之后sonar检测时读取的结果文件。

2. cnpm run lint-html

package.json 中需要添加:

1
2
3
"scripts": {
"lint-html": "eslint -f html -o reports/index.html src/.",
},

lint-html:在/reports目录下生成index.html文件,eslint报告的UI界面。

3. sonar

这里使用 Sonar 来上传 ESLint 的检测结果。
这一步无需配置,只要保证前面的 reports/eslint.json 文件成功生成就行。
可在本地安装 sonar 进行测试:

1
2
3
4
5
sonar-scanner
-Dsonar.projectKey=project-name
-Dsonar.sources=./src
-Dsonar.host.url=http://sonar.host
-Dsonar.eslint.reportPaths=reports/eslint.json

Artifacts:
reports
├── eslint.json
└── index.html

2. 单元测试

选了 Jest (和 React 同出一门,比较友好,Vue 也能用)。

Jest 提供了覆盖度报告,但是导出的 HTML 报告没有包含成功率之类的信息,所以决定用 Allure 来辅助一下。
选用 Allure 是因为为了配合其他的后端项目,统一单元测试报告。(Java、Python 配合 Allure 比较好用)

但如果前端用的是 Angular 用 Jasmine & Karma 更舒服。需要确保生成的测试报告是一致的(Allure 报告)。

统一的单元测试命令以及生成报告:

  • cnpm run test
  • allure generate --clean

1. cnpm run test

package.json中需要添加:

1
2
3
"scripts": {
"test": "jest --coverage --all -o",
},

在/coverage目录下生成覆盖度报告

2. allure generate –clean

2.1 生成 Allure 的报告,需要安装 jest-allure

  1. cnpm i -D jest-allure
  2. 在 jest.config.js 配置文件中添加:
    1
    2
    3
    4
    5
    module.exports = {
    testEnvironment: 'jsdom',
    moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node'],
    setupFilesAfterEnv: ['jest-allure/dist/setup'],
    }
    配置完后每次运行 cnpm run test 就会在 /allure-results 目录下生成结果,用于之后的步骤。

2.2 生成 Allure 报告的 UI 界面

需要安装 allure(仅为了在本地跑通,也可以跳过,只要确保上一步的/allure-results生成即可)
Mac OS:
brew install allure
或:
直接下载,然后配置 $PATH
在项目根目录下运行:
allure generate –clean
在 /allure-report 目录下生成html文件

Artifacts:
coverage
├── clover.xml
├── coverage-final.json
├── lcov-report
└── lcov.info

allure-results
├── 2ed4135f-5ef3-4009-a9f0-bdc191e94680-testsuite.xml

allure-report
├── index.html
├── styles.css

3. 项目打包

静态检测和单测都没问题就开始打包。

命令:

  • cnpm run build
  • cnpm run upload-static

打包就不多说了,最后生成 build/ 文件夹包含所有静态文件,如果用 CDN 则需要在打包后上传,统一用以上命令。

生成一堆报告后别忘了在.gitignore里添加:

/reports
/coverage
/allure-results
/allure-report
/.scannerwork

Docker + k8s

CD 部分就是把 Docker 镜像部署到 k8s 就大功告成。由于 Node 版本很多,用于打包的基础镜像可以事先在本地准备好后,push 到 Gitlab,然后在 build 那一步用自己准备的基础镜像,就不用怕 CI 实际情况和本地差太多。

纯静态资源的前端项目用 Ngnix 即可,参考 Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
FROM nginx:1.18.0

WORKDIR /usr/share/nginx/html/

COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf

COPY ./build /usr/share/nginx/html/

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;

gzip on;
gzip_buffers 32 4K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_vary on;
gzip_static on; # 已有gz文件则直接用,可以配合 webpack 上传压缩后的gzip文件,代替nginx压缩

root /usr/share/nginx/html;
include /etc/nginx/mime.types;
location / {
try_files $uri $uri/ /index.html;
}
}

制作基础镜像可以参考:前端基础镜像

  • docker build -t #build-tag .
  • docker push
  • kubectl set image -n ...

企业微信通知

发布平台的通知接入企业微信,在测试和上线的时候会通知相关人员,上线成功后也会通知组内全员。

展望

可以看到发布详情页面上,当前有一个栏目是空缺的,也就是「灰度」的部分。
下一阶段,我们将通过 header、访问路径以及流量比例,三种方式来控制灰度发布。各业务可以各取所需地来配置。

第三部分:实际使用

遇到的最困难的就是让大家都接入这个流程。
比较方便的是 Java,因为每个 Java 项目都非常严谨,编译方式也都很统一。
其次是 Python,除了脚本特别多(需要另外解决)。
最难受的就是前端项目,不仅要考虑 node 版本,还要让各种花里胡哨的打包方式都统一,非常困难,要大家的配合。遇到一些需要其他语言 build 的依赖,更头疼,比如令人绝望的 node-sass。