技术分享 | 玩转Devops之Gitlab-CI

2022-07-08

分享到

作者:吴江鹏


前言


如何在日益繁杂的软件开发过程中,提高软件开发效率,增强开发和运维人员的合作,且看Devops实现之Gitlab-CI带来的改变。



Devops简介

Devops基于Development和Operations组合而来,通过自动化的“软件交付”和“架构变更”流程,使得构建、测试、发布软件流程更加迅速、便捷、稳定,能够按时按质交付产品从而提供更好的用户体验。


Devops实现有很多,其中既有Jenkins这样大而全的平台,也有Gitlab-CI这样小而精的工具。本文将通过GitlabGitLabCommunity Edition 11.8.1Gitlab-CI(基于Gitlab-Runner14.6.0来剖析Devops的实现、难点及其优缺点。


由于目前主流开源版本的Gitlab内置Runner版本老旧,安装不便,本文推荐使用Kubernetes单独安装配置Gitlab-Runner(参考文献:https://docs.gitlab.com/runner/install/)进行Devops使用。


Gitlab-CI实现Devops架构剖析



从Gitlab-CI实现Devops的架构图不难看出,整个Devops流程分为三大步骤:


(1)软件开发流程:通常本步骤为软件开发人员主要参与代码编写;


(2)持续集成(CI):代码上传、编译代码、打包镜像、推送镜像至harbor仓库;


(3)持续部署(CD):拉取harbor镜像、部署服务至k8s集群(测试、生产),通常本步骤为运维人员主要参与。


Gitlab-CI的Devops链路剖析

本部分将介绍最经典的Devops实现模式,将托管在Gitlab上的代码分为三个分支:dev、test、master。三个分支分别由开发、测试、运维三个角色维护。


1、开发人员需要将开发的代码合并到dev分支即开发版本分支后,自动触发编译代码、打包镜像、推送镜像至harbor仓库等构建流程;


2、当开发人员代码正确的完成编译构建等一系列流程后,测试人员负责将开发人员提交的代码合并至test分支,触发构建流程,并自动部署软件服务至目标k8s集群,然后进行代码测试工作;


3、当测试人员测试无误后,通知运维人员将代码合并至master分支,构建软件的release等版本信息,并于构建完成后进行版本发布操作。


下面将基于.gitlab-ci.yml的伪代码文件进行CI/CD流程的剖析。



持续构建(CI)


持续构建的意义在于使用自动化流程去实现代码集成、版本管理、新版本发布、功能升级等流程。


提供持续构建的工具有很多,其中应用最广的是Jenkins,但因其实现过程较为复杂,不适合初创或规模较小的公司使用。本文推荐使用的工具为Gitlab-CI,其原生支持Gitlab代码托管平台。


通过Gitlab-CI实现Devops,依赖Gitlab-Runner工具。可以把Gitlab-CI理解成调度中心,而Gitlab-Runner为具体实施CI/CD任务的工具。Gitlab-CI与Gitlab-Runner的关系如下图所示,其中Runner可以部署在物理机也可以部署在容器内,推荐部署在容器内,方便管理部署及扩展。



触发Gitlab-CI调度工作,仅需编写一个.gitlab-ci.yml文件,该文件存放于Gitlab项目仓库的根目录,通过一系列的描述语句定义整个Devops链路规则。其中.gitlab-ci.yml中涉及到的各关键字用法可在官网进行学习(参考文献:https://docs.gitlab.com/ee/ci/yaml/index.html)。


在介绍持续构建(CI)前,需要着重介绍缓存cache的相关知识点。


cache


Gitlab-Runner实现Devops时会根据项目需要将整个流程划分成不同的stage(每个stage为一个独立的容器环境),大多数场景下一个stage都需用到上一个stage的产物或者需要缓存项目的依赖(maven、pip、npm),如果不使用cache,前后stage之间的产物将几乎无法传输以及每次构建maven等项目时都需重新缓存依赖jar包导致构建流程明显变慢。此时可以使用Gitlab-Runner提供的cache功能缓存产物及加速构建流程。cache实现有两种,一种是缓存到本地,一种是缓存到分布式缓存系统minio。


由于本文采用的Gitlab-CI实现为部署到k8s集群上,采用本地缓存无法在stage之间正常传递,故采用minio形式缓存cache。使用minio形式缓存cache需注意要使用cache_key,因为不使用cache_key的话,不同的stage缓存都会存在默认目录下,从而覆盖原有缓存。



下面将介绍Devops链路中持续构建(CI)相关步骤。


lint:代码提交信息规范


随着软件开发涉及到的部门及人员越来越多,如果不对代码提交信息进行规范化,将导致部门割据,Devops推行困难,所以在一开始就要定义好代码提交信息的规范(参考文献:
https://commitlint.js.org)。



release:版本发布


随着敏捷开发的盛行,版本发布越来越快,需要每次发布的版本进行统一管理发布,便于部署及回滚(参考文献:https://docs.gitlab.com/ee/ci/examples/semantic-release.html)。



build_maven:maven项目构建


本文构建的项目为maven项目,且因为运用了Nexus私库,所以将maven的配置文件修改后基于开源maven镜像打包了新的工具镜像。基于新构建的工具镜像即可使用Nexus私库及将依赖jar包缓存至cache中。



build_docker:镜像构建


考虑到性能及服务器安全保证,本文构建镜像并没有采用传统的docker in docker(容器中挂载宿主机docker)的方式,而是采用了Google开源的kaniko镜像构建工具,完全在用户空间中执行Dockerfile中的每个命令构建镜像。同时配置了harbor仓库,镜像构建完成后直接上传至harbor仓库。



持续部署(CD)


在持续构建(CI)步骤中,完成了推送代码到Gitlab、代码编译、镜像构建、推送镜像到harbor仓库等步骤。接下来在持续部署步骤中,需要将镜像部署到测试或开发环境中。


持续部署是Devops链路中最重要的一环,这一步会将CI时产生的镜像部署至k8s集群。


deploy_k8s:部署至k8s集群


本文采用直接使用kubectl客户端+k8s集群配置文件+软件服务对应的yaml文件方式进行部署,此方法好处在于仅需将目标k8s集群的配置文件构建进含有kubectl客户端的容器镜像中即可在需要部署服务至k8s集群时直接采用kubectl apply –f xx.yaml的形式部署即可,这一步可以获取环境中的版本信息发布对应版本的软件到相应环境中去。



Gitlab界面上的Devops链路解析


当将包含有.gitlab-ci.yml文件的代码推送到Gitlab仓库后即会触发提前定义好的Devops链路。




通过Pipeline界面可以查看Devops链路的执行顺序及各stage的运行状态,如下图所示即为各stage运行成功。




通过jobs界面可以查看Devops链路的中各stage的运行时间、状态等具体信息,如下图所示。




通过点击对应的job可以查看该job运行时各阶段的具体信息,代码编译报错时也会在此显示日志以供debug,如下图所示。



总结

通过Devops可以使得软件开发过程更加快捷可靠,让开发和运维人员能够更好的沟通和合作。


基于Gitlab-CI实现的Devops优点如下:


1、原生和Gitlab代码托管平台融合,提交代码后,直接在Gitlab对应代码仓库的CI/CD页面即可看到整个Devops链路执行进度及具体执行情况;


2、通过k8s集群配置并启动相应容器服务即可快速将Gitlab-CI与Gitlab仓库绑定。通过定义.gitlab-ci.yml文件即可在提交代码到Gitlab托管平台时自动执行CI/CD等流程。


基于Gitlab-CI实现Devops缺点如下:


1、.gitlab-ci.yml与代码放置在一起,没有隔离开,对于某些特定场景可能会造成不必要的信息泄露;


2、相对于Jenkins这种主流Devops工具,Gitlab-CI需要自行配置jdk、maven、镜像构建等,使用上不太便捷。


需要注意,为了避免用户名、密码等敏感信息暴露在代码配置文件中,需通过Gitlab环境变量注入的方式进行管理。