Terraform多循环实现CNAME关联多A记录的配置报错解决方案
问题原因
- Terraform语法错误:
records = [values(aws_route53_record.instance_record)[*].name]这行额外套了一层方括号,最终传入参数的是双层嵌套列表[["webserver1.domain.com", "webserver2.domain.com"]],而records参数要求一维字符串列表,第一个元素是列表而非字符串,直接触发类型不匹配。 - DNS协议规则限制:哪怕你修正语法去掉外层方括号,配置也无法正常创建。标准DNS规范(RFC 1034)明确要求单条CNAME记录仅允许配置1个目标域名,不支持同时关联多个值,你预期的单条CNAME绑定2个A记录的效果本身不符合协议规则,Route53会直接拒绝创建这类记录。
- 隐藏逻辑错误:你现有配置里的
instance_record资源也有问题:你用for_each遍历hostname为每个webserver创建单独A记录,但records参数直接传入了所有EC2的IP列表,最终会导致webserver1、webserver2两个A记录都同时绑定2个IP,和你预期的单域名绑定单实例IP的效果不符。
可行实现方案
如果你的核心需求是3个www子域名均可解析到2台EC2实例地址,实现多节点轮询访问,推荐用以下符合规范的方案:
方案1:直接创建多值A记录(最优方案)
不需要额外创建webserver层的A记录再做跳转,直接给www子域名配置多值A记录,少一层CNAME解析,解析性能更好:
# 如果你不需要单独访问webserver1、webserver2这两个域名,可以删掉这段instance_record资源 resource "aws_route53_record" "instance_record" { for_each = toset(var.hostnames) zone_id = data.aws_route53_zone.route53_zone.zone_id name = "${each.value}.${var.domain}" type = "A" ttl = "300" # 按hostname索引取对应实例IP,避免列表顺序错乱;更推荐将EC2模块输出改为map类型做键值匹配,稳定性更高 records = [module.ec2_instance.server_ip_addresses[index(var.hostnames, each.value)]] } resource "aws_route53_record" "webservice_records" { for_each = toset(var.subdomain_addresses) zone_id = data.aws_route53_zone.route53_zone.zone_id name = "${each.value}.${var.domain}" type = "A" ttl = "300" # 二选一即可:不需要保留webserverA记录就直接用EC2输出,保留的话就引用instance_record的IP # records = values(aws_route53_record.instance_record)[*].records[0] records = module.ec2_instance.server_ip_addresses }
这个配置最终生成的解析效果和你预期的访问效果完全一致:访问任意www子域名时,DNS会轮询返回两台EC2的IP地址。
方案2:必须使用CNAME的场景处理
如果你因为业务规则必须使用CNAME类型记录,单条CNAME只能指向一个目标域名,你需要配合负载均衡(比如ALB)实现:先创建一个ALB挂载两台EC2实例,给ALB配置单独的访问域名,再将三个www子域名的CNAME指向ALB的域名即可,无法通过单条CNAME直接指向多个A记录实现需求。
内容的提问来源于stack exchange,提问作者Lloyd
相关产品推荐
相关产品推荐

