Z.S.K.'s Records

Gitlab学习(实现多kubernets环境CI/CD)

随着环境的多样性, 频繁的集成、测试占用了大量的时间, 大公司都有专门的团队做效率工程, 而我司这种小公司则就只能自养自足. 好在所有的环境都切换到了kubernetes环境, k8s天然的属性结合gitlab end-to-end的能力,实现CI/CD也能节省大量的时间.

目前存在有3个环境dev, gray, prod,都是基于k8s架构, 使用的开发语言大部分都是golang.

dev用于线下环境测试 --> gray用于灰度环境的联调 --> prod则是生产环境

由于不同环境只是配置文件的不同, CI/CD主要存在以下场景:

  1. Merge request请求,对于这类请求全都需要执行源码编译, 可由maintainer选择是否同时需要后续流程
  2. dev环境发布, 开发同学自测环境
  3. gray环境发布,所有开发同学都能够发布
  4. prod环境发布, 只有部分同学有权限发布
  5. 配置文件的变更,变更权限跟环境走

CI/CD流程

dev --> makesource --> imagespush --> --> CD gray --> [自动化测试] --> CD prod --> [Blackbox Monitor]

由于dev环境其实是开发自己使用的环境,虽然接入了CI/CD,但基于不怎么维护, 因此把dev放在最前面,用于说明开发者自测完成.

目前自动化测试跟功能黑盒测试还在完善.

merge request

由于出于对源码的保护, 对于merge request的请求都需要通过maintainer进行codeview,因此merge request 进行源码编译(代码测试), 编译通过后才能合并到目的分支是,同时gitlab还支持选择当pipeline成功时可自动合并

maintainer也可以选择是否需要配置合并后自动发布流程.

关于gitlab开启自动合并功能, 详见merge_request_pipelines

kubernetes认证

多个kubernetes的认证也是根据环境来做的, 最简单的办法就是通过将各种环境下的kubeconfig文件作为变量,最好做为gitlab的组环境变量,这样所有的repo都能够使用了.

在gitlab-ci.yml中通过不同的环境来选用不同的kubeconfig, 这样就能实现对集群的操作,

比如修改gray环境下的某个应用的配置文件, 主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.exportenvgray: &exportenvgray
- export MODE=gray
- KUBE_CONFIG=${KUBE_CONFIG_GRAY}

.kubeconfig: &kubeconfig
- mkdir $HOME/.kube && cat $KUBE_CONFIG > $HOME/.kube/config #需要在gilab中指定为文件类型的变量

.k8supdateconfig: &k8supdateconfig
- kubectl create configmap ${APP}-${KUBERNETES_NS}-cm --from-file=/tmp/config.yml -n ${KUBERNETES_NS} -o yaml --dry-run | kubectl apply -f -

.updateconfig: &updateconfig
image: kubectl_yaml:v1.15.4
dependencies: []
script:
- *kubeconfig # 获取认证文件
- *k8supdateconfig # 到这里就有权限能够更新configmap了

updateconfig:
<<: *updateconfig
stage: updateconfig1box
before_script:
- *exportenv1gray # 指定环境变量,通过不同的环境获取不同的kubeconfig变量.
rules:
- if: '$CI_COMMIT_MESSAGE =~ /\[gray[ _-]uc\]/i && $CONFIGPATH != ""' # 指定执行条件

多环境发布流程

对于多个环境, 其实除了配置不一样之外,其它的操作都是一样的,因此可借用yaml文件的锚定及gitlab的external功能大于减少gitlab-ci.yml配置文件的行数

因为需要将gitlab-ci.yml做成标准化的流程,对于我来说, 我不需要区分是谁触发的pipeline,只需要知道你想触发哪个pipeline, 至于权限问题,则直接丢给了gitlab做管理

有些开发者可能一天commit 100次, 但是他知道前面的90次都是做代码集成, 并不能编译通过, 所以没必要每次的push都执行pipeline, 所以把什么时候需要才真正执行pipeline的选择丢给了开发者,因为开发者才是真正知道代码进度的问题, 当然他想每次都执行也是没问题的.

因此这里大量使用了commit message关键字来区分environment

根据commit message的内容来选择执行对应的pipeline(以下关键字不区分大小写),比如:

  • 包含有[mb] 时: 会执行源码编译(makebinary),主要用于开发编译集成
  • 包含有[gray-cd] or [gray_cd] or [gray cd]时: 发布到1box环境(测试环境)
  • 包含有 [gray-uc] or [gray_uc] or [gray uc]时: 说明只需要更新配置文件,但代码并未更新,适用于数据库密码修改等操作

  • gray环境回归测试通过后, 将分支合并到主分支,打tag后可使用[prod-cd]发布到生产再进行回归

  • 包含有[skip ci] or [ci skip]时: 不执行任何pipeline, 适用于比如提交文档修改之类的操作

对于只需更新配置文件的前提

  • 由于缺少专门的配置平台, 目前使用的配置文件都使用configmap中, 很多的开发者又喜欢直接在平台(rancher)上修改,这样就没办法保证源代码中的配置会得到及时的更新, 为保证配置文件端到端的修改, 尽量禁止了在rancher上直接修改配置文件
  • 配置文件的存放路径需要位于项目跟目录下的config/config.yml,yaml格式, demo见下.
  • 开发人员在发布gray环境时, 不应该保存有生产上的配置文件, 生产上则可以保存1box环境的配置,CI流程会根据发布的环境来选择对应的配置文件
  • 应用启动时可通过命令行参数指定配置文件的路径, 固定位于目录/etc/${APP}/config.yml下
  • 如果应用不存在配置文件(如nodejs等应用)则可在gitlab-ci.yml文件中把CONFIGPATH变量置为空

配置文件处理

这是一个标准化的流程,由于代码中可能保存有所有环境的配置文件, 为了数据安全, 需要对配置文件进行解析, 即: 根据要发布的环境来选择配置文件段,然后发布成kubernetes configmap的形式,最后挂载到应用中.

这里参考一个开源库config,随便改了些代码就实现功能了,即: 通过指定一个环境变量来获取配置文件段.

###config/config.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
debug:
mode: debug
table: filter
enabled: [mon,osd]
disabled: []
ipv4:
mon:
priority: 100
tcp:
- "-p tcp -m multiport --dport 6789,3300 -m state --state NEW -j ACCEPT"
- "-p tcp -m multiport --dport 6789,3300 -m state --state ESTABLISHED -j ACCEPT"
osd:
priority: 200
1box:
zsk: "我是ZSK"
mode: 1box
table: filter
enabled: [mon,osd]
disabled: []
ipv4:
mon:
priority: 100
tcp:
- "-p tcp -m multiport --dport 6789,3300 -m state --state NEW -j ACCEPT"
- "-p tcp -m multiport --dport 6789,3300 -m state --state ESTABLISHED -j ACCEPT"
prod:
...

经过几天的研究测试,发现gitlab的CI/CD还是很强大的, 除了能够支持很多的语言来写gitlab-ci.yaml外,官方文档也是非常的详细, 我几乎没有再看其它的文档 .

CI/CD是个很有技巧的活, 除了标准化之外,跟其它工种的同学怎么协调接入, 比如自动化测、 分级发布、联动发布、黑盒监控等,都需要投入大量的时间来做.

技术从来都不是重点, 推动起来被人认可才是

参考文章:

转载请注明出处https://izsk.me

Z.S.K. wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?