刷新状态时出错:S3 中的状态数据没有预期的内容

Posted

技术标签:

【中文标题】刷新状态时出错:S3 中的状态数据没有预期的内容【英文标题】:Error refreshing state: state data in S3 does not have the expected content 【发布时间】:2020-01-18 22:27:29 【问题描述】:

当我们尝试运行带有远程状态处理的 terraform 脚本时,我们会遇到以下问题:

。 这可能是由 S3 处理先前状态的异常长时间延迟引起的 更新。请等待一两分钟,然后重试。如果这个问题 持续存在,并且 S3 和 DynamoDB 都没有遇到中断,您可能需要 手动验证远程状态并更新存储在 DynamoDB 表为以下值

【问题讨论】:

【参考方案1】:

根据您的具体情况,有 3 种可能的解决方法来解决它:

案例一

如果您有 AWS S3 terrform.tfstate 文件的备份,您可以将状态后端 "s3" key = "path/to/terraform.tfstate" 恢复到旧版本。重新尝试terraform init 并验证它是否正常工作。


案例2

删除 AWS DynamoDB 表中的不同步条目。表中将有一个 LockID 条目,其中包含您应该删除的状态和预期校验和,并且将在重新运行 terraform init 后重新生成。

重要注意事项:

在此过程中,您将失去锁定状态保护,这会阻止其他人获得锁定,并且可能有 2 个人同时更新相同的资源,从而破坏您的状态。 请考虑使用terraform refresh 命令 (https://www.terraform.io/docs/commands/refresh.html),该命令用于协调 Terraform 知道的状态(通过其状态文件)与现实世界的基础设施。这可用于检测与上次已知状态的任何偏差,并更新状态文件。 删除 DynamoDB LockID 表条目 -> 屏幕截图:


案例3

如果在 terraform destroy 之后您手动删除了 AWS S3 terraform.tfstate 文件,然后可能尝试启动所有 tf​​state 声明资源的新实例,这意味着您正在从头开始工作,您可以更新您的AWS S3 terrform.tfstate 状态后端密钥 "s3" key = "path/to/terraform.tfstate" 到一个新的 "s3" key = "new-path/to/terraform.tfstate"。重试terraform init 并验证这应该可以正常工作。这种解决方法的局限性在于您并没有真正解决根本原因,您只是使用 S3 tfstate 的新密钥绕过问题。

【讨论】:

【参考方案2】:

今天遇到了同样的问题,但尽管Exequiel Barrierero 提出了很好的建议,但没有明显的错误——直到我发现它。

在我们的例子中,我们有一个较旧的 Terragrunt 堆栈(v0.23.30 / terraform v0.12.31),CloudWatch 的一个组件模块抛出了同样的错误:

错误:S3 中的状态数据没有预期的内容。

这可能是由于 S3 处理 之前的状态更新。请等待一两分钟,然后重试。 如果此问题仍然存在,并且 S3 和 DynamoDB 都没有遇到 中断,您可能需要手动验证远程状态并更新 将存储在 DynamoDB 表中的 Digest 值转换为以下值:

...没有提供实际的摘要值。但是,我最近重构了一些组件模块文件以降低堆栈的复杂性,并发现了一个悬空的 data.terraform_remote_state 用于一个不再存在的元素——我已经合并了模块并且不再有一个该特定数据元素的远程状态。

一旦我删除了无效的 data.terraform_remote_state 引用,planapply 都完成了,没有任何故障或错误。

【讨论】:

【参考方案3】:

这发生在我尝试从新机器执行“terraform init”时。

所以我删除了 DynamoDB 锁并尝试了该线程中的大部分内容,但没有成功。 删除锁的重要一点是,我在那里看到了多条记录,并记得 我们也在使用 terraform 工作区。所以当我在新机器上创建并切换到正确的工作区时,问题就解决了。

我想背后的原因是我的 terraform 文件的资源与运行 init 命令时默认工作区的 S3 上的状态不同。于是我切换到了新资源:

terraform workspace new 'dev'
(or)
terraform workspace select 'dev'

(and then)
terraform init

然后一切又顺利进行了。

【讨论】:

【参考方案4】:

问题在于 terraform 状态文件。当您使用 s3 作为后端进行远程状态处理时,我们会收到此错误,因为 s3 文件位置和 dynamodb 记录不匹配 试试下面的步骤。

1) 删除该特定状态条目的 dyanmodb 记录。 2)删除s3位置的状态文件。 3) 现在从头开始初始化和应用 terraform。

这将在 dynamodb 中创建一个新的状态信息条目,并将新的状态文件添加到 s3 中,问题将得到解决。

编码愉快...

【讨论】:

这是一个非常糟糕的主意。删除锁定记录而不查看其错误原因意味着您将失去锁定记录提供的安全检查,因为它认为状态文件应该与它的状态文件不同,因此可能由于最终一致性而在某处不匹配,但可能更糟糕的事情。也不需要删除状态文件。如果您认为状态文件很好并且锁是错误的,那么只需删除锁就可以了。删除状态文件意味着您可能会复制一堆资源或在尝试复制唯一资源时导致错误。 这是在开发和测试的时候,不需要一直这样做。 删除 DynamoDB 上的锁定和重命名(删除)S3 上的状态文件对于我们遇到的特定情况起到了作用。【参考方案5】:

您也可以尝试从 dynamodb 中删除 -md5 项

【讨论】:

以上是关于刷新状态时出错:S3 中的状态数据没有预期的内容的主要内容,如果未能解决你的问题,请参考以下文章

在 React 中使用 aws-amplify 将文件上传到具有联合身份的 S3 时出错

SwiftUI 如何快速识别视图(View)界面的刷新是由哪个状态的改变导致的?

SwiftUI 如何快速识别视图(View)界面的刷新是由哪个状态的改变导致的?

Kafka 连接器记录写入器因缺少要分配的内存而卡在 S3OutputStream 中,但在几个小时内保持空闲状态并没有失败

Flux 中的 AJAX:依赖状态更改时刷新存储

无法更新运行时文件夹共享状态:在客户机操作系统内装载共享文件夹文件系统时出错——解决方案