前两篇讲到了服务如何适配容器化我们在服务里做的一系列改造,服务可以很优雅的适配容器化环境了,但是有一个前提是服务得容器化,也就是说如何打包成镜像。自己手动构建推送镜像可不可以?当然可以,不过老话说得好,一个月几百块,你玩儿什命啊。你天天手动,手不累么?肩膀不酸吗?身体受得了吗?别再自己用手了,通过Gitlab CI来解放你的手,用你的手去做些更快乐的事情。
首先聊聊我们面对的问题
针对上述几个问题,我们构建出了一个场景
开发同学开发完成后先在开发环境里测试完成后自动部署至测试环境,测试同学进行多轮测试后标记可发布的服务版本,同时可能存在同一个服务根据不同的需求在多分支上的开发和测试问题。而生产环境部署时只能选择测试确认的服务版本进行发布上线,并且对于服务的资源配置要提供参考。线上运行过程中遇见的问题能追溯到发布版本和代码版本。
结合问题、场景、容器化技术我们得出了以下的结论:
- 基于k8s namespace策略做环境隔离、团队隔离,通过资源限制策略、调度策略进行控制不同环境的资源用量,减少资源成本、维护成本
- 多个开发环境和测试环境在提交代码后均可完成自动构建和部署
- 将代码分支和部署环境进行匹配,同时支持根据不同环境注入不同的环境变量值(前一篇文章分享过)
- 通过监控数据向正式环境提供服务运行CPU和内存的参考值,可以考虑直接用k8s VPA的策略(生产环境暂时不推荐使用),也可以考虑参考VPA的算法再结合监控数据进行计算,不过这个带来的问题是需要人工调整服务的Request/Limit值
- 线上部署的应用服务记录版本号用于问题追溯到代码
- 在不引入其他平台的前提下完成整个流程,我们就把目光聚焦在了gitlab提供的ci能力上了
为什么我们选择用gitlab ci?网上一搜索就有很多在讲优势劣势,这里说说我们看中的几个原因:
1.轻量:内置在Gitlab平台中,和代码管理天然融合一体,而且上线的服务只用记录commit号在后续回溯代码时很方便
2.易于配置:配置使用YAML文件进行定义,具有直观的语法。这使得构建、测试和部署流程可以以代码的方式进行管理,易于维护和版本控制
3.扩展性强:如果标准任务不足以满足特定需求,可以无需侵入gitlab本身的代码,就能定制构建和部署流程
总结下来,gitlab提供的ci从我们的角度看,够轻量,够简单,扩展性强。尤其是扩展性强这一点,这点让我们脸都笑开花了,可以低成本实现我们的想法,满足我们的想象力。
先看看整体流程
图片
整套流程涵盖了开发阶段、线上运行阶段,首先开发阶段下,运维同学只需要在开发测试的k8s集群中为不同团队创建ns并做资源限制,后续的部署更新都是基于研发同学的代码提交触发,研发人员可在提交代码后通过gitlab pipeline查看ci构建、部署结果。开发环境中健康检查通过,研发测试没有问题后将该迭代版本的代码合并到对应的测试分支部署至测试ns交由测试人员进行测试,整体测试完成后标记服务镜像正式版本号。而后在平台上进行发布操作。后续运行过程中遇见的问题通过服务镜像号可以追溯到对应代码,修复后重复上述过程
详细说说流程中的几个核心点
1.代码分支和环境对应
首先定义namespace名称困难不困难?困难,而且不只是这个名字困难,涉及到命名的时候都困难,方法名、变量名,尤其是变量名,当然如果说都是用i,j 这些来作为变量名也算的话那就不困难,但是别人看到了。。怕是要被刀。。
所以namespace是基于gitlab组和分支规范较为方便,分支规范每家不一样没有对错之分,把握的原则只是分支与环境对应就好。举一个例子,分支命名dev作为开发分支前缀,test作为测试分支前缀,master作为主分支,gitlab上有两个组 team1,team2(team2和team1一样的逻辑图中就不多画了)
图片
这样做了之后,可以通过在ci中解析分支命名就可以在对应的namespace下创建有分支后缀的服务名了
2.如何限制环境下的资源
通过k8s提供的resourcequotas限制每个namespace的资源上限,通过监控集群资源池和namespace的资源用量,来调整集群的整体资源池,如果使用的公有云还可以通过k8s提供的CA(Cluster Autoscaler)进行伸缩
3.线上问题如何追溯到代码版本
在CI构建打包的时候,在gitlab runner中可以通过获取环境变量的方式来获取本次提交的commit值并自动添加到镜像版本号中,这样在后续通过镜像版本号便能追溯到对应的代码版本。
4.为何只提ns,不提集群
这是因为ns是一个逻辑概念,是为了考虑k8s集群出现灾难性故障时,可以方便我们快速在一个新的k8s集群中迅速重建所有服务。同时也让一次CI部署多套集群成为可能。
5.如何实现自行实现上述流程
从图中可知总共分成了4个大块,可以根据自己的需求去实现。