IaC:简洁 or 灵活

文章目录

  1. 1. 方案一: 动态分组
  2. 2. 方案二: 静态分组

最近在搞devops,有一点对Infrastructure as code代码风格的感悟

直接从一个例子展开吧

假如需要将原来单账号下以下多网络分别创建到单独的账号下

1
2
3
4
5
6
7
8
9
10
11
12
# network.auto.tfvars
vpcs = {
network1 = {
name = "vpc-1"
}
network2 = {
name = "vpc-2"
}
network3 = {
name = "vpc-3"
}
}

为了网络创建复用自然需要使用module去按账号构建

(别想动态指定providerterraform不支持!)

那问题是怎么将vpc的配置按账号分组传递给对应的module

来看两种方案

方案一: 动态分组

给每个vpc配置加acct_key, 然后代码动态分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# network.auto.tfvars
vpcs = {
network1 = {
acct_key = "a"
name = "vpc-1"
}
network2 = {
acct_key = "a"
name = "vpc-2"
}
network3 = {
acct_key = "b"
name = "vpc-3"
}
}

## main.tf
locals {
# 按 acct_key 聚合网络
grouped_networks_as_array = {
for k, v in var.vpcs :
v.acct_key => { "${k}" = v }...
}
grouped_networks_as_object = {
for k, v in local.grouped_networks_as_array :
k => merge({}, v...)
}
}

output "group_result" {
value = local.grouped_networks_as_object
}
provider "external" {
alias = "acct_a"
}
provider "external" {
alias = "acct_b"
}
module "acct_a_vpcs_1" {
source = "./vpc"
vpcs = local.grouped_networks_as_object.a
providers = {
external = external.acct_a
}
}
module "acct_b_vpcs_1" {
source = "./vpc"
vpcs = local.grouped_networks_as_object.b
providers = {
external = external.acct_b
}
}

聚合那里代码需要两段,主要是terraform的默认聚合,只会按key相同合并成array,但我们其实是要把array的每个元素合并成一个object, 方便后续按网络的key去索引资源创建的结果

(比如module输出了vpc资源的创建结果vpcs,就可以用module.acct_a_vpcs.vpcs.network1拿到network1的结果)

聚合后结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+ group_result = {
+ a = {
+ network1 = {
+ acct_key = "a"
+ name = "vpc-1"
}
+ network2 = {
+ acct_key = "a"
+ name = "vpc-2"
}
}
+ b = {
+ network3 = {
+ acct_key = "b"
+ name = "vpc-3"
}
}
}

这不是程序员最擅长的代码封装么,配置没怎么变,代码动态一聚合就完成了变更的需求。

等等,再来看一个方案

方案二: 静态分组

就是配置按账号重新拆分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# network.auto.tfvars
accounts = {
acct_a = {
vpcs = {
network1 = {
name = "vpc-1"
}
network2 = {
name = "vpc-2"
}
}
}
acct_b = {
vpcs = {
network3 = {
name = "vpc-3"
}
}
}
}

然后使用时按账号获取配置就是一目了然的事

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module "acct_a_vpcs" {
source = "./vpc"
vpcs = var.acct_a.vpcs
providers = {
external = external.acct_a
}
}

module "acct_b_vpcs" {
source = "./vpc"
vpcs = var.acct_b.vpcs
providers = {
external = external.acct_b
}
}

整体看下来两种方案好像都差不多,但如果考虑代码的简洁与配置聚合的粒度的话,第二种就更胜一筹

毕竟对于IaC而言,一目了然的简洁比复杂的代码抽象更易于维护,基础设施的配置文件本来就不应该搞复杂。

哈哈, 代码封装也有碰壁的时候。

当然也有需要代码封装的时候,比如把多个账号的vpcs结果合并起来,便于其他资源跨账号按vpc key查询资源id,路由表id啥的

1
2
3
4
5
6
locals {
combined_acct_vpcs = merge(
module.acct_a_vpcs.vpcs,
module.acct_b_vpcs.vpcs
)
}
如有疑问,请文末留言交流或邮件:newbvirgil@gmail.com 本文链接 : https://newbmiao.github.io/2024/08/17/iac-loves-simple.html