背景
关于大禹
大禹是交付场景下的All-in-One生产力平台。基于GTS交付过程中的实际问题,大禹提供了面向2B&2G交付场景的生产力工具,让原厂小二、生态伙伴、客户基于同一平台项目协作。大禹包括项目、协同、研运、质量等板块。
研运质量板块已具备完整的DevOps功能,提供架构设计、开发、测试、部署、运维等能力,赋能项目中的业务应用研发,支撑定开类项目的交付。
遇到的问题
大禹研运板块主要服务对象是阿里云GTS交付项目,大部分项目的代码及二方包托管在大禹或公共云上。还有部分在弹内开发的项目代码托管在弹内GitLab、构建时依赖弹内的maven仓库,这类项目也有通过大禹构建及部署的诉求。大禹部署在阿里云售卖区不能访问弹内网络,并且由于安全原因不能通过打通网络来访问。
除上述网络原因,运维上也有不便,大禹流水线是通过Jenkins来运行,实现了代码构建、质量扫描、镜像构建、部署等能力。Jekins维护、升级时需要重启会影响流水线运行,因此只能提前在平台发公告等到凌晨一点左右做维护。
网络现状
上图中涉及到4个网络区域:
- 右边是阿里云独立云账号(售卖区)VPC:部署大禹应用的K8S集群在此区域;
- 中上是宙斯售卖区VPC:大禹Jenkins部署在此网络的K8S集群,通过CEN与独立云账号VPC打通。
- 中下是公司弹内网络不能被Jenkins访问;
- 左边是公网:大禹流水线除了支持大禹平台搭建的Git仓库、Docker镜像仓库也支持使用外部的代码及镜像仓库,另外也会使用到用户或公网上的Maven、NPM仓库等资源;
方案调研
最初想到的是打通网络使现有Jenkins可以访问弹内代码及二方库仓库,但与安全团队讨论得出的结论是不能。于是想到在弹内生产网络部署一套Jenkins。弹内Jenkins通过公网访问大禹代码、镜像、二方库仓库,大禹构建中心与Jenkins的访问通过AnyTunnel打通。与安全同学对方案时了解到OXS区是阿里云的生产环境,阿里云现有的应用部分已经在从弹内生产网络向OXS区迁移,因此大禹Jenkins也部署到OXS区。
网络区域确定为OXS,在OXS区也有多种资源可选择:ECS或K8S,其中K8S又有独立的K8S集群及ASK(Serverless K8S)。为了减少运维成本、方便扩缩容最终选择了ASK。
技术方案
总体上会部署三套Jenkins集群:Jenkins-1(即在宙斯K8S中已存在的Jenkins)、Jenkins-2、Jenkins-oxs。
Jenkins-2部署到哪个K8S集群是个问题,若单独申请其配置规格需要和Jenkins-1一样。作为Backup一般情况下是空闲并不使用,这样就造成了资源浪费。因此选择部署在Jenkins-1的K8S集群中,通过命名空间隔离,这样就可以共享主机资源。
集群规划
整体架构
技术实现
流水线运行流程
流水线运行流程简化如下图:
- 准备运行参数如应用git地址、git账号信息、镜像地址、镜像仓库账号信息、构建参数等;
- 计算此次流水线在哪个Jenkins集群上运行,根据配置及默认规则来计算;
- 查询出代码仓库及镜像仓库账号;
- 将代码及镜像仓库账号写入到Jenkins中(Jenkins自己有密钥管理模块,使用到的密钥需先写入到密钥管理模块中然后在流水线中通过ID引用);
- 创建Jenkins Job(存在则重用不存在则创建)。
- 启动Jenkins Job运行流水线(git地址、账号ID等作为参数)。
集群路由
Jenkins集群从原来一套变成了多套,第一个要解决的问题就是使用哪个Jenkins集群运行流水线。首先系统会配置一个Jenkins集群作为默认,通常是Jenkins-1。其次用户可以按应用设置流水线运行的集群,未设置的应用使用默认集群。
通常情况下默认集群为Jenkins-1,在需要升级维护时先把Jenkins-2升级到最新版,然后把把Jenkins-2设置成默认,Jenkins-1升级维护完成后再把默认集群改成Jenkins-1,实现了用户无感知维护。
凭证服务
当应用中使用外部代码或镜像仓库时,需要用户填写账号、密码或公私钥,这些数据不能直接存明文,原来单Jenkins集群时直接存到Jenkins的凭证管理模块中,现在有多个Jenkins集群于是把这些数据改为存到数据库,运行流水线时再同步到当前运行流水线的Jenkins集群中。
在系统中新增了凭证服务CredentialService用于存账号数据,考虑到以后可能要存非账号加密数据因此加了一层KeyVaultService,KeyVaultService提供按标识(Code)加密并存储及读取解密后数据的功能,在公有环境可使用阿里云的KMS云产品,考虑到大禹有私有化部署的需求,在私有化部署环境不一定有KMS于是抽象出了KeyVaultCryptoProvider,并提供两个实现KmsKeyVaultCryptoProvider及AesKeyVaultCryptoProvider,在没有KMS云产品的场景下使用Aes提供加密,通过配置来选择使用哪种加密方式。
镜像构建
Jenkins部署在K8S集群中,Jenkins-1是把宿主机中的Docker Enginge服务/etc/run/docker.sock挂载到容器中,在容器中执行Docker命令时直接使用宿主机中的Docker Engine。但在ASK集群中宿主机没有Docker Engine而是使用的Containerd,也找ASK同学咨询了得到的结果是不能安装Docker建议使用BuildKit,BuildKit的方案之前也有调研过,由于流水线中镜像构建使用了Jenkins插件,Jenkins Docker插件不支持BuildKit,要使用BuildKit需自定义镜像构建过程有一些改造工作量。
经调研可以启用特权模式在POD中启动Container来运行Docker Eninge。原来构建的POD就一个Jenkins Slave容器,现以Sidecar的方式添加了Docker Engine容器,此容器以特权模式来运行Docker Engine,并通过将两个容器/var/run都挂载到相同EmptyDir卷的方式来将Docker Engine共享给Jenins Slave容器使用。
安全加固
Jenkins-1、Jenkins-2集群所有应用都可以使用,Jenkins-oxs集群是弹内开发的应用专用,因此为Jenkins集群添加了category字段(值为公共、专属),对于专属集群需要在AllowList表中添加白名单。
Jenkins-oxs部署在OXS区为了减少风险也做了一些安全加固:
- 集群category为专属,因此需要在OXS区上运行流水线的应用需要申请白名单,这需要平台管理员操作;
- 只有应用使用的是阿里弹内Git仓库才能在Jenkins-oxs上运行流水线;
- 在启动在Jenkins-oxs上运行流水线的操作人必须有阿里工号,其它ISV用户不能启动。
总结
此功能上线后支撑了用户弹内应用代码的构建发布;也有部分弹内开发的大禹平台应用通过大禹流水线进行了构建发布,实现了自闭环。另外此功能上线后已经实现多次默认集群的切换及维护,在不影响用户使用流水线的情况下实现了Jenkins及其插件的更新。