【问题标题】:Terraform flappy stateTerraform 飘动状态
【发布时间】:2022-11-04 21:38:18
【问题描述】:

我创建了一个 Terraform 项目,以创建 s3 存储桶、跨区域复制、版本控制和用于删除旧版本的生命周期规则。

问题是,每当我运行 terraform 时,它都想删除跨区域复制和 livecycle 规则,如果它存在于 AWS 中,并且每当它不再存在时,它就想读取它。这发生在没有任何代码更改的情况下。 状态好像不准确。

我已经在 AWS 中从头开始删除了所有内容并从头开始,但这并没有帮助。我总是遇到飘忽不定的情况。

所有细节:

$ terraform init && terraform plan -var-file xyz.tfvars

...

Terraform will perform the following actions:

   # module.test_s3_bucket["bnpl-docs"].aws_s3_bucket.s3_bucket  will be updated in-place  
    ~   resource "aws_s3_bucket" "s3_bucket" {
          id                            = "bnpl-docs" 
          tags                          = {}        
         # (11 unchanged attributes hidden)  

       -   replication_configuration {
           -     role   = "arn:aws:iam::....:role/bnpl-docs-s3-bucket-replication"  ->    null    

           -   rules {
               -     id         = "version-replication"  ->    null    
               -     priority   = 0  ->    null    
               -     status     = "Enabled"  ->    null    

               -   destination {
                   -     bucket          = "arn:aws:s3:::bnpl-docs-crr"  ->    null    
                   -     storage_class   = "STANDARD"  ->    null    
                }
            }
        }

         # (1 unchanged block hidden)  
    }

   # module.test_s3_bucket["bnpl-docs"].aws_s3_bucket_lifecycle_configuration.s3_bucket[0]  will be created  
    +   resource "aws_s3_bucket_lifecycle_configuration" "s3_bucket" {
       +     bucket   = "bnpl-docs"
       +     id       = (known after apply)

       +   rule {
           +     id       = "version-retention"
           +     status   = "Enabled"

           +   expiration {
               +     days                           = 0 
               +     expired_object_delete_marker   = true
            }

           +   noncurrent_version_expiration {
               +     noncurrent_days   = 30
            }
        }
    }

  Plan:  1 to add, 1 to change, 0 to destroy. 

但结果是两个都运行应用后在 AWS 中丢失。

当我重新运行时,我得到相同的输出:

Terraform will perform the following actions:

   # module.test_s3_bucket["bnpl-docs"].aws_s3_bucket.s3_bucket  will be updated in-place  
    ~   resource "aws_s3_bucket" "s3_bucket" {
          id                            = "bnpl-docs" 
          tags                          = {}        
         # (11 unchanged attributes hidden)  

       -   replication_configuration {
           -     role   = "arn:aws:iam::......:role/bnpl-docs-s3-bucket-replication"  ->    null  

           -   rules {
               -     id         = "version-replication"  ->    null  
               -     priority   = 0  ->    null   
               -     status     = "Enabled"  ->    null  

               -   destination {
                   -     bucket          = "arn:aws:s3:::bnpl-docs-crr"  ->    null  
                   -     storage_class   = "STANDARD"  ->    null  
                }
            }
        }

         # (1 unchanged block hidden)  
    }

   # module.test_s3_bucket["bnpl-docs"].aws_s3_bucket_lifecycle_configuration.s3_bucket[0]  will be created  
    +   resource "aws_s3_bucket_lifecycle_configuration" "s3_bucket" {
       +     bucket   = "bnpl-docs" 
       +     id       = (known after apply)

       +   rule {
           +     id       = "version-retention"
           +     status   = "Enabled"

           +   expiration {
               +     days                           = 0               
               +     expired_object_delete_marker   = true
            }

           +   noncurrent_version_expiration {
               +     noncurrent_days   = 30
            }
        }
    }

  Plan:  1 to add, 1 to change, 0 to destroy. 

但结果是两个都运行 apply 后在 AWS 中创建。

我创建了几个模块来实现我想要的。涉及代码:

module "test_s3_bucket" {
  source = "./modules/test-s3-bucket"

