Terraform Route53别名记录因S3网站域名未就绪执行失败问题
问题:Terraform配置S3静态站点+Route53需两次
terraform apply才能成功 场景概述
我需要完成以下操作:
- 创建S3存储桶
- 向存储桶上传静态站点文件
- 将存储桶配置为静态网站
- 配置Route53将子域名转发至该存储桶网站,替代S3默认的冗长域名
目前Terraform文件已编写完成,站点最终可正常访问,但必须执行两次terraform apply:
- 首次执行会创建存储桶、上传站点文件并完成静态网站的相关配置,但Route53记录资源会报错
- 第二次执行才能成功创建Route53记录
首次执行报错信息
Error: Missing required argument │ │ with module.ui_site.aws_route53_record.www-a, │ on modules\UI\route53.tf line 14, in resource "aws_route53_record" "www-a": │ 14: name = aws_s3_bucket.site.website_domain │ │ The argument "alias.0.name" is required, but no definition was found.
对应的Terraform代码
resource "aws_s3_bucket" "site" { bucket = "${var.ui_bucket_name}.${var.root_domain}" } resource "aws_s3_bucket_public_access_block" "site" { bucket = aws_s3_bucket.site.id block_public_acls = false block_public_policy = false ignore_public_acls = false restrict_public_buckets = false } resource "aws_s3_bucket_website_configuration" "site" { bucket = aws_s3_bucket.site.id index_document { suffix = "index.html" } error_document { key = "index.html" } } resource "aws_s3_bucket_ownership_controls" "site" { bucket = aws_s3_bucket.site.id rule { object_ownership = "BucketOwnerPreferred" } } resource "aws_s3_bucket_acl" "site" { bucket = aws_s3_bucket.site.id acl = "public-read" depends_on = [ aws_s3_bucket_ownership_controls.site, aws_s3_bucket_public_access_block.site ] } resource "aws_s3_bucket_policy" "site" { bucket = aws_s3_bucket.site.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Sid = "PublicReadGetObject" Effect = "Allow" Principal = "*" Action = "s3:GetObject" Resource = [ aws_s3_bucket.site.arn, "${aws_s3_bucket.site.arn}/*", ] }, ] }) depends_on = [ aws_s3_bucket_public_access_block.site ] } module "template_files" { source = "hashicorp/dir/template" base_dir = "${path.module}/../../../client_ui/build" } resource "aws_s3_object" "site" { bucket = aws_s3_bucket.site.bucket for_each = module.template_files.files key = each.key content_type = each.value.content_type # The template_files module guarantees that only one of these two attributes # will be set for each file, depending on whether it is an in-memory template # rendering result or a static file on disk. source = each.value.source_path content = each.value.content # Unless the bucket has encryption enabled, the ETag of each object is an # MD5 hash of that object. etag = each.value.digests.md5 } ####################################################### ## Route53 data "aws_route53_zone" "zone" { name = var.root_domain private_zone = false } resource "aws_route53_record" "www-a" { zone_id = data.aws_route53_zone.zone.zone_id name = aws_s3_bucket.site.bucket type = "A" alias { name = aws_s3_bucket.site.website_domain zone_id = aws_s3_bucket.site.hosted_zone_id evaluate_target_health = true } depends_on = [ aws_s3_bucket_website_configuration.site ] }
已尝试的解决方法
在Route53记录的depends_on部分添加不同的资源(存储桶资源、存储桶网站配置资源),但问题仍未解决。
解决方案
问题根源在于:aws_s3_bucket.site.website_domain和aws_s3_bucket.site.hosted_zone_id这两个属性只有在存储桶的静态网站配置生效后才会被Terraform正确获取,但仅通过depends_on = [aws_s3_bucket_website_configuration.site]无法让Terraform明确感知到这两个属性的依赖关系。
修改Route53资源的配置,将alias块中的属性替换为从aws_s3_bucket_website_configuration资源导出的值,而不是直接从aws_s3_bucket资源获取:
resource "aws_route53_record" "www-a" { zone_id = data.aws_route53_zone.zone.zone_id name = aws_s3_bucket.site.bucket type = "A" alias { name = aws_s3_bucket_website_configuration.site.website_domain zone_id = aws_s3_bucket_website_configuration.site.hosted_zone_id evaluate_target_health = true } }
为什么这样修改有效?
aws_s3_bucket_website_configuration.site.website_domain和aws_s3_bucket_website_configuration.site.hosted_zone_id是明确依赖于静态网站配置资源的属性,Terraform会自动等待aws_s3_bucket_website_configuration.site创建完成后再计算这些值,不需要额外的depends_on声明。- 原配置中直接使用
aws_s3_bucket.site.website_domain,Terraform在首次计划时无法确定该值是否存在,因为存储桶本身创建完成后,静态网站配置可能还未生效,导致属性值为空,触发"缺少必填参数"的错误。
修改后,只需要执行一次terraform apply即可完成所有资源的创建。
内容的提问来源于stack exchange,提问作者ahmad alzamer
相关产品推荐
相关产品推荐

