什么是编程语言式IaC?
很多人会把编程语言式 IaC 称为命令式 IaC(即声明式的另一面),着重关注配置资源并达到运行状态的所有步骤。但实际上这类 IaC 工具更多地利用了编程语言的动态性,其核心是使用基于期望状态的声明性基础架构作为代码模型。因此,把它称作“编程语言式 IaC”更为贴切。
在什么是声明式IaC?中所提到的不足恰好可以通过编程语言来弥补,比如函数、循环、变量等特性均是程序员所熟悉的典型抽象能力。一旦使用编程语言,也就能够获得 IDE 带来的诸多好处。既然如此,自然就会想到使用编程语言来定义基础设施,这就是编程语言式 IaC 的由来。
如果您还不了解 IaC 的概念,请阅读什么是基础设施即代码(IaC)。
常见的编程语言式 IaC 工具
常见的编程语言式 IaC 工具包括:
在声明式 IaC 之上结合编程语言构建的各类 CDK (Cloud Development Kit) 工具,包括 ROS CDK、AWS CDK、CDK for Terraform 等。
直接基于编程语言的多云 IaC 工具 Pulumi。
下面展示如何使用 ROS CDK 和 Pulumi 编写出用于创建阿里云安全组及规则的代码。
ROS CDK
ROS CDK 是阿里云资源编排服务(ROS)提供的一个云资源开发套件,允许用户使用多种编程语言定义云资源。ROS CDK 会自动将编程语言代码转换为 ROS 模板,并进一步调用 ROS API 进行自动化部署。
下面是使用 Python 语言编写的 ROS CDK 代码,它定义了专有网络、安全组及两条入规则(开放 TCP 80 端口和 ICMP 协议):
import ros_cdk_core as core
import ros_cdk_ecs as ecs
class RosCdkDemoStack(core.Stack):
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
vpc = ecs.Vpc(self, "Vpc", ecs.VPCProps(
vpc_name="my-vpc",
cidr_block="192.168.0.0/16",
))
sg = ecs.SecurityGroup(self, "SecurityGroup", ecs.SecurityGroupProps(
security_group_name="my-sg",
vpc_id=vpc.ref,
))
rules = [{"IpProtocol": "tcp", "Port": 80, "Suffix": "80"},
{"IpProtocol": "icmp", "Port": -1, "Suffix": "ICMP"}]
for r in rules:
ecs.SecurityGroupIngress(
self, f"SecurityGroupIngress_{r['Suffix']}",
ecs.SecurityGroupIngressProps(
security_group_id=sg.ref,
nic_type="intranet",
ip_protocol=r["IpProtocol"],
policy="accept",
port_range="{0}/{0}".format(r["Port"]),
priority=1,
source_cidr_ip="0.0.0.0/0",
))
上述代码中,描述专有网络和安全组的内容和什么是声明式IaC?的 ROS YAML 模板很相似。但关于两条安全组规则的描述却体现出了很大的差异性,这里通过编程语言的变量定义与循环巧妙减少对规则中重复条目的描述,此外,借助 Python 等编程语言中字典和字符串格式化的能力,可以优雅地处理更加复杂的属性赋值情况。这是声明式 IaC 很难做到的。
此外,还可以看到 ROS CDK 的代码量要比 ROS YAML 模板更少一些,随着基础设施变得越来越复杂,这种代码量的差距也会越来越大。
借助编程语言,本地编码除了能够享受代码提示和补全,也能够享受类型检查。上述代码中的每个参数均有类型定义,能最大程度地减少人为的编写错误。甚至可以利用编程语言的抽象能力,将一段重复或复杂的代码封装到一个函数、类中;对于更加复杂的情况,可以把它打包到库中进行分发。其他人就能够通过简单干净的接口复用这段代码,从中收益。
Pulumi
Pulumi 是一个开源的、多云的 IaC 工具,它允许用户使用熟悉的编程语言来编写基础设施代码。Pulumi 的开源引擎会理解这些语言并直接调用云厂商的 API 以进行自动化部署。此外,它不仅支持多云,也支持更上层的 SaaS 应用。
下面是使用 Python 语言编写的 Pulumi 代码,它定义了专有网络、安全组及两条入规则(开放 TCP 80 端口和 ICMP 协议):
from pulumi_alicloud import ecs, vpc
vpc = vpc.Network(
"Vpc",
vpc_name="my-vpc",
cidr_block="192.168.0.0/16",
)
sg = ecs.SecurityGroup("SecurityGroup", name="my-sg", vpc_id=vpc.id)
rules = [
{"IpProtocol": "tcp", "Port": 80, "Suffix": "80"},
{"IpProtocol": "icmp", "Port": -1, "Suffix": "ICMP"},
]
for r in rules:
ecs.SecurityGroupRule(
f"SecurityGroupIngress_{r['Suffix']}",
security_group_id=sg.id,
type="ingress",
nic_type="intranet",
ip_protocol=r["IpProtocol"],
policy="accept",
port_range="{0}/{0}".format(r["Port"]),
priority=1,
cidr_ip="0.0.0.0/0",
)
整体来看, Pulumi 同各个 CDK 工具的代码都很像,都是允许用户选择熟悉和喜爱的编程语言,使用基于期望状态的声明性基础架构作为代码模型。其主要区别在于:
部署原理不同:Pulumi 的引擎是在理解这些编程语言后直接调用云厂商的 API 以进行自动化部署;而 CDK 则是将编程语言“翻译”成对应模板(对于 ROS CDK 是 ROS 模板、AWS CDK 是 CloudFormation 模板、CDK For Terraform 是 Terraform 配置文件),再使用对应平台的引擎进行自动化部署。
支持的范围和力度不同:Pulumi 和 CDK For Terraform 支持的范围更广,支持包括所有主流云厂商和主流的 SaaS 提供商。ROS CDK 和 AWS CDK 则是支持自己的云厂商,但支持的覆盖度、及时性和便捷程度会更胜一筹。
自动化测试的能力不同:由于部署原理的不同,Pulumi 可以运行快速、内存中(离线)的单元测试,并模拟对云厂商的外部调用;而 CDK 则是针对由其生成的各类模板进行断言测试。