无法使用 localstack dynamoDB 锁定 terraform 状态:UnrecognizedClientException

Posted

技术标签:

【中文标题】无法使用 localstack dynamoDB 锁定 terraform 状态:UnrecognizedClientException【英文标题】:Can't use localstack dynamoDB to lock terraform state: UnrecognizedClientException 【发布时间】:2021-04-28 14:13:47 【问题描述】:

我一直在尝试创建一个本地开发环境,以便在 docker 上运行带有 localstack (https://github.com/localstack/localstack) 的 terraform。

我已经能够创建一个 S3 存储桶来存储 terraform 状态,但我还想将 DynamoDB 模拟为锁。

配置是:

localstack docker-compose.yml:

version: "3.2"
services:
  localstack:
    image: localstack/localstack:latest
    container_name: localstack
    ports:
      - "4563-4599:4563-4599"
      - "8080:8080"
    environment:
      - DATA_DIR=/tmp/localstack/data
      - DEBUG=1
    volumes:
      - "./.localstack:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

第一个地形:

用作初始引导程序,为 tfstate 锁创建 s3 tfstate 存储和 DynamoDB 表。

provider "aws" 
  region                      = "us-east-1"
  access_key                  = "foo"
  secret_key                  = "bar"
  skip_credentials_validation = true
  skip_requesting_account_id  = true
  skip_metadata_api_check     = true
  s3_force_path_style         = true
  endpoints 
    apigateway     = "http://localhost:4566"
    cloudformation = "http://localhost:4566"
    cloudwatch     = "http://localhost:4566"
    dynamodb       = "http://localhost:4566"
    es             = "http://localhost:4566"
    firehose       = "http://localhost:4566"
    iam            = "http://localhost:4566"
    kinesis        = "http://localhost:4566"
    lambda         = "http://localhost:4566"
    route53        = "http://localhost:4566"
    redshift       = "http://localhost:4566"
    s3             = "http://localhost:4566"
    secretsmanager = "http://localhost:4566"
    ses            = "http://localhost:4566"
    sns            = "http://localhost:4566"
    sqs            = "http://localhost:4566"
    ssm            = "http://localhost:4566"
    stepfunctions  = "http://localhost:4566"
    sts            = "http://localhost:4566"
  


resource "aws_s3_bucket" "terraform_state" 
  bucket = "terraform-state"
  acl    = "private"

  versioning 
    enabled = true
  

  server_side_encryption_configuration 
    rule 
      apply_server_side_encryption_by_default 
        sse_algorithm = "AES256"
      
    
  

  lifecycle 
    prevent_destroy = true
  


resource "aws_s3_bucket_public_access_block" "terraform_state_access" 
  bucket = aws_s3_bucket.terraform_state.id

  block_public_acls       = true
  ignore_public_acls      = true
  block_public_policy     = true
  restrict_public_buckets = true


resource "aws_dynamodb_table" "terraform_state_lock" 
  name           = "terraformlock"
  read_capacity  = 5
  write_capacity = 5
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "LockID"

  attribute 
    name = "LockID"
    type = "S"
  

第二个地形:

创建资源并将状态存储在 s3 中并使用 DynamoDB 创建锁。

terraform 
  backend "s3" 
    bucket                      = "terraform-state"
    key                         = "main/terraform.tfstate"
    region                      = "us-east-1"
    endpoint                    = "http://localhost:4566"
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    force_path_style            = true
    dynamodb_table              = "terraformlock"
    encrypt                     = true
  


provider "aws" 
  region                      = "us-east-1"
  access_key                  = "foo"
  secret_key                  = "bar"
  skip_credentials_validation = true
  skip_requesting_account_id  = true
  skip_metadata_api_check     = true
  s3_force_path_style         = true
  endpoints 
    apigateway     = "http://localhost:4566"
    cloudformation = "http://localhost:4566"
    cloudwatch     = "http://localhost:4566"
    dynamodb       = "http://localhost:4566"
    es             = "http://localhost:4566"
    ec2            = "http://localhost:4566"
    firehose       = "http://localhost:4566"
    iam            = "http://localhost:4566"
    kinesis        = "http://localhost:4566"
    lambda         = "http://localhost:4566"
    route53        = "http://localhost:4566"
    redshift       = "http://localhost:4566"
    s3             = "http://localhost:4566"
    secretsmanager = "http://localhost:4566"
    ses            = "http://localhost:4566"
    sns            = "http://localhost:4566"
    sqs            = "http://localhost:4566"
    ssm            = "http://localhost:4566"
    stepfunctions  = "http://localhost:4566"
    sts            = "http://localhost:4566"
  


resource "aws_sqs_queue" "test" 
  name = "test"
  tags = 
    "Environment" = "dev"
  


resource "aws_sns_topic" "test" 
  name         = "test"
  display_name = "test"


每当我应用第二个 terraform 时,我都会收到此错误:

❯ terraform apply
Acquiring state lock. This may take a few moments...

Error: Error locking state: Error acquiring the state lock: 2 errors occurred:
        * UnrecognizedClientException: The security token included in the request is invalid.
        status code: 400, request id: UEGJV0SQ614NIEDRB93IAF0JQ7VV4KQNSO5AEMVJF66Q9ASUAAJG
        * UnrecognizedClientException: The security token included in the request is invalid.
        status code: 400, request id: U1IRF6CHGK7RM4SQEGVCSU699RVV4KQNSO5AEMVJF66Q9ASUAAJG



Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.

有没有人试过这个或者知道是什么原因造成的?

【问题讨论】:

【参考方案1】:

这可能是因为您尝试使用real DynamoDB,而不是来自localstack。要使用 localstack,您必须添加

dynamodb_endpoint           = "http://localhost:4566"

到您的backend.S3 配置。更新 backend 设置后,您必须使用 terraform init 重新初始化 TF。

【讨论】:

太棒了!那成功了!我认为后端的端点足以使用我的本地 dynamodb。 Turns 我刚刚了解到,使用 terraform,如果我们愿意,我们甚至可以 tfstate 锁定另一个 AWS 账户……非常感谢!

以上是关于无法使用 localstack dynamoDB 锁定 terraform 状态:UnrecognizedClientException的主要内容,如果未能解决你的问题,请参考以下文章

由 Terraform 在 LocalStack 中创建的 DynamoDB 表在 NoSQL Workbench 中不可见

sh localstack_dynamodbテスト.sh

无法使用测试容器的 localstack 模块连接到 Aws SQS

localstack 1.0 ga 了

无法使用 YCSB 对 DynamoDb 进行基准测试

无法使用 CloudFormation 将 GSI 添加到 DynamoDB 表