TencentHub是一个集Docker镜像、二进制文件、helmcharts于一体的仓库存储服务。那么这一架构技术是如何基于Kubernetes 快速实现workflow引擎的呢?今天将为大家分享《TencentHub技术架构与DevOps落地实践揭秘》,让我们开始吧!
大家好,这次主要是给大家分享TencentHub技术架构和DevOps相关的一些东西,这两点和大家日常开发结合会比较紧密,比较接地气一点。我今天会主要分享三部分,第一,简单聊一下TencentHub这个产品和DevOps的关系,我们如何去思考建设一个TencentHub镜像仓库+DevOps引擎。第二部分讲讲TencentHub总体的一些东西和Docker镜像存储在腾讯云上是如何实现的,最后是我们的workflow引擎:为了支撑DevOps工作流去设计产品以及一些具体设计/实现细节。
我相信很多人对DevOps已经比较熟悉了,这个概念从2009年大火起来到现在已经过去了接近十年的时间。直击DevOps的核心理念,下面这句话是我最赞同的对DevOps的描述:以业务敏捷为中心,去构造适应快速发布软件的工具和文化。我们做DevOps,要去推崇DevOps,肯定不能忘掉我们的目标是快速交付软件产品。在达到这个目标的过程当中,非常重要的落地就是我们需要工具去支撑DevOps,所以接下来分享TencentHub这样一个以DevOps引擎为指导的工具。
TencentHub是什么?TencentHub核心有两部分,第一,它是一个多功能的存储仓库,包含了Docker镜像存储功能以及helmcharts这样的存储,还有一些构建产物的存储等等。第二,TencentHub是一个DevOps引擎,通过我们自己设计的workflow引擎对工作流进行编排,去帮助大家建立自己的DevOps流程,比如说构建、测试、审核、部署等等任务。当然,在前置环节,我们也将去对接腾讯云提供的TGit代码托管服务,最终给开发者提供一套完整的云上Devops工具解决方案。
我简单介绍一下TencentHub的总体架构,TencentHubd 的镜像仓库存储是基于COS实现,因为COS可靠性非常高,这非常方便地给我们的镜像存储带来高可靠保证。TencentHub核心还有一个自研workflow引擎,可以使用YAML定义DevOps流程,让我们的DevOps本身达到Programmable,这对Devops的管理是很重要的。在TencentHub的Devops引擎里面,我们使用容器去实现插件机制,用来封装用户自定义的DevOps任务,后面会详细介绍。使用Kubernetes作为执行引擎,运行DevOps任务,目前是使用TKE来实现的。在Docker存储仓库里,我们也会加入Docker镜像漏洞的安全扫描,后面会做一个的简单介绍。
左边这个图分为两大部分。上面是Registry,下面是StorageEngine。Registry主要包含了组织、团队、成员的管理,以及一些权限的控制,同时还包括仓库Repository的管理,负责Docker镜像、文件、helmchart的存储。我们所有存储都是使用一个仓库来管理,镜像、文件等都会放在某一个仓库下面。在最上面,我们提供了Webhook,可以帮助用户对接自己的系统,监听仓库或者DevOps流程发生的一些事情。在Registry里面还有Component组件,负责DevOps任务的存储。下面这部分StorageEngine,是我们去解决统一的仓库存储层的问题,它是一个我们提供出来给全球的腾讯云的机房都能使用TencentHub服务的机制。
TencentHub仓库中最重要的是Docker镜像的存储。除了公共的镜像存储之外,TencentHub还支持私有的镜像存储。私有镜像存储需要通过登录才能获取或者上传Docker镜像。如何是想登录认证呢?这是Docker官方的Registry用户认证的规范,它并没有纳入到OCI规范里面,只是在官方有一个文档去说明流程是什么样的,Docker客户端也是按这个流程去实现的,所以我们只需要在TencentHub后端按这个流程去实现自己的授权服务就可以了。
这里用一个时序图简单说一下它的流程。首先可以看到,Docker服务端首先会去访问/v2/这样的路径,客户端会根据当前是否有携带Token来返回一个授权的地址,我们目前返回的是hub.tencentyun.com/token这个地址,客户端就会自动访问/token的URL,带上当前的账户以及申请的权限范围。客户端申请Token完成之后,就会进入Docker镜像拉取流程。
这里再简单补充一下关于distribution 规范的一些API。前面两个不说,主要是第三个,每个Docker镜像的上传都会访问到/v2/仓库名/manifests/tags|digest地址,在这个地址上,它支持去GET、PUT、DELETE,去实现Docker镜像在远端仓库的拉取/上传/删除的功能。刚才所说的Layer、Config文件,包括Menifests文件,也可以通过V2这个路径下面的name+blobs+digest去获取。更详细的规范,可以看一下OCI组织已经成为标准的说明,下面有个URL。
在权限控制下面会有API协议的函数处理,一些主要的业务逻辑,都在这里实现。最终到下面storage的实现,它提供了一套存储的插件机制,有一个标准的存储接口,规定了文件上传、文件移动等等接口,只要去实现就可以了。我们这里也会实现GOS,是对COS的简单封装,后面会做一个GOS简单介绍。
现在腾讯云容器服务的仓库是CCR,还没有提到TencentHub上面来。CCR有两个问题,第一是不同地域的镜像是不通的,比如说我们在广州上传一个镜像,想在硅谷拉取是拉取不到的,这是我们直接依赖了COS提供的分发能力,没有去对它做封装,COS是无法跨区域访问的,所以会存在这个问题,这会带来用户体验上的不一致,基于仓库的触发器、Docker镜像构建功能,都会受到这个问题的影响,所有基于仓库的服务都需要单独又去部署一份,维护上也带来了很大影响。所以我们就做了下面这一层。
前面基于Docker仓库关于镜像存储方面的分享,也是TencentHub镜像仓库里面最复杂的部分,关于artifact和heml chart这样的文件存储,我们就不做过多的实现,因为它的实现都类似。
我们为什么要去做一个TencentHub的DevOps引擎呢?因为我们发现很多客户在上云的时候,平时遇到非常多重复性的操作工作,例如在腾讯云UI上面做很多事情,没办法自动化或者腾讯云的API还不够好用等等各种问题。其实DevOps的自动化要求是很高的,我们不能加入大量的人工去操作,基于这个考虑,同时还要照顾到中长尾客户的一些需求,我们最终决定要做一个DevOps的工具,去帮用户来建立自己的DevOps流程。
这里是我们考虑如何去做这个事情。第一点,要实现DevOps这样一个工具,首先要把DevOps任务编排起来,所以我们需要做到一个能尽量覆盖到尽多客户DevOps需求的编排逻辑。第二,DevOps任务是千差万别的,我们没办法去开发完所有的插件,去适配每个客户自己的需求,他们的部署策略,他们的单元测试、编译等等。所以我们需要把这些任务交给客户自己去完成,需要设计一个插件机制,就是Component,后面会介绍。第三点,用户的DevOps流程运行在TencentHub里面,我们需要真正去执行它,但我们不想去发一个执行任务的集群,我们只需要只需要做很简单的任务调度,然后交给成熟的集群管理组件完成。所以我们最终还是选择kubernetes来做这个事情,也就是TKE,它为我们省去了很多运维工作,还有TKE的监控都可以复用。
Component的设计我们后面再详细介绍。
workflow被触发执行,就会在系统中把它置成一个pending状态。因为每个客户有配额限制,我们的scheduler会去检查这个用户的配置是否足够,例如他如果有些比较长的workflow执行,我们会一直将它放在一个调度的状态,当检查通过之后,就会被投入到TKE当中去执行。但是它也不一定马上会运行起来,因为TKE的资源也有可能会比较紧张,我们这里提供的是公有云服务,所有人都会访问,所以资源可能会临时不够用,也会处于pending。我们会有一个状态的检测服务,不停的轮巡job的状态,如果发现部分它已经脱离了pending,进入了其它状态类型值,我们就会把它标定为running状态。如果一个stage被标记为是一个可暂停的stage,这个stage里所有的job被执行完之后,我们会把它标记为已被暂停的状态,这时候它需要等待外界的反馈,来决定这条workflow继续如何走: 如果外界反馈说它要取消,workflow就会进入到整个流程的结束。
首先,每个job都考虑成为一个类似于函数一样,去处理输入,在内部做一些自己的业务逻辑,最后通过我们定义的标准输出,去输出一些它处理完的信息。第二,job可以从workflow全局环境变量中去读取信息,做一些逻辑。这些环境变量不能修改,因为如果我们提出一个全局可修改的变量存储,它会导致整个component的调试或者开发会非常麻烦。第三,每个component肯定需要和外界打交道,我们workflow里面会去提供cache和artifact指令,让用户可以非常方便地把container里面构建出或者运行的一些结果保存到我们提供的外部存储里面。第四,workflow没有办法去循环执行,只是一个DAG构成的关系图,然后一条一条向前执行。这是我们设计workflow的一些考虑,没有去违背这些,才去做接下来的开发。
Cache,是用来在不同的job之间共享和传递一些数据,它可以是文件夹,也可以是文件。Artifacts是构建出的一些结果,可以保存在TencentHub仓库里面,在仓库里面有界面,也有API,可以进行查看或者拉取下来。Cache没有去跨多个workflow实例。Cache的具体实现工程是对指定的文件/文件目录进行压缩,上传到TencentHub的对象存储里面。当下面有一个Job依赖它的时候,又会在Component内部把它下载下来。整个实现就是在两个hook中进行完成,两个hook一个是Prestart,一个Poststop,后面会介绍我们如何去实现hook机制。
我们选择了用容器来做DevOps,为什么我们要选择用容器来做这样的插件机制呢?也是考虑了很久,讨论了很久,核心是基于下面四个考虑。
Component像一个函数实现一样,会有Input和Output,每个Component可以从另一个Component的Output去添加需要使用的一些输出值,workflow会把它变成Component执行的容器的环境变量,注入到当前Component里面。在Component容器进程里面可以使用这些环境变量做一些逻辑,比如说克隆指定版本的代码,或者发布上一个环节构建出的版本。Component的输出直接放到标准输出里面,我们规定了每一行只要符合下面红色地方标明的数据格式,我们就把它作为Component的输出。选择这样不够优美,但是非常实用的方式去实现,是考虑到如果使用外部的存储比如redis对input/output 作为存储,会对用户编写Component造成很大的影响:需要在Component里面还要去调用外部存储,保存输出需要存储一个Key,在下一个阶段使用时又要用key到存储里去取出来。虽然可能用一个第三方的存储会带来更丰富的数据结构方面的优势,但是我们认为对客户开发Component侵入性太大,所以我们直接用环境变量和标准输出来做这个事情。
workflow是在我们的TKE去执行的,选择用DevOps做workflow引擎的执行集群,是基于这些特性去考虑的。
前面到使用Component作为插件的时候,使用到 Prestart和Poststop这两个hook,在设计的时候,我们调研过是否能复用kubernetes pod 的Poststop。发现是不行的,Poststop是在pod的生命没结束之前由外面的controller去结束一个pod的时候执行(这才会有机会在容器之内去运行指定的hook程序)。但如果像workflow这种Task是一次性执行然后自行退出的,kubernetes没有办法在进程正常前调用调用Poststop里面指定的程序 – kubernetes不知道什么时候Task会退出 。所以我们最终实现了自己的方式: workflow把Component在kubernetes里面运行变成pod前,把它的CMD替换成另一个程序CommandWrapper,这个程序采用静态链接,保证可以在Linux上运行。CommandWrapper会在组件component任务被执行之前,会完成Cache和Artifact相应的逻辑,然后component会在子进程中运行,子进程退出后, CommandWrapper会继续处理Cache和Artifact的上传逻辑,最后,CommandWrapper程序会以子进程所退出状态码进行退出,如果是返回码是0,workflow引擎就把它标记为是成功运行,然后会调度下一个job的运行。这就是我们去设计的Hook机制。
这里简单介绍如果workflow引擎如何获取Task的Log。开发人员常常需要查看每个运行的workflow job的Log。可能workflow里面会有Bug,或者想看它当前进行到什么地步。Log的获取没有使用Docker driver,因为这在kubernetes里面目前还没有实现,即时kubernetes支持了docker的log driver,通过单独的通道去收集Log也会带来很大的复杂性,所以workflow引擎直接调用了kubernetes的API去获取它的Log,因为kubernetes API的Log只要在调用没退出之前,会一直把pod运行的Log从集群里面读出来,返回给调用方。Workflow引擎把整个Log存起来,放到COS里面,或者最后把它通过websocket去写到前端,让用户可以去实时查看。当然,后者我们还没有实现,开发人员太少,但是我们预留了,可以这样去做。
今天没有给大家分享怎么去搭建自己DevOps流程的例子,因为我相信这是千差万别的,在不同的公司,不同的组织里面,流程都不相同,我们没有办法枚举出来。而是站在公共服务的提供商角度,考虑怎么给用户最大的便利去建立这样一套工具。所以我今天的分享主要是关于DevOps的设计和一些实现细节,希望对大家会有一些帮助。
TencentHub这个产品目前已经在腾讯云官网上开启内测,邀请大家一起来体验这个产品,也欢迎大家的反馈和吐槽。
https://cloud.tencent.com/product/thub