因文章略长,故分为三篇展开呈现,本篇为最后一篇。
workflow 引擎设计与实现
为什么要去做 Tencent Hub 的 DevOps 引擎呢?因为很多客户在上云的时候遇到了操作重复性的问题。而且 DevOps 的自动化要求还很高,再照顾到一些客户的需求,因此要做一个 DevOps 的工具,去帮用户来建立自己的 DevOps 流程。
这就需要考虑很多事情,第一,把 DevOps 任务编排起来,需要做到一个能尽量覆盖到尽多客户 DevOps 需求的编排逻辑,比如 Workflow;第二,DevOps 任务是差别较大,需要把这些任务交给客户自己去完成,需要设计一个插件机制 Component;第三,用户的 DevOps 流程运行在 Tencent Hub 里面,需要做很简单的任务调度,最终还是选择 Kubernetes 来省去很多运维工作,监控都可以去复用。
按业界通用的方法把 workflow 设计成三级结构,每个 workflow 包含多个 stage 来完成,每个 stage 里面会有很多 job。job 这里会有并行和串行的执行方式。stage 有一个类型叫 past+prst。在 DevOps 流程当中,在合适的时候是需要人工介入的,设计可以暂停的 stage 就能适应这样的场景。
workflow 的设计生命周期对流程推动十分重要。workflow 可以被触发执行,有三种方式。一,把某一条 workflow 和代码关联起来,当提交代码的时候,可以触发这条 workflow 的执行;二,可以和 Tencent Hub 的镜像存储关联起来,不需要代码去触发,可以通过 push 一个镜像去触发;三,通过调 API 直接触发某一条 workflow。
被触发后,就可以系统把它置成一个 pending 状态。Workflow 被触发执行,一个新建的 workflow 实例被置于 pending 状态,经过配额检查,scheduler 调用 k8s API 执行第一个 job,workflow 实例进入 scheduling 状态;StatusFetcher 检测 job 在 k8s 中的状态,如果不是 pending,workflow 实例进入 running 状态;
Scheduler 遇到可暂停的 stage(type=break),待 stage 中任务执行成功后,workflow 实例中的 job 被暂停调度,workflow 进入 paused 状态,等待外部 API 调用唤醒 workflow 的执行;end 是一组状态的描述,实际上包括 timeout、failure、success、canceled 四种状态。处于 paused 状态的 workflow 可以被终止。
workflow 上 job 在设计时需要考虑四点。第一,job 可以都考虑成一个函数去处理输入,在内部做一些业务逻辑,通过定义的标准输出处理完的信息;第二,job 可以从 workflow 全局环境变量中去读取,传进来做一些逻辑。第三,每个 component 都需要和外界接触,因此 workflow 里会去提供 cache 和 artifact 指令。第四,workflow 没有办法去循环执行,只是一个 DAG 构成的关系去一条一条向前执行。
关于 artifact 和 cache 的实现和作用是不同的,设计 Cache 是用来在不同的 job 之间共享和传递数据;Artifacts 则可以保存在提供的仓库里面。Cache 的具体实现如保存文件夹,它会把指定的文件目录进行压缩,上传到 Tencent Hub 的图形存储里面。当下面有一个 Job 依赖它的时候,会在 Component 内部下载下来。
为什么要选择用容器来做 DevOps 呢?第一,面对的所有用户是公共服务,隔离性是第一要务。用容器可以非常方便的帮我们实现不同用户的任务隔离,有些用户可能对自己任务的安全性要求非常好,后期还会考虑和 CIS 做结合,直接用 Clear Container 来提供更高的隔离性。第二是复用,在不同的部门之外,它们的技术段可能会有相似的,后台有一些公共的 DevOps 任务需要去使用,通过容器 Docker 镜像可以共享这样的逻辑;第三则是标准,组件的开发维护可用本地 Docker 进行测试;第四是平滑,从而能让已有的 DevOps 任务可通过容器快速进行封装。
Component 函数一样会有涉及到 Input 和 Output。Input 方面,输入值以环境变量的方式传入到 Component 中,包括 workflow 全局变量和上游 Job 的输出变量;而 output 方面,输出值写入到 stdout,workflow 通过分析日志进行提取;输出值格式为: JOB_OUT key=value ,可以通过输出多行 Log 来输出多个值;Component 进程执行成功后以状态码 0 退出。
Workflow 是采用了 TKE 去执行的,选择用 DevOps 做 workflow 引擎的执行集群是基于以下三大特性考虑的。首先,Kubernetes 的可靠性使得 TKE 非常可靠,从而不必去担心运维难题;第二,workflow 跑的很多任务可能会占用不同的资源,而 TKE 可以做到自动扩缩容,能为客户提供构建的能力,不需要人工介入;第三的资源分配更灵活,客户的 workflow 资源占用大小不同,这对 Kubernetes 来讲解决并不难。
关于 job 的两个 hook,在实现的时候需要注意到这些事情。Flow 引擎通过分析 Component 的 config,保存 Component 定义的 Entrypoint 和 Command;实现 CommandWrapper 程序,Job 运行指定该程序为 Pod 的 Command;CommandWrapper 启动后处理 PreStart 动作,如下载依赖的 Cache;CommandWrapper fork 子进程运行 Component 定义的 Entrypoint 和 command;子进程退出后,CommandWrapper 处理 PostStop 动作,如上传 Artifact、Cache 等;最后,CommandWrapper 以子进程的返回码作为返回码退出。
每一个构建的 workflow 的 job 需要去关心它的 Log。Job 是一次性任务,利用 k8s api 读取日志,比独立的日志收集通道更简单;dispatcher 读取日志之后,使用 multi writer 将日志交给 StatusFetcher 保存,同时可以通过 websocket 将日志推送给 web 页面。
到此,workflow 引擎实现和设计就基本完成。通过 Tencent Hub,经过思考,如何搭建自己的 DevOps 流程是千差万别的,以上方法站在公有服务的提供商角度,考虑给用户最大的便利而建立的一套工具。
云上构建容器化的大规模计算平台
看了这么多的技术解析后,那么究竟腾讯云的容器技术在其用户的手中是怎样的状态呢?晶泰科技是腾讯云在药物工业领域的合作伙伴,他们在云端部署大规模科学计算平台与腾讯云有着紧密的合作。
晶泰科技是一家以计算驱动的创新药物研发科技公司,在药物工业中,一款药的上市需要经过复杂的研发工序以及 10 年以上的漫长研发周期,而且越是重磅的药物,经历的周期就越长;因此腾讯云的合作伙伴晶泰科技致力于通过分子模拟平台、药物动力学等技术,借助云端大规模 HPC、AI 驱动、量子算法等预测技术,提升药物工业中临床前期的研发效率,为患者带来更优质的药物。
科学计算平台通常是跑在像天河这样的超算上, 但超算上大规模资源的申请需要排队, 对任务的调度管理, 数据存储都不太灵活, 而且在计算性价比上优势也不明显,综上我们提出, 能否把传统的科学计算搬到云端?目前一些批量计算、高性能计算已经迁移到云端。在把两部分技术结合之后,借助云端去构建一个大规模的 HPC 集群,可能会达到百万核实量级,可能会用到上万级的机器集群。
晶泰科技的小分子药物晶型预测流程中,需要用到构像分析、力场训练、晶体结构预测、结构聚类及排位算法等,每个流程都需要大量计算支持,而且越靠后计算需求越高这就需要借助云计算,甚至需要多个云融合在一起以便构建一个比较大规模的计算资源池,在里面执行大批量科学计算任务。
计算平台演变
计算平台在这几年发生了较大的变化。从 2015 年晶泰成立的时候推出了第一代计算平台,基于 PBS 调度系统以及 NFS 文件共享存储,架构上类似于超算的 PBS/LSF+SAN。系统都是使用开源组件搭建,命令行方式对任务进行提交及管理, 基本满足了前期使用需求。但是随着业务的发展,计算量需求越来越大,而第一代平台的计算资源利用率不足、PBS 动态管理能力有限, 以及 NFS 的 IOPS 压力等问题开始出现。
从第二代平台的迭代更新开始,我们使用 Mesos 对资源进行管理,自研 Mesos 的 Framework, 使用 Docker 打包科学计算的软件以及算法, 从此开始了云上科学计算的容器化之路。通过添加不同的计算资源, 计算池得到了进一步扩大。当我们单个资源池突破 1000 台机器时, 我们使用 Golang 重构了调度系统,以便支持更高性能的任务分发。接着我们通过接入多个公有云厂商,实现多公云资源弹性伸缩与监控。18 年开始, 随着 k8s 的高速发展, 调度平台也正式开始使用 K8s 去管理云上的超算集群。
第三代平台技术产品上主要是 CSP, Faces 晶型预测系统服务,以及最终产出计算报告的全自动工具 XtalVision。第二层主要是是预测流程中使用到的各种核心算法,融合了现有的科学计算算法进行二次开发、封装,打包成一个 Docker 镜像,业务人员只需要去使用这个 Docker 镜像,就可以在平台上提交对应的预测计算任务, 如一些能量计算以及一些通用力场的计算。然后是我们支撑大规模科学计算的高性能计算平台,最下面就是公有云的基础资源。
腾讯云容器服务实践
需要注意的是,超算和信息服务的计算有较大的差异。科学计算的特点是计算密集型,计算时间长,通常是异步计算,追求算法的执行效率并行化,主要以工作站或超算为主;信息服务的特点则是 IO 密集型,低延时高可用,利用架构提高系统容量及服务质量,大量使用云计算。
在开始之前我们简单介绍一下在云上构建科学计算的镜像, 科学计算使用的镜像跟服务化的镜像会有一些不太一样的地方, 一般科学计算的镜像大小会达到 GB 级别,因此需要对镜像进行剪裁和分层优化,以便加速镜像拉取速度。
下面的参数会涉及到镜像拉取的性能以及并发率。如:kubelet --serialize-image-pulls=false 是串行镜像拉取,通常情况下是 false,如果设置为 true,需要更高版本的 Docker 支持, 同时 docker storage 需要使用 overlay 作为镜像存储。kubelet --image-pull-progress-deadline=10mins 是镜像拉取超时, Docker 本身也会有并发拉取的参数在里面(如:dockerd --max-concurrent-download=5),以便在任务分发时减少镜像拉取时间。对于 kubelet 来说, 目前最新版的 K8s 已经支持动态修改 Kubulet 参数。
腾讯云的 TKE 容器服务,基本实现了一键就可以构建出一个带有 Master 的 K8s 集群。同时腾讯云打通了 TKE 和腾讯云其他云服务交互通道, 更易于系统的快速集成。TKE 会提供一个容器服务 API 出来,但是它主要还是针对一些信息服务编排, 对于高性能计算批量提交任务还不是特别适用, 因此我们使用了 k8s 原生 API 进行平台构建。
现在 K8s 已经发布到 1.11 版本,支持不超过五千个节点,在集群里面不超过 1.5 万个 pod,以及不超过 30 万个容器,单个节点不超过 100 个 pod。K8s 官方也提供了一些构建大集群的辅助文档在里面,但实际上在构建的时候还是会有形形色色的问题。
K8s 主节点集成已经由腾讯云构建出来,接下来需要要向集群中添加计算节点,TKE 提供了弹性伸缩组对集群资源进行动态扩缩容。但出于节约成本的考虑,伸缩组需要是高度弹性, 可以快速扩容大批量资源, 同时也能在任务计算完成时快速回收资源。比如晶泰就会有如下业务场景:
平台一次性提交 10 万个任务,每个任务需要 8 核的 cpu 去计算, 同时由于案例时间上的要求, 要求几天之内要把这些任务算完,所以此时需要让资源池从 0 扩容到 1000/2000 个节点一起跑。任务的计算复杂度很多时候都是有相似性的,因此计算的周期也比较相似,某个时间点就会有大批任务同时跑完, 大批量资源被释放出来, 这个时候又需要快速回收资源。经过与腾讯 TKE 团队一起排查, 目前基本在快速扩缩容这块满足了计算的需求.
到目前为此利用 TKE 构建了 K8s 集群并通过其快速弹性扩缩容组件实现资源的管控, 接下来我们看看计算平台上所支持的 HPC 任务.
简单地从时间维度来看,可以分为短时间任务和长时间任务。从精度来看可以分为低精度和高精度任务。在药物分子预测中的能力/排位等流程中都会对精度要求有,从右边图来说,不同的科学计算算法在不同的流程中都会有一个精度及时间的差别,通常精度越高需要的计算周期越长。
在支持的 HPC 多节点并行任务中,一些公有云的普通网络是没有办法满足像 MPI 这种多节点并行任务的。通常 MPI 任务多节点需要有一个高性能的网络, 如 IB 网络,需要一些专有的网卡去支持远程的直接内存访问(RDMA)。
MPI 任务的运行周期会相对长一些,右图是在晶泰基于 K8s 实现的 MPI 任务。刚才提及现有的 TKE 提供的网络没有达到通用的 MPI 的网络要求,但是一些数据并行化的 MPI 任务还是可以在一般性能的容器网络上面进行运算。它们特点是节点之间的数据交互通常是比较少的,这样网络数据传输也比较少,能避免高性能网络的带宽限制。其实 k8s 对构建高性能容器网络也提供了插件支持, 通过 k8s Device Plugins 可实现 NVIDIA/AMD GPU 及 RDMA/Solarflare 等外部组件接入。
容器云 TKE 提供了健全的服务监控,能够实时监控 pod CPU 以及内存。同时也提供了定制化的接入的方案,通过 heapster+influxdb+grafana 架构可以收集计算任务的 cpu/memory 信息,对于高性能计算关注的核心算法效率问题来说, 这些监控数据对我们平台算法的不断改进提供了很好的指导方向 。
值得一提的是, kubelet 10250 端口的参数,在安全组方面不能大意,如果没有把计算节点 10250 端口封掉,容易导致入侵,因为在开启了 enable-debugging-handlers=true 的情况下,外部可以直接通过这个端口,到 pod 里面进行集群调试。
综合来看,Kubernetes 的出现降低了容器服务的入门门槛和复杂性,解放了企业的技术精力,使之能够完全投入到行业所处的技术领域之中。而如 CIS、Tencent Hub 等技术工具的发展,容器服务的部署、监控、运维和管理都在变得更加高效,无论是医药交通,还是科算超算,都已开始享受技术发展的红利。可以看到的是,2018 年的 Kubernetes 技术,就如繁星之上的皓月,望眼可见,普照各地。
本文转载自公众号云加社区(ID:QcloudCommunity)。
原文链接:
https://mp.weixin.qq.com/s/_v6ZDG-eehCWBe-nOpclDA
评论