  for_each = local.aws_s3_bucket_map

  bucket_name = each.key
  versioning  = each.value.version_config
}

module "test_s3_bucket_repli" {
  source = "./modules/test-s3-bucket"

  providers = {
    aws = aws.repli
  }

  for_each = local.aws_s3_bucket_map_repli

  bucket_name = each.key
  versioning  = each.value.version_config
}

module "test_s3_bucket_repli_config" {
  source = "./modules/test-s3-bucket-replication"

  for_each = local.aws_s3_bucket_map_repli

  src_bucket = {
    name = module.test_s3_bucket[each.value.src_bucket_name].name
    arn  = module.test_s3_bucket[each.value.src_bucket_name].arn
  }
  dest_bucket = {
    name = module.test_s3_bucket_repli[each.key].name
    arn  = module.test_s3_bucket_repli[each.key].arn
  }
}

test_s3_bucket-Module 的内容:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

##
# Bucket with configuration
##

resource "aws_s3_bucket" "s3_bucket" {
  bucket = var.bucket_name
}

resource "aws_s3_bucket_acl" "s3_bucket" {
  bucket = aws_s3_bucket.s3_bucket.id

  acl = "private"
}

resource "aws_s3_bucket_versioning" "s3_bucket" {
  bucket = aws_s3_bucket.s3_bucket.id

  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "s3_bucket" {
  count = var.versioning == null ? 0 : 1

  bucket = aws_s3_bucket.s3_bucket.id
  rule {
    id = var.versioning.rule_id

    expiration {
      expired_object_delete_marker = true
    }

    noncurrent_version_expiration {
      noncurrent_days = var.versioning.expiration_days
    }
    status = "Enabled"
  }
}

resource "aws_s3_bucket_public_access_block" "s3_bucket" {
  bucket                  = aws_s3_bucket.s3_bucket.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

test-s3-bucket-replication 模块的内容:

erraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

resource "aws_s3_bucket_replication_configuration" "bucket_main" {
  bucket = var.src_bucket.name
  role   = aws_iam_role.s3_bucket_main_replication.arn

  rule {
    id     = "version-replication"
    status = "Enabled"

    destination {
      bucket        = var.dest_bucket.arn
      storage_class = "STANDARD"
    }
  }
}

resource "aws_iam_role" "s3_bucket_main_replication" {
  name               = "${var.src_bucket.name}-s3-bucket-replication"
  assume_role_policy = file("${path.module}/files/policies/sts-s3-assume.json")
}

resource "aws_iam_policy" "s3_bucket_main_replication" {
  name = "${var.src_bucket.name}-s3-bucket-replication"
  policy = templatefile("${path.module}/files/policies/s3-bucket-replication.json", {
    source_bucket_arn      = var.src_bucket.arn,
    destination_bucket_arn = var.dest_bucket.arn,
  })
}

resource "aws_iam_role_policy_attachment" "s3_bucket_main_replication" {
  role       = aws_iam_role.s3_bucket_main_replication.name
  policy_arn = aws_iam_policy.s3_bucket_main_replication.arn
}

您会看到似乎有冲突的两个配置部分分布在两个模块上。我不确定这是否有问题。我对 terraform 有点陌生 :)

【问题讨论】:

  • 似乎该模块错误地在嵌套块和专用资源中双重定义了生命周期规则。这会在与 AWS API 交互时导致问题,如果模块确实包含该配置,这很可能是根本原因。

标签: amazon-s3 terraform


【解决方案1】:

通过 TF_LOG="DEBUG" 增加 Loglevel 后,我发现这两个资源与存储桶配置冲突 - aws_s3_bucket-configuration 不包括任何生命周期或复制配置(如文档所建议的那样),但 terraform 期望这个遗留以某种方式声明。 我使用的是 AWS Provider 3.75 并升级到 4.X。此次升级后,一切正常。

【讨论】:

    猜你喜欢
    • 2021-08-22
    • 2021-01-19
    • 2023-03-22
    • 1970-01-01
    • 2021-07-02
    • 2021-05-14
    • 2016-11-24
    • 2021-12-11
    • 2020-11-29
    相关资源
    最近更新 更多