GrowingIO Terraform 实践
背景
为满足 GrowingIO 客户多样性的需求,在公有云设施上使用 Terraform 作资源管理。采取 Terrform 具有以下相关优势:
多云支持,主流云厂商均提供对应的
Provider
支持。自动化管理基础结构,可重复对资源进行编排使用。
基础架构即代码
(Infrastructure as Code)
,允许保存基础设施状态,便于追踪管理。统一的语法来管理不同的云服务,实现标准化管理。
Terraform 介绍
概念
Terraform
是一个开源 IAS
工具,提供一致的 CLI
工作流,可管理数百个云服务。 Terraform
通过将云厂商提供的 API
编写为声明式配置文件,通过Terraform
的命令行接口,可将资源调度配置应用到任意支持的云上,并实现版本控制。更多详情请参见HashiCorp Terraform。
Terraform
通过不同的Provider
来支持不同云平台。国外云服务商如 Azure
, AWS
, GoogleCloud
, DigtalOcean
,国内云服务商如 Aliyun
, TencentCloud
, Ucloud
, BaiduCloud
均有提供官方的 Provider
。
架构
Terraform
通过解析用户书写的HCL(HashiCorp Configuration Language)
格式的DSL
文件,然后通过Terraform core
与各云厂商提供的Providers
进行交互,从而进行相关资源的调度。各云厂商依HCL
代码风格,将自家资源调用API
重新封装,以生成对应的 Providers
。
项目实践
项目设计
客户项目存在多个同构环境,环境交付需要一致。
每个环境中存在中多个项目,各项目对资源调度需求各异。
每个项目需要使用
EC2
、ELB
、EBS
、EMR
等多种资源。
项目实现
项目结构
目录结构拆解:
module
中依项目名进行封装。其中app1
为项目名。global
为全局参数设置。dev
为各环境对module
的引用封装。
module
细节:
config.tf
为配置的相关参数,如Providers
的相关参数设定。locals.tf
为变量的计算生成与其它变量引用,如module
的引用与一些复杂变量的重生成。main.tf
为resource
与data
相关的资源编排调用。outputs.tf
为项目输出值,如创建ecs
之后主机的ip
等。variables.tf
为传参的相关设置,如需创建ecs
的数量。
module
封装
module
的资源引用
在对资源调度的实施过程中,往往需要多次重复作业,故需将多个原子操作,统一封装成module
,后续在外部引用module
并传入对应参数即可。
apply
构建文件代码:
module
的条件判断
在 Terraform
中,往往将循环与判断结合使用,主要使用场景有两种:
确认变量形式
确认资源是否创建
如创建 ecs
时的主机名设置,当创建多台主机时,主机名需数字后缀以区分,而只有一台主机时,不需要数字后缀。
相关实例代码如下:
如在ECS
的创建之中,无法判断用户是否需要数据盘。
相关实例代码如下:
当用户传入var.aws_ebs_block_device_volume_size
的值为0
时,即循环一个空列表,即不创建该资源,亦即不创建数据盘。
module
的复杂循环
在 Terraform
中,循环主要依赖于count
与for_each
,这两种方法均只支持简单的循环,而for
循环更多的是参与计算,并不会直接在resource
中直接进行使用。
如在app1
项目中,需要创建 5 台实例,同时实例需分布在不同的subnet
之中,但subnet
只有 3 个。在该情况下,我们无法简单的以subnet
的id
作循环,更为重要的是,如果后期 subnet
的数量也可能会变化,所以无法固定循环列表。
对于复杂的循环需求,一般将其置于locals
中作相关计算,其后在resource
中进行引用 。
在locals
中的计算,相关代码如下:
通过在locals
中的计算,我们可以得到一个名为subnet_list_combine
的list
,其后在resource
中进行引用即可。
resource
相关代码如下:
全局变量
在Terraform
中,官方为了层级的简洁,默认不推荐使用全局变量,因为全局变量的设置,会出现所见非所得的现象,详见Terraform global variables
但在实际生产中,却有相关需求,如 aws_profile_name
在每个项目中均一致,同时后期因为用户的 profile
设置不一致而需要统一变更。
我们可以将此类参数写入一个 module
之中。
在各项目中的module
,再次对global
的module
作引用。
最后在项目中,作对应自身module
的locals
值作相关的引用。
环境隔离
在Terraform
中,隔离一般有两种:
workspace
隔离目录隔离
在 workspace
隔离中,需要使用 terraform workspace
子命令,与 git branch
类似,但是 terraform workspace
中的隔离,并不直观,在生产中容易出现误操作,所以对于不同环境的 module
调用,本项目中采用了目录隔离。
项目心得
Terraform
在基础资源编排中,使用方便,语法简洁,但由于各云厂商提供 Provider
的风格并不完全统一,一定程度上增加了多云混合使用的成本。特别是对于国内非 AWS
用户而言,国内部分云厂商提供的Provider
,支持的资源种类相较于 AWS
偏少,部分场景可能无法实现。
同时也因为 Terraform
的语法对于一些高级特性的支持欠缺,导致在部分复杂的场景中,有些捉襟见肘,而更多需要 Provider
去提供对应功能。虽然有 module
的设计,可以进行代码复用,但也有因部分参数无法动态区分,而不得不创建多个 module
以区分,这点在国内云厂商提供的 Provider
中尤为明显。
小结
本文简单介绍了Terraform
的基本概念以及采用Terraform
的原由。
同时例举了在生产实践中Terraform
的目录结构编排与环境隔离,详细说明如何通过传参来动态调整资源编排的实际传参与调度,如何通过多次组合计算以动态生成新的参数来规避Terraform
对高级特性支持的欠缺,以及如何构建全局变量以解决全局动态传参。基于篇幅限制, Terraform
的使用无法逐一说明,对Terraform
有兴趣的同学可自行学习了解。
参考
Mikael Krief. Terraform Cookbook: Efficiently define, launch, and manage Infrastructure as Code across various cloud platforms. Packt Publishing 2020
Scott Winkler. Terraform in Action. Manning 2021
Yevgeniy Brikman. Terraform: Up & Running: Writing Infrastructure as Code. O'Reilly Media 2019
版权声明: 本文为 InfoQ 作者【GrowingIO技术专栏】的原创文章。
原文链接:【http://xie.infoq.cn/article/841c6a726ce8527ada718137a】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论