最近我们的项目经理问了我一个直击灵魂的问题:为什么 Terraform 可以用于多云迁移?
我差点脱口而出:那显然是因为 …
因为啥呢?我突然意识到,这个问题的答案可能一点也不显然,我默默的在心里想了一个晚上,于是有了这篇文章。
什么是多云迁移
一般情况下,多云迁移是指将整个业务系统的拓扑从一朵云迁移到另外一朵云上,包含基础设施、应用,以及围绕着基础设施与应用的一整套工作流。
什么时候会进行多云迁移呢?例如你想从私有云迁移到公有云、想从一家云商迁移到另一家云商就是一个典型的多云迁移场景。并且「在同一家云商创建一个灾备集群」本质上也是这个场景的一种特例。
图 1 使用 Terraform 进行拓扑发现
从顶层的视角来看,我们常说的多云迁移其实是包括基础设施的拓扑、网络的拓扑以及应用的拓扑这三种拓扑关系的迁移。也就是说在迁移前后,我们要尽可能保证资源之间的关系,网络之间的连通性,应用之间的调用关系和方式不发生变化。那么 Terraform 在这里可以扮演什么角色呢?
什么是 Terraform
首先来看,什么是 Terraform?引用一段对 Terraform 的描述:
Terraform 是 Hashicorp 公司开源的一种多云资源编排工具。使用者通过一种特定的配置语言(HCL, Hashicorp Configuration Language)来描述基础设施,由 Terraform 工具统一解析,构建资源之间的关系,生成执行计划,并通过调用各家云厂商的具体实现来完成整个基础设施生命周期的管理。
简而言之就是用一种特殊的文本格式来描述基础设施,之后对基础设施进行 CRUD 的一种工具。
在生产环境实际的使用中,我们观察到,大家非常喜欢把它当作一个命令行工具创建资源,不用担心失败,重试操作是幂等的,极为省心。这其实是一种极端的用法,在这种模式下,它相比手写一个脚本或者串联一些 Ansible Module 封装成 Playbook,只是减少了一些工作量,实际上并没有什么不同。
而 Terraform 相比其它的工具来说,如何可以更适用于多云迁移呢?
资源依赖图
可能大家一看到标题,就知道我接下来要说什么了。是的,Terraform 基于 DAG(有向无环图),可以严格描述资源之间的拓扑关系。这也是它跟其他的工具最本质和最直观的区别。多云迁移时,如果想去映射资源与资源之间的拓扑,首先必须可以拿到一张完整的拓扑,Terraform 可以以极低的成本拿到它。
图 2 Terraform 状态文件示例
首先 Terraform 将所有信息都存储在一个状态文件中,这个状态文件中描述了完整的资源拓扑关系,社区也有一些可视化工具来读取它(虽然并不是非常完备,参考 Blast Radius),但对于自动化工具来说,这个带有依赖关系的数据文件是后面一切工作的基石。
其次 Terraform 支持“导入已经存在的资源”这一能力,Google 牵头的 Terraformer 项目更是加速了这一工程,可以一键导入一家云厂商存量资源的结构。并且 Terraform 对接了几乎所有主流云厂商的 API,省去了一个一个适配云厂商 API 的成本。
最后 这个拓扑结构甚至是可以更新的!这一点至关重要,因为往往一个多云迁移的项目往往跨越几个月的时光,不能及时更新的拓扑,往往会产生灾难性的后果。Terraform 本身对于读操作的幂等处理,使得重复导入是一个安全的过程,只需要妥善处理资源的 name 和 id,相同资源导入即刷新,就可以不断更新这个拓扑的状态。
不断变化的网络
在上一步我们已经拿到了一张完整的资源拓扑,也许我们已经做好了跨云的资源映射,这个时候的网络有两种可能的情况:
1.我们通过新的集群虚拟网络内的静态 IP,几乎完美复制了一套网络拓扑过来,任何实例的内网 IP 都没有变,以前的程序还能继续用,Awesome!
2.我们没有固定 IP,应用之间的连接通过名字服务还能用,但是我要通过脚本下发控制指令,怎么办!
第一反应是查 CMDB,但是 CMDB 还没对接这朵云怎么办?研发那边已经催着我改文件描述符上限了,在线等,急!
Don’t Panic,Terraform 的状态文件也可以作为 CMDB 的基准,可以简单粗暴地写一个脚本,从状态文件中读取 IP 等信息输出 Ansible dynamic inventory,如下图这样自定义分组,将 Terraform 状态直接当作 Ansible inventory 使用(可参考 terraform-inventory 项目)。但对于大多数业务来说,针对自身业务定制一个脚本也许是更好的选择。
图 3 Ansible 集成示例
在这个简单的示例中,基于的一个事实是,在上一步我们拿到的资源拓扑是严格的,并且是可以更新的,我们才可以基于它拿到信息去做二次处理。
应用迁移
目前看来,Terraform 的定位是基础设施编排,应用编排暂时不在此列,对于应用的迁移,Terraform 能做的有限,这里也分为两种情况:
图 4 容器应用交付示意图
第一种是应用已经在 K8S 上的,直接由 K8S 接管,Terraform 只负责拉起一个 K8S 集群即可,例如 TiDB Operator 项目,由于容器化的应用本身是跨平台的,可以完美迁移过来。
这里不得不重点提及一个项目:Pulumi,它是新一代面向资源的多云 SDK,类似于 AWS 的 CDK。Pulumi 对于跨云基础设施编排的做法是,在 Terraform 和 Pulumi 之间架设了一个桥,直接将 Terraform 的 Schema 转换成原生编程语言的 Pulumi SDK,在运行时唤醒 Terraform Provider 并通过 RPC 来调用它完成基础设施编排,巧妙地避免了与社区割裂。
Pulumi 在此基础上增加了 Crosswalk 子项目,用于跟其他的编排引擎如 K8S 集成,既可以编排容器和基础设施,也可以将应用代码 Serverless 化,打破了基础设施和应用编排的边界。
Pulumi 作为 Terraform 与 Native Language 之间的一座桥梁,对于非常高阶的用法,例如要在基础设施与应用层中间做各种策略,可以考虑使用 Pulumi 来进行二次开发。
图 5 传统应用交付示意图
第二种是应用不在 K8S 上的,也需要分两种情况:
1.如果策略不复杂,可以考虑使用 Packer 打包系统镜像,将应用以系统镜像的形式交付,Terraform 仅用于完成“最后一公里”的计算资源拉起环节。或者在这一环节完全舍弃 Terraform。
2.如果策略很复杂,Terraform 能做的非常有限,最好加一个控制器层,用来分发镜像和做一些复杂的逻辑等,或者使用一些成熟的抽象层,如基于 Packer 做多云发布的 Spinnaker 等工具,可以整合跨多云的发布管道,这里就不展开了。
让我们回过头来看这些应用编排相关的工具与技术,其实并不一定限定于一定要使用哪个,比如 Spinnaker 一样可以用于 K8S、Pulumi 也一样可以用于云主机,只是 Terraform 的定位在这里不同。Terraform 本身专注于基础设施编排,对于拥有复杂策略和实时工作负载的应用编排,并不适合完全使用 Terraform 来编写,但可以借助于 Terraform 的生态整合能力去复用社区的力量,取得成本和收益的更好平衡。
总结
综上所述,Terraform 可以用于多云迁移的关键在于,它可以描述资源之间的拓扑关系,开箱即用,适配多云 API。对于应用的迁移,Terraform 能做的有限,但可以作为生态内其他工具的基准,因地制宜,复用其它优秀工具的力量。
可以看到,在介绍多云迁移的时候,有很多其他工具的身影,比如 Ansible、Pulumi、Spinnaker 等。我很欣喜地意识到,随着云资源、应用、甚至是安全合规的代码化,基础设施相关的工具链已经到了百花齐放的时期。这是最好的时代,希望我们一起前行!
评论 2 条评论