1. Important Points#
这个例子针对下面这个 root module 调用:
module "default" {
source = "terraform-aws-modules/alb/aws"
version = "10.5.0"
}Import 的对象不是 module.default 本身,而是 module 里面的具体 resource。地址必须和 module 源码里的 count / for_each 完全一致。
current root module:
module.default
ALB resource inside module:
aws_lb.this uses count
import address is module.default.aws_lb.this[0]
listener / target group / listener rule:
use for_each
import address must include the map key2. Full Resource List#
如果需要完整导入这个 ALB module 管理的所有资源,需要逐个导入 module 里的具体 resource。实际要导入哪些实例,取决于 listeners、target_groups、route53_records、WAF、证书和 attachment 等输入参数。
| Resource address | Import ID |
|---|---|
module.default.aws_lb.this[0] |
ALB ARN |
module.default.aws_security_group.this[0] |
security group ID |
module.default.aws_vpc_security_group_ingress_rule.this["http"] |
security group rule ID |
module.default.aws_vpc_security_group_ingress_rule.this["https"] |
security group rule ID |
module.default.aws_vpc_security_group_egress_rule.this["all"] |
security group rule ID |
module.default.aws_lb_listener.this["http_redirect"] |
listener ARN |
module.default.aws_lb_listener.this["https"] |
listener ARN |
module.default.aws_lb_listener_rule.this["https/<rule_key>"] |
listener rule ARN |
module.default.aws_lb_target_group.this["<target_group_key>"] |
target group ARN |
module.default.aws_lb_target_group_attachment.this["<target_group_key>"] |
target group ARN / target ID / port |
module.default.aws_lb_target_group_attachment.additional["<key>"] |
target group ARN / target ID / port |
module.default.aws_lb_listener_certificate.this["<key>"] |
listener 配置了 additional_certificate_arns |
module.default.aws_route53_record.this["<key>"] |
module 配置了 route53_records |
module.default.aws_wafv2_web_acl_association.this[0] |
module 配置了 associate_web_acl = true |
module.default.aws_lambda_permission.this["<key>"] |
target group 是 Lambda target |
3. Fake Values#
下面命令使用 fake ARN / ID。真实导入时替换成 AWS Console 或 AWS CLI 查到的值。
account_id:
123456789012
region:
ap-northeast-1
alb_name:
ping-uat-alb
alb_arn:
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/ping-uat-alb/d12dac00d9c29937
security_group_id:
sg-0123456789abcdef0
http_listener_arn:
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/ping-uat-alb/d12dac00d9c29937/80aaaaaaaaaaaaaa
https_listener_arn:
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/ping-uat-alb/d12dac00d9c29937/443bbbbbbbbbbbbb
listener_rule_arn_pattern:
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener-rule/app/ping-uat-alb/d12dac00d9c29937/443bbbbbbbbbbbbb/<rule-id>
target_group_arn_pattern:
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/<target-group-name>/<target-group-id>4. How To Derive Import Order From Module#
导入顺序不是 Terraform module 文档额外给你的东西,而是从 module 源码和 AWS 资源依赖关系推出来的。
先把 module 当成普通 Terraform code 看,不要只看 root module 里的 module "default" 调用。真正要导入的是 module 源码里的 resource block。
terraform init
terraform providers找到 module 下载目录后,直接搜索 resource:
rg -n '^resource "' .terraform/modules对 terraform-aws-modules/alb/aws 这种 module,重点看这些信息:
resource type:
resource "aws_lb" "this"
resource "aws_lb_listener" "this"
resource "aws_lb_target_group" "this"
count / for_each:
count means address uses [0], [1]
for_each means address uses ["key"]
references:
load_balancer_arn = aws_lb.this[0].arn
listener_arn = aws_lb_listener.this[each.value.listener_key].arn
target_group_arn = aws_lb_target_group.this[each.key].arn然后按下面的方法推导顺序。
1. 先导入被别人引用的基础资源
例如 ALB 本体、ALB security group。
2. 再导入依赖基础资源的子资源
例如 listener 依赖 ALB,security group rule 依赖 security group。
3. 再导入更细的绑定关系或规则
例如 listener rule 依赖 listener 和 target group,target attachment 依赖 target group。
4. 最后导入 optional / association 类型资源
例如 Route53 record、WAF association、additional certificate、Lambda permission。Terraform import 本身多数时候不会因为 state 里还没有父资源就失败,因为 import 是把一个远端对象放进一个指定地址。但如果顺序乱了,后面的 terraform plan 会很难读:Terraform 可能同时显示很多 create / replace / unknown diff,你不容易判断是配置不匹配,还是只是关联资源还没导完。所以推荐顺序的目的不是满足 Terraform 的硬性限制,而是让每一步 plan 都可解释、可回滚、可定位 drift。
对 ALB module 来说,依赖关系大概是:
ALB
-> listener
-> listener rule
-> listener certificate
security group
-> security group rules
target group
-> listener default action / listener rule action
-> target group attachment
-> lambda permission, when target type is lambda
ALB
-> WAF association
-> Route53 alias record所以本文的顺序才是:ALB / security group 先导入,target group 和 listener 居中,rule / attachment / optional association 最后导入。
5. Import Order#
推荐顺序:
1. ALB
2. ALB security group
3. security group ingress / egress rules
4. target groups
5. listeners
6. listener rules
7. target group attachments
8. optional resources: additional certs, Route53, WAF, Lambda permission
9. terraform plan and fix config driftALB、listener、listener rule、target group 的 ARN 可以用 AWS CLI 查:
aws elbv2 describe-load-balancers --names ping-uat-alb
aws elbv2 describe-listeners --load-balancer-arn '<alb-arn>'
aws elbv2 describe-rules --listener-arn '<https-listener-arn>'
aws elbv2 describe-target-groups --load-balancer-arn '<alb-arn>'
aws elbv2 describe-target-health --target-group-arn '<target-group-arn>'Security group rule ID 可以查:
aws ec2 describe-security-group-rules \
--filters Name=group-id,Values=sg-0123456789abcdef06. ALB And Security Group#
# ALB 本体。module 源码里 aws_lb.this 使用 count,所以地址必须带 [0]。
terraform import \
'module.default.aws_lb.this[0]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/ping-uat-alb/d12dac00d9c29937'
# module 创建的 ALB security group。aws_security_group.this 也使用 count。
terraform import \
'module.default.aws_security_group.this[0]' \
'sg-0123456789abcdef0'
# HTTP ingress rule,key 来自 default_alb.security_group_ingress_rules.http。
# 是sgr - Security group rule ID 不是security group id
terraform import \
'module.default.aws_vpc_security_group_ingress_rule.this["http"]' \
'sgr-0http000000000000'
# HTTPS ingress rule,key 来自 default_alb.security_group_ingress_rules.https。
terraform import \
'module.default.aws_vpc_security_group_ingress_rule.this["https"]' \
'sgr-0https0000000000'
# Egress rule,key 来自 alb_security_group_egress_rules.all。
terraform import \
'module.default.aws_vpc_security_group_egress_rule.this["all"]' \
'sgr-0egress000000000'Security group rule 的 import ID 是 rule ID,例如 sgr-...,不是 security group ID。
7. Target Groups#
target_groups 里的每个 key 都会进入 Terraform address。listener 里的 target_group_key 必须能对应到这里的 key,或者对应 module 支持的外部 target group ARN 配置。
# 固定 EC2 instance target group。
terraform import \
'module.default.aws_lb_target_group.this["victorialogs-vmauth"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/victorialogs-vmauth/bbb222bbb222bbb2'
# 固定 EC2 instance target group。
terraform import \
'module.default.aws_lb_target_group.this["ping-uat-ninedata-tg"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/ping-uat-ninedata-tg/ddd444ddd444ddd4'8. Listeners#
这个 sample 有两个 listener:
# 80 listener,默认动作是 redirect 到 HTTPS。
terraform import \
'module.default.aws_lb_listener.this["http_redirect"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/ping-uat-alb/d12dac00d9c29937/80aaaaaaaaaaaaaa'
# 443 listener,默认动作是 forward 到 ping-uat-alb-im-srv。
terraform import \
'module.default.aws_lb_listener.this["https"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/ping-uat-alb/d12dac00d9c29937/443bbbbbbbbbbbbb'9. Listener Rules#
Listener rule 地址格式:
module.default.aws_lb_listener_rule.this["<listener_key>/<rule_key>"]这个 sample 的所有规则都挂在 listeners.https.rules 下,所以前缀都是 https/:
# Host-only rule。
terraform import \
'module.default.aws_lb_listener_rule.this["https/logs-uat"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener-rule/app/ping-uat-alb/d12dac00d9c29937/443bbbbbbbbbbbbb/rule000000000005'
# Host + path rule。
terraform import \
'module.default.aws_lb_listener_rule.this["https/api-uat"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener-rule/app/ping-uat-alb/d12dac00d9c29937/443bbbbbbbbbbbbb/rule000000000090'logs-uat、api-uat 等 rule key 不会显示在 AWS Console。AWS Console 里能看到的是 priority、conditions、actions 和 rule ARN。
10. Target Group Attachments#
terraform-aws-modules/alb/aws 的 target group 默认 create_attachment = true。如果 target group 里配置了固定 target_id,module 会创建:
module.default.aws_lb_target_group_attachment.this["<target_group_key>"]Import ID 使用 target group ARN、target ID、可选 port、可选 availability zone 组成,字段之间用逗号分隔:
TARGET_GROUP_ARN,TARGET_ID[,PORT][,AVAILABILITY_ZONE]这里的 target ID 是被 target group 注册的后端目标,不是 target group 自己的 ID。
target_type = "instance":
target ID is EC2 instance ID, for example i-00da965592ca402e0
target_type = "ip":
target ID is IP address, for example 10.0.12.34
target_type = "lambda":
target ID is Lambda function ARN
target_type = "alb":
target ID is ALB ARN真实值可以从 target health 里查:
aws elbv2 describe-target-health \
--target-group-arn '<target-group-arn>'返回里的 Target.Id 就是 import ID 里的 target ID,Target.Port 就是 import ID 里的 port。
固定 EC2 instance target 的例子:
terraform import \
'module.default.aws_lb_target_group_attachment.this["victorialogs-vmauth"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/victorialogs-vmauth/bbb222bbb222bbb2,i-00da965592ca402e0,8427'
terraform import \
'module.default.aws_lb_target_group_attachment.this["ping-uat-ninedata-tg"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/ping-uat-ninedata-tg/ddd444ddd444ddd4,i-02ac8a7a6f3fc85b7,9999'ECS service 动态注册 task IP 的 target group 通常不要让这个 ALB root module 管理具体 attachment。应该在这些 target group 上显式设置:
create_attachment = false这些 key 作为 ECS 动态 target 或没有固定 target_id 的示例,通常不导入 attachment:
ping-uat-alb-im-srv
group-data-center-backend-tg
sub2api-targets
ping-uat-alb-im-admin如果某个 ip target group 确实要由 Terraform 固定管理 IP attachment,示例是:
terraform import \
'module.default.aws_lb_target_group_attachment.this["sub2api-targets"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/sub2api-targets/fff666fff666fff6,10.0.12.34,8080'11. Additional Attachments#
如果使用 additional_target_group_attachments,地址不是 .this[...],而是:
module.default.aws_lb_target_group_attachment.additional["<attachment_key>"]示例配置:
additional_target_group_attachments = {
sub2api_private_ip_1 = {
target_group_key = "sub2api-targets"
target_id = "10.0.12.34"
port = 8080
}
}对应 import:
terraform import \
'module.default.aws_lb_target_group_attachment.additional["sub2api_private_ip_1"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/sub2api-targets/fff666fff666fff6,10.0.12.34,8080'12. Extra Module Resources#
additional listener certificate#
这个对应 AWS Console 里 HTTPS listener 上的 SNI certificate list,也就是额外证书,不是 listener 的 default certificate。
listener default certificate:
managed by aws_lb_listener.this["<listener_key>"]
configured by listener certificate_arn
additional SNI certificates:
managed by aws_lb_listener_certificate.this["<key>"]
configured by additional_certificate_arns这是完整 sample 的额外证书配置例子:
additional_certificate_arns = [
"arn:aws:acm:ap-northeast-1:123456789012:certificate/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
]module 会创建 aws_lb_listener_certificate.this。它的 key 来自 listener key 和证书列表 index,导入前先看 module 的 local.additional_certs 生成逻辑或 terraform plan 中的地址。
aws_lb_listener_certificate 的 import ID 使用 listener ARN 和 certificate ARN 组成,中间用下划线 _ 拼接。
示例:
terraform import \
'module.default.aws_lb_listener_certificate.this["https/0"]' \
'arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/ping-uat-alb/d12dac00d9c29937/443bbbbbbbbbbbbb_arn:aws:acm:ap-northeast-1:123456789012:certificate/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'Route53 record#
这是完整 sample 的 Route53 alias record 配置例子:
route53_records = {
api = {
zone_id = "Z0123456789ABCDEFG"
name = "api-uat.jxcq.work"
type = "A"
}
}对应 import:
terraform import \
'module.default.aws_route53_record.this["api"]' \
'Z0123456789ABCDEFG_api-uat.jxcq.work_A'WAF association#
这是完整 sample 的 WAF association 配置例子:
associate_web_acl = true
web_acl_arn = "arn:aws:wafv2:ap-northeast-1:123456789012:regional/webacl/ping-uat/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"对应 import:
terraform import \
'module.default.aws_wafv2_web_acl_association.this[0]' \
'arn:aws:wafv2:ap-northeast-1:123456789012:regional/webacl/ping-uat/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee,arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/ping-uat-alb/d12dac00d9c29937'Lambda permission#
当 target group 是 Lambda target 时,module 会为 Lambda 创建允许 ALB 调用的 permission。
这是完整 sample 的 Lambda target group 配置例子:
target_groups = {
image-resizer-lambda = {
target_type = "lambda"
target_id = "arn:aws:lambda:ap-northeast-1:123456789012:function:image-resizer"
}
}对应 import:
terraform import \
'module.default.aws_lambda_permission.this["image-resizer-lambda"]' \
'image-resizer/AllowExecutionFromLb'如果 Lambda permission 的 statement ID 不是 module 默认值 AllowExecutionFromLb,import ID 要换成真实 statement ID:
terraform import \
'module.default.aws_lambda_permission.this["image-resizer-lambda"]' \
'image-resizer/AllowExecutionFromAlbImageResizer'13. Verify#
导入后先看 state 地址是否完整:
terraform state list | sort重点检查:
module.default.aws_lb.this[0]
module.default.aws_security_group.this[0]
module.default.aws_vpc_security_group_ingress_rule.this["http"]
module.default.aws_vpc_security_group_ingress_rule.this["https"]
module.default.aws_vpc_security_group_egress_rule.this["all"]
module.default.aws_lb_listener.this["http_redirect"]
module.default.aws_lb_listener.this["https"]
module.default.aws_lb_target_group.this["victorialogs-vmauth"]
module.default.aws_lb_target_group.this["ping-uat-ninedata-tg"]
module.default.aws_lb_listener_rule.this["https/logs-uat"]
module.default.aws_lb_listener_rule.this["https/api-uat"]然后跑 plan:
terraform planPlan review 规则:
expected:
no replacement
no unexpected destroy
small tag or description drift can be fixed in code or accepted intentionally
dangerous:
ALB replacement
listener replacement
target group replacement
deleting existing listener rules
Terraform trying to register ECS task IP targets that should be ECS-owned如果 plan 显示 Terraform 要创建 target group attachment,但该 target group 实际由 ECS 动态注册 task IP,先在对应 target group 配置里加:
create_attachment = false再重新执行:
terraform plan14. Terraform Input Example#
下面是一个用于匹配 import address 的 terraform.tf 输入示例:
alb_security_group_egress_rules = {
all = {
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
default_alb = {
security_group_ingress_rules = {
http = {
from_port = 80
to_port = 80
ip_protocol = "tcp"
description = "HTTP from anywhere"
cidr_ipv4 = "0.0.0.0/0"
}
https = {
from_port = 443
to_port = 443
ip_protocol = "tcp"
description = "HTTPS from anywhere"
cidr_ipv4 = "0.0.0.0/0"
}
}
listeners = {
http_redirect = {
port = 80
protocol = "HTTP"
redirect = {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
https = {
port = 443
protocol = "HTTPS"
certificate_arn = "arn:aws:acm:ap-northeast-1:123456789012:certificate/4e07d72a-bf9f-4fe3-8dd6-99ed2d070e5b"
additional_certificate_arns = ["arn:aws:acm:ap-northeast-1:123456789012:certificate/6df41b9c-8062-4290-9d0c-9383de65fee5"]
forward = {
target_group_key = "ping-uat-alb-im-srv"
}
rules = {
logs-uat = {
priority = 5
actions = [
{
forward = {
target_group_key = "victorialogs-vmauth"
}
}
]
conditions = [
{
host_header = {
values = ["logs-uat.x.com"]
}
}
]
}
api-uat = {
priority = 90
actions = [
{
forward = {
target_group_key = "ping-uat-vector-firehose"
}
}
]
conditions = [
{
host_header = {
values = ["api-uat.x.com"]
}
},
{
path_pattern = {
values = ["/__vector*"]
}
}
]
}
}
}
}
target_groups = {
victorialogs-vmauth = {
protocol = "HTTP"
port = 8427
target_type = "Instance"
target_id = "i-00da965592ca402e0"
health_check = {
enabled = true
path = "/health"
matcher = "200"
}
}
ping-uat-ninedata-tg = {
protocol = "HTTP"
port = 9999
target_type = "Instance"
target_id = "i-02ac8a7a6f3fc85b7"
health_check = {
enabled = true
path = "/"
matcher = "200"
}
}
}
}