【问题标题】:Terraform attempts to create the S3 backend again when switching to a new workspace切换到新工作区时,Terraform 尝试再次创建 S3 后端
【发布时间】:2020-04-04 07:02:38
【问题描述】:

我正在关注this terraform 的优秀指南。我目前正在探索该州的第三篇文章。特别是在 point 演示 terraform 工作空间的地方。 所以,我有以下main.tf

provider "aws" {
  region = "us-east-2"
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "mark-kharitonov-terraform-up-and-running-state"

  # Enable versioning so we can see the full revision history of our
  # state files
  versioning {
    enabled = true
  }

  # Enable server-side encryption by default
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "AES256"
      }
    }
  }
}

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-up-and-running-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

terraform {
  backend "s3" {
    # Replace this with your bucket name!
    bucket = "mark-kharitonov-terraform-up-and-running-state"
    key    = "workspaces-example/terraform.tfstate"
    region = "us-east-2"
    # Replace this with your DynamoDB table name!
    dynamodb_table = "terraform-up-and-running-locks"
    encrypt        = true
  }
}

output "s3_bucket_arn" {
  value       = aws_s3_bucket.terraform_state.arn
  description = "The ARN of the S3 bucket"
}

output "dynamodb_table_name" {
  value       = aws_dynamodb_table.terraform_locks.name
  description = "The name of the DynamoDB table"
}

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

一切都很棒:

C:\work\terraform [master ≡]> terraform workspace show
default
C:\work\terraform [master ≡]> terraform apply
Acquiring state lock. This may take a few moments...
aws_dynamodb_table.terraform_locks: Refreshing state... [id=terraform-up-and-running-locks]
aws_instance.example: Refreshing state... [id=i-01120238707b3ba8e]
aws_s3_bucket.terraform_state: Refreshing state... [id=mark-kharitonov-terraform-up-and-running-state]

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Releasing state lock. This may take a few moments...

Outputs:

dynamodb_table_name = terraform-up-and-running-locks
s3_bucket_arn = arn:aws:s3:::mark-kharitonov-terraform-up-and-running-state
C:\work\terraform [master ≡]>

现在我正在尝试遵循指南 - 创建一个新工作区并在那里应用代码:

C:\work\terraform [master ≡]> terraform workspace new example1
Created and switched to workspace "example1"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
C:\work\terraform [master ≡]> terraform plan
Acquiring state lock. This may take a few moments...
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_dynamodb_table.terraform_locks will be created
  + resource "aws_dynamodb_table" "terraform_locks" {
...
      + name             = "terraform-up-and-running-locks"
...
    }

  # aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                          = "ami-0c55b159cbfafe1f0"
...
    }

  # aws_s3_bucket.terraform_state will be created
  + resource "aws_s3_bucket" "terraform_state" {
...
      + bucket                      = "mark-kharitonov-terraform-up-and-running-state"
...
    }

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

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Releasing state lock. This may take a few moments...
C:\work\terraform [master ≡]>

问题从这里开始。在指南中,terraform plan 命令报告只会创建一个资源 - EC2 实例。这意味着 terraform 将为后端重用相同的 S3 存储桶,并为锁重用相同的 DynamoDB 表。但就我而言,terraform 通知我它想要创建所有 3 种资源,包括 S3 存储桶。这肯定会失败(已经尝试过)。

那么,我做错了什么?缺少什么?

