如何将手动更改导入Terraform远程状态 [英] How to import manual changes into Terraform remote state

查看:97
本文介绍了如何将手动更改导入Terraform远程状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对terraform并不陌生-我在s3中创建了远程tfstate,现在在AWS基础架构中也进行了一些手动更改.我需要将这些手动更改导入tfstate.

I am new to terraform - I have created remote tfstate in s3, and now there are some manual changes too that are done in my AWS infrastructure. I need to import those manual changes into tfstate.

我将import命令用于某些资源,但是对于某些资源(例如IAM策略等),则没有这样的导入命令.

I used the import command for some resources, but for some resources such as IAM policy etc, there is no such import command.

另外,诸如DB之类的某些资源也随着添加的新参数而改变,我也需要导入它们.当我尝试导入这些更改时,它说:

Also some resources such as DB are changed with new parameters added, and I need to import them as well. When I try to import those changes it says:

Error importing: 1 error(s) occurred:

* Can't import aws_security_group.Q8SgProdAdminSshInt, would collide
  with an existing resource.

Please remove or rename this resource before continuing.

任何帮助将不胜感激.谢谢.

Any help would be appreciated. Thanks.

推荐答案

在直接回答此问题之前,我认为一些上下文会有所帮助:

Before directly answering this question I think some context would help:

在后台,Terraform维护一个状态文件,该文件包含从配置中的资源到基础提供程序API中的对象的映射.当您使用Terraform创建新对象时,创建的对象的ID将自动保存在状态中,以便将来的命令可以定位引用的对象以进行读取,更新和删除操作.

Behind the scenes, Terraform maintains a state file that contains a mapping from the resources in your configuration to the objects in the underlying provider API. When you create a new object with Terraform, the id of the object that was created is automatically saved in the state so that future commands can locate the referenced object for read, update, and delete operations.

terraform import是在状态文件中创建条目的另一种方法.用户无需在命令行上提供一个ID,而无需创建一个新对象并记录其ID. Terraform 读取具有该id的对象,并将结果添加到状态文件中,然后在状态文件中将其与Terraform自身创建的资源区分开.

terraform import, then, is a different way to create an entry in the state file. Rather than creating a new object and recording its id, instead the user provides an id on the command line. Terraform reads the object with that id and adds the result to the state file, after which it is indistinguishable in the state from a resource that Terraform created itself.

话虽如此,让我们一个一个地解决您的问题.

So with all of that said, let's address your questions one-by-one.

由于每种资源都需要少量的验证和数据提取代码来进行导入,因此目前尚不支持所有资源进行导入.

Since each resource requires a small amount of validation and data-fetching code to do an import, not all resources are supported for import at this time.

鉴于我们从上面从理论上了解到terraform import所做的事情,有可能跳过Terraform对所提供ID的验证,而是手动将资源添加到状态中. 这是一项高级操作,必须小心进行,以免破坏状态..

Given what we know about what terraform import does from the above, in theory it's possible to skip Terraform's validation of the provided id and instead manually add the resource to the state. This is an advanced operation and must be done with care to avoid corrupting the state.

首先,将状态检索到用于本地工作的本地文件中:

First, retrieve the state into a local file that you'll use for your local work:

terraform state pull >manual-import.tfstate

这将创建一个文件manual-import.tfstate,您可以在文本编辑器中打开该文件.它使用JSON语法,因此尽管其内部结构未记录为稳定格式,但只要我们与预期结构保持一致,我们就可以对其进行仔细编辑.

This will create a file manual-import.tfstate that you can open in a text editor. It uses JSON syntax, so though its internal structure is not documented as a stable format we can carefully edit it as long as we remain consistent with the expected structure.

在与要导入,复制和编辑它相同的模块中找到现有资源是最简单的.假设我们有一个像这样的resources对象:

It's simplest to locate an existing resource that is in the same module as where you want to import and duplicate and edit it. Let's assume we have a resources object like this:

"resources": {
    "null_resource.foo": {
        "type": "null_resource",
        "depends_on": [],
        "primary": {
            "id": "5897853859325638329",
            "attributes": {
                "id": "5897853859325638329"
            },
            "meta": {},
            "tainted": false
        },
        "deposed": [],
        "provider": ""
    }
},

resources对象中的每个属性对应于您配置中的资源.属性名称是资源的类型和名称.在这种情况下,资源类型为null_resource,属性名称为foo.就您而言,您可能会在这里看到aws_instance.server之类的东西.

Each attribute within this resources object corresponds to a resource in your configuration. The attribute name is the type and name of the resource. In this case, the resource type is null_resource and the attribute name is foo. In your case you might see something like aws_instance.server here.

对于许多资源(但不是全部!),id属性是需要填充的主要内容.因此,我们可以为假设的IAM策略复制此结构:

The id attributes are, for many resources (but not all!), the main thing that needs to be populated. So we can duplicate this structure for a hypothetical IAM policy:

"resources": {
    "null_resource.foo": {
        "type": "null_resource",
        "depends_on": [],
        "primary": {
            "id": "5897853859325638329",
            "attributes": {
                "id": "5897853859325638329"
            },
            "meta": {},
            "tainted": false
        },
        "deposed": [],
        "provider": ""
    },
    "aws_iam_policy.example": {
        "type": "aws_iam_policy",
        "depends_on": [],
        "primary": {
            "id": "?????",
            "attributes": {
                "id": "?????"
            },
            "meta": {},
            "tainted": false
        },
        "deposed": [],
        "provider": ""
    }
},

此步骤面临的挑战是弄清楚该资源需要哪种ID.知道这一点的唯一肯定方法是读取代码,它告诉我该资源期望id为策略的完整ARN.

The challenge at this step is to figure out what sort of id this resource requires. The only sure-fire way to know this is to read the code, which tells me that this resource expects the id to be the full ARN of the policy.

有了这些知识,我们将上面示例中的两个?????序列替换为我们要导入的策略的ARN.

With that knowledge, we replace the two ????? sequences in the above example with the ARN of the policy we want to import.

手动更改状态后,有必要在文件的顶层更新serial号. Terraform希望任何新的更改都将具有更高的序列号,因此我们可以增加该序列号.

After making manual changes to the state it's necessary to update the serial number at the top-level of the file. Terraform expects that any new change will have a higher serial number, so we can increment this number.

完成更新后,我们必须将更新后的状态文件上传回Terraform:

After completing the updates, we must upload the updated state file back into Terraform:

terraform state push manual-import.tfstate

最后,我们可以要求Terraform刷新状态以确保其有效:

Finally we can ask Terraform to refresh the state to make sure it worked:

terraform refresh

同样,这是一个非常冒险的过程,因为状态文件是Terraform与基础系统关系的记录,如果丢失该文件的内容,则可能很难恢复.通常,简单地替换资源比进行所有这些工作要容易得多,除非资源已经在您的基础架构中发挥了关键作用,并且没有可用的优雅迁移策略.

Again, this is a pretty risky process since the state file is Terraform's record of its relationship with the underlying system and it can be hard to recover if the content of this file is lost. It's often easier to simply replace a resource than to go to all of this effort, unless it's already serving a critical role in your infrastructure and there is no graceful migration strategy available.

您的问题中给出的错误消息是关于导入与现有资源的冲突":

The error message given in your question is talking about an import "colliding" with an existing resource:

Error importing: 1 error(s) occurred:

* Can't import aws_security_group.Q8SgProdAdminSshInt, would collide with an existing resource.

Please remove or rename this resource before continuing.

此消息的含义是,当Terraform尝试将新资源写入状态文件时,它发现已经存在一个名称为aws_security_group.Q8SgProdAdminSshInt的资源条目.这表明它已经被导入,或者Terraform本身已经创建了一个新的安全组.

The meaning of this message is that when Terraform tried to write the new resource to the state file it found a resource entry already present for the name aws_security_group.Q8SgProdAdminSshInt. This suggests that either it was already imported or that a new security group was already created by Terraform itself.

您可以检查处于以下状态的现有资源的属性:

You can inspect the attributes of the existing resource in state:

terraform state show aws_security_group.Q8SgProdAdminSshInt

比较您尝试导入的安全组返回的数据.如果ID匹配,则无需做任何事情,因为该资源已被导入.

Compare the data returned with the security group you were trying to import. If the ids match then there's nothing left to do, since the resource was already imported.

如果IDs 不匹配,那么您需要确定两个对象中哪个是您要保留的对象.如果您想保留Terraform已有的版本,可以手动删除您要导入的版本.

If the ids don't match then you need to figure out which of the two objects is the one you want to keep. If you'd like to keep the one that Terraform already has, you can manually delete the one you were trying to import.

如果您想保留要导入的内容,可以将不需要的内容从Terraform状态中删除,以使导入成功:

If you'd like to keep the one you were trying to import instead, you can drop the unwanted one from the Terraform state to make way for the import to succeed:

terraform state rm aws_security_group.Q8SgProdAdminSshInt

请注意,这只会使Terraform忘记"资源;它仍将存在于EC2中,并且需要通过控制台,命令行工具或API手动删除.删除它之前,请务必记下它的id,以确保可以找到它以进行清理.

Note that this just makes Terraform "forget" the resource; it will still exist in EC2, and will need to be deleted manually via the console, command line tools, or API. Be sure to note down its id before deleting it to ensure that you can find it in order to to clean it up.

这篇关于如何将手动更改导入Terraform远程状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