【问题讨论】:

    标签: terraform


    【解决方案1】:

    创建一个新的workspace 实际上是从头开始。在这方面,指南步骤有点令人困惑,但他们正在制定两个计划来实现最终结果。第一个创建状态 S3 Bucket 和锁定 DynamoDB 表,第二个计划仅包含他们正在创建的实例,但使用 terraform 代码块告诉该计划将其状态存储在哪里。

    在您的示例中,您既要设置州位置,又要在同一个计划中创建它。这意味着当您创建一个新工作区时,它会再次尝试创建该状态位置,因为该工作区不知道其他工作区的状态。

    最后,重要的是要知道使用工作空间会通过appending the workspace name to the remote state path 为每个工作空间创建唯一的状态文件。例如,如果您的州位置是 mark-kharitonov-terraform-up-and-running-state,路径为 workspaces-example,那么您可能会看到以下内容:

    • 默认状态:mark-kharitonov-terraform-up-and-running-state/workspaces-example/default/terraform.tfstate
    • 其他状态:mark-kharitonov-terraform-up-and-running-state/workspaces-example/other/terraform.tfstate

    编辑:

    要明确如何获得指南结果。您需要在单独的文件夹中创建两个单独的计划(工作目录中的所有计划将同时运行)。所以创建一个像这样的层次结构:

    • 计划>
      • 状态 >
        • main.tf
      • 实例>
        • main.tf

    在您的 plans/state/main.tf 文件中放置您的状态位置内容:

    provider "aws" {
      region = "us-east-2"
    }
    
    resource "aws_s3_bucket" "terraform_state" {
      bucket = "mark-kharitonov-terraform-up-and-running-state"
    
      # Enable versioning so we can see the full revision history of our
      # state files
      versioning {
        enabled = true
      }
    
      # Enable server-side encryption by default
      server_side_encryption_configuration {
        rule {
          apply_server_side_encryption_by_default {
            sse_algorithm = "AES256"
          }
        }
      }
    }
    
    resource "aws_dynamodb_table" "terraform_locks" {
      name         = "terraform-up-and-running-locks"
      billing_mode = "PAY_PER_REQUEST"
      hash_key     = "LockID"
    
      attribute {
        name = "LockID"
        type = "S"
      }
    }
    
    output "s3_bucket_arn" {
      value       = aws_s3_bucket.terraform_state.arn
      description = "The ARN of the S3 bucket"
    }
    

    然后在您的plans/instance/main.tf 文件中,您可以使用terraform 块引用创建的状态位置,并且只需要以下内容:

    terraform {
      backend "s3" {
        # Replace this with your bucket name!
        bucket = "mark-kharitonov-terraform-up-and-running-state"
        key    = "workspaces-example/terraform.tfstate"
        region = "us-east-2"
        # Replace this with your DynamoDB table name!
        dynamodb_table = "terraform-up-and-running-locks"
        encrypt        = true
      }
    }
    
    resource "aws_instance" "example" {
      ami           = "ami-0c55b159cbfafe1f0"
      instance_type = "t2.micro"
    }
    

    【讨论】:

    • 该指南解释说创建了一个唯一的状态文件 - terraform 会自动更改路径以包含工作空间名称。这部分很清楚。尚不清楚如何使指南与发生的事情相协调。我必须做些什么才能让它发挥作用?这是否意味着我需要将 main.tf 拆分为两个文件?如何使第二个文件重用相同的 S3 存储桶。很抱歉,但在阅读您的回答后,我的解决方案远不及以前。
    • 是的,您需要拆分计划文件。因此,为什么我说“在这方面,指导步骤有点混乱,但他们正在制定两个计划来实现最终结果。”在我的开幕词中。我编辑了我的答案以提供一个例子。请务必注意,当您拆分它们时,它们不能位于同一工作目录中,因为 terraform applyplan 将读取所有 .tf 文件。
    • 它有效 - 谢谢。一个问题是如果我想要彻底清理,如何销毁后端状态文件。它们是用terraform apply 创建的,但不会用terraform destroy 删除。什么是正确的做法?还是我应该将其作为关于 SO 的单独问题提出?
    • 好问题。它们不会特别伤害任何东西,我认为没有任何自动删除机制。也许是另一个问题。
    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 2021-12-26
    • 2018-05-29
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 2021-06-28
    • 2022-10-25
    相关资源
    最近更新 更多