arrow_back

管理 Terraform 状态

加入 登录
Test and share your knowledge with our community!
done
Get access to over 700 hands-on labs, skill badges, and courses

管理 Terraform 状态

Lab 1 小时 universal_currency_alt 5 个积分 show_chart 中级
Test and share your knowledge with our community!
done
Get access to over 700 hands-on labs, skill badges, and courses

本实验由 Google 与我们的合作伙伴 Hashicorp 共同开发。如果您在账号个人资料中选择接收产品动态、通知和优惠信息,那么我们可能会与实验赞助商 Hashicorp 共享您的个人信息。

GSP752

Google Cloud 自定进度实验

概览

Terraform 必须存储有关您托管的基础设施和配置的状态。Terraform 利用此状态将真实的资源映射到您的配置、跟踪元数据以及提高大型基础设施的性能。

此状态默认存储在名为 terraform.tfstate 的本地文件中,但也可以远程存储。远程存储更适合团队环境。

Terraform 使用此本地状态来创建方案并对基础设施进行更改。在执行任何操作之前,Terraform 都会先刷新,以根据真实基础设施来更新状态。

Terraform 状态的主要作用是存储远程系统中的对象与您的配置中声明的资源实例之间的绑定关系。当 Terraform 因配置变更而相应地创建远程对象时,会记录该远程对象相对于特定资源实例的身份信息,以后当配置再次发生变更时,可能会相应地更新或删除该对象。

目标

在本实验中,您将学习如何执行以下任务:

  • 创建本地后端。
  • 创建 Cloud Storage 后端。
  • 刷新 Terraform 状态。
  • 导入 Terraform 配置。
  • 使用 Terraform 管理导入的配置。

设置和要求

点击“开始实验”按钮前的注意事项

请阅读以下说明。实验是计时的,并且您无法暂停实验。计时器在您点击开始实验后即开始计时,显示 Google Cloud 资源可供您使用多长时间。

此实操实验可让您在真实的云环境中开展实验活动,免受模拟或演示环境的局限。我们会为您提供新的临时凭据,让您可以在实验规定的时间内用来登录和访问 Google Cloud。

为完成此实验,您需要:

  • 能够使用标准的互联网浏览器(建议使用 Chrome 浏览器)。
注意:请使用无痕模式或无痕浏览器窗口运行此实验。这可以避免您的个人账号与学生账号之间发生冲突,这种冲突可能导致您的个人账号产生额外费用。
  • 完成实验的时间 - 请注意,实验开始后无法暂停。
注意:如果您已有自己的个人 Google Cloud 账号或项目,请不要在此实验中使用,以避免您的账号产生额外的费用。

如何开始实验并登录 Google Cloud 控制台

  1. 点击开始实验按钮。如果该实验需要付费,系统会打开一个弹出式窗口供您选择付款方式。左侧是实验详细信息面板,其中包含以下各项:

    • 打开 Google 控制台按钮
    • 剩余时间
    • 进行该实验时必须使用的临时凭据
    • 帮助您逐步完成本实验所需的其他信息(如果需要)
  2. 点击打开 Google 控制台。 该实验会启动资源并打开另一个标签页,显示登录页面。

    提示:请将这些标签页安排在不同的窗口中,并将它们并排显示。

    注意:如果您看见选择帐号对话框,请点击使用其他帐号
  3. 如有必要,请从实验详细信息面板复制用户名,然后将其粘贴到登录对话框中。点击下一步

  4. 请从实验详细信息面板复制密码,然后将其粘贴到欢迎对话框中。点击下一步

    重要提示:您必须使用左侧面板中的凭据。请勿使用您的 Google Cloud Skills Boost 凭据。 注意:在本次实验中使用您自己的 Google Cloud 帐号可能会产生额外费用。
  5. 继续在后续页面中点击以完成相应操作:

    • 接受条款及条件。
    • 由于该帐号为临时帐号,请勿添加帐号恢复选项或双重验证。
    • 请勿注册免费试用。

片刻之后,系统会在此标签页中打开 Cloud 控制台。

注意:您可以点击左上角的导航菜单来查看列有 Google Cloud 产品和服务的菜单。 “导航菜单”图标

激活 Cloud Shell

Cloud Shell 是一种装有开发者工具的虚拟机。它提供了一个永久性的 5GB 主目录,并且在 Google Cloud 上运行。Cloud Shell 提供可用于访问您的 Google Cloud 资源的命令行工具。

  1. 点击 Google Cloud 控制台顶部的激活 Cloud Shell “激活 Cloud Shell”图标

如果您连接成功,即表示您已通过身份验证,且当前项目会被设为您的 PROJECT_ID 环境变量所指的项目。输出内容中有一行说明了此会话的 PROJECT_ID

Your Cloud Platform project in this session is set to YOUR_PROJECT_ID

gcloud 是 Google Cloud 的命令行工具。它已预先安装在 Cloud Shell 上,且支持 Tab 自动补全功能。

  1. (可选)您可以通过此命令列出活跃账号名称:
gcloud auth list
  1. 点击授权

  2. 现在,输出的内容应如下所示:

输出:

ACTIVE: * ACCOUNT: student-01-xxxxxxxxxxxx@qwiklabs.net To set the active account, run: $ gcloud config set account `ACCOUNT`
  1. (可选)您可以通过此命令列出项目 ID:
gcloud config list project

输出

[core] project = <project_ID>

输出示例

[core] project = qwiklabs-gcp-44776a13dea667a6 Note: For full documentation of gcloud, in Google Cloud, refer to the gcloud CLI overview guide.

Terraform 状态的作用

状态是 Terraform 运行的必要条件。人们有时会问 Terraform 是否可以在没有状态的情况下工作,或者干脆不使用状态,只在每次运行时检查云资源。即便 Terraform 能够在没有状态的情况下工作,这样做也只不过是将大部分复杂性从一个地方(状态)转移到另一个地方(类似的替换概念)。本部分将解释为什么说 Terraform 状态是必要的。

映射到真实世界

Terraform 需要某种数据库来将 Terraform 配置映射到真实世界。如果您的配置包含 resource resource "google_compute_instance" "foo",Terraform 通过此映射了解到实例 i-abcd1234 是以该资源表示的。

Terraform 希望每个远程对象只绑定到一个资源实例,这通常是能够保证的,因为 Terraform 负责在状态中创建对象并记录它们的身份信息。如果您改为导入在 Terraform 之外创建的对象,则必须验证每个不同的对象是否仅导入至一个资源实例。

如果一个远程对象绑定到两个或更多个资源实例,Terraform 可能会对这些对象执行非预期的操作,因为从配置到远程对象状态的映射变得不明确。

元数据

除了跟踪资源与远程对象之间的映射之外,Terraform 还必须跟踪元数据,例如资源依赖关系。

Terraform 通常使用配置来确定依赖顺序。但是,当您从 Terraform 配置中移除某项资源时,Terraform 必须知道如何删除该资源。Terraform 可能发现某个映射针对的是您配置文件中未定义的资源,并会计划销毁该资源。但是,由于该资源不再存在,因此仅根据配置无法确定顺序。

为确保正确操作,Terraform 会在状态内保留最新的一组依赖项的副本。现在,当您从配置中删除一项或多项内容时,Terraform 仍然可以基于状态确定正确的销毁顺序。

如果 Terraform 知道资源类型之间所需的顺序,则可以避免这种情况。例如,可以让 Terraform 知道必须先删除服务器,然后才能删除服务器所属的子网。然而,这种方法的复杂性很快会变得难以管理:Terraform 除了了解每个云的每个资源的排序语义外,还必须了解各提供程序 (Provider) 的排序。

Terraform 还会出于类似原因存储其他元数据,例如,在存在多个别名提供程序的情况下,Terraform 还会存储指向资源最近使用的提供程序配置的指针。

性能

除了基本映射之外,Terraform 还会在状态中存储所有资源的特性值缓存。这是 Terraform 状态的可选功能,仅作性能改进之用。

运行 terraform plan 时,Terraform 必须知道资源的当前状态,才能有效地确定实现您想要的配置所需的更改。

对于小型基础设施,Terraform 可以查询您的提供程序并同步您所有资源的最新特性。这是 Terraform 的默认行为:每次执行 planapply 时,Terraform 将同步您状态中的所有资源。

对于较大的基础设施,查询每个资源就会太慢。许多云服务提供商不提供同时查询多个资源的 API,并且每个资源的查询往返时间为数百毫秒。此外,云服务提供商几乎总是设置 API 速率限制,因此 Terraform 在一段时间内只能请求有限数量的资源。为解决此问题,Terraform 的大型用户经常同时使用 -refresh=false 标志和 -target 标志。在这些场景中,缓存的状态被视为真实的记录。

同步

在默认配置下,Terraform 将状态存储在当前工作目录(即运行 Terraform 的目录)下的某个文件中。这在刚开始时有效,但是当在团队中使用 Terraform 时,每个人都必须使用相同的状态,这样操作才能应用于相同的远程对象。

建议使用远程状态来解决该问题。借助功能完备的状态后端,Terraform 可以使用远程锁定这种措施来避免多个不同的用户意外同时运行 Terraform。这样可确保 Terraform 每次都以最新的状态开始运行。

状态锁定

只要您的后端支持,Terraform 就会锁定您的状态,防止被任何可以写入状态的操作更改。这可以防止其他人获得状态锁,杜绝其破坏您的状态的可能性。

所有可以写入状态的操作都会自动触发状态锁定。您不会看到有任何消息指出正在发生状态锁定。如果状态锁定失败,Terraform 将不会继续操作。您可以使用 -lock 标志对大多数命令停用状态锁定,但不建议这样做。

如果获取锁的时间比预期的要长,Terraform 将输出一条进度消息。如果 Terraform 没有输出消息,则说明状态锁定仍在进行。

并非所有后端都支持锁定。请查看后端类型列表,详细了解某个后端是否支持锁定。

工作区

每个 Terraform 配置都有一个关联的后端,该后端定义操作的执行方式以及 Terraform 状态等永久性数据的存储位置。

存储在后端的永久性数据属于一个“工作区”。最初,后端只有一个工作区,称为“default”,因此只有一个 Terraform 状态与该配置相关联。

某些后端支持多个命名工作区,即允许一个配置与多个状态相关联。该配置仍然只有一个后端,但您可以部署该配置的多个不同实例,而无需配置新后端或更改身份验证凭据。

任务 1. 使用后端

Terraform 中的后端决定如何加载状态以及如何执行 apply 等操作。这种抽象化实现了非本地文件状态存储、远程执行等。

默认情况下,Terraform 使用“本地”后端,这是您已习惯的 Terraform 的常规行为。在之前的实验中调用的就是这种后端。

下面列举了后端的一些好处:

  • 团队合作:后端可以远程存储其状态,并用锁保护该状态以防止被破坏。Terraform Cloud 等后端甚至会自动存储所有状态修订的历史记录。
  • 将敏感信息保留在磁盘之外:状态是按需从后端检索的,并且仅存储在内存中。
  • 远程操作:对于大型基础设施或某些变更,执行 terraform apply 可能需要很长时间。一些后端支持远程操作,即允许操作远程执行。这样,哪怕您关闭自己的计算机,操作仍将完成。此功能结合远程状态存储和锁定(如上所述),也可在团队环境中提供帮助。

后端是完全可选的:您无需学习或使用后端也可成功使用 Terraform。不过,后端确实在一定程度上解决了困扰团队的痛点。如果您是以个人身份工作,可能无需使用后端也不会遇到问题。

即使您只打算使用“本地”后端,了解后端也很有用,因为您还可以更改本地后端的行为。

添加本地后端

在本部分中,您将配置一个本地后端。

首次配置后端(从不定义后端转为明确配置后端)时,Terraform 会提供一个将状态迁移至新后端的选项。这样,您就可以在不丢失任何现有状态的情况下应用后端。

谨慎起见,我们始终建议您另外手动备份您的状态,只需将 terraform.tfstate 文件复制到另一个位置即可。初始化过程也应该会创建一个备份,但确保万无一失总没有坏处!

首次配置后端与以后更改配置没有什么不同:创建新配置并运行 terraform init。Terraform 会指导您完成剩下的工作。

  1. 在新的 Cloud Shell 窗口中,创建您的 main.tf 配置文件:
touch main.tf
  1. 如需检索您的项目 ID,请运行以下命令:
gcloud config list --format 'value(core.project)'
  1. 在 Cloud Shell 工具栏上,点击打开编辑器。如需在 Cloud Shell 与代码编辑器之间切换,请根据需要点击打开编辑器打开终端,或点击在新窗口中打开,使编辑器在单独的标签页中打开。
  1. 将 Cloud Storage 存储桶资源代码复制到您的 main.tf 配置文件中,并将 projectname 变量定义替换为您的项目 ID:
provider "google" { project = "# REPLACE WITH YOUR PROJECT ID" region = "{{{project_0.default_region | REGION}}}" } resource "google_storage_bucket" "test-bucket-for-state" { name = "# REPLACE WITH YOUR PROJECT ID" location = "US" uniform_bucket_level_access = true }

请参阅 Terraform 文档,详细了解 Cloud Storage 资源。

  1. main.tf 文件中添加一个本地后端:
terraform { backend "local" { path = "terraform/state/terraform.tfstate" } }

这会引用 terraform/state 目录中的 terraform.tfstate 文件。如需指定其他文件路径,请更改 path 变量。

本地后端会将状态存储在本地文件系统上,使用系统 API 锁定该状态,并在本地执行操作。

Terraform 在使用任何已配置的后端之前必须先对其进行初始化。为此,您需要运行 terraform init。团队中的任何成员针对任何 Terraform 配置执行的第一个步骤都应是运行 terraform init 命令。该命令可以执行多次而不会出现任何问题,它会执行 Terraform 环境所需的全部设置操作,包括初始化后端。

在以下情况下,必须调用 init 命令:

  • 当出现任何配置了后端的新环境时
  • 后端配置(包括后端类型)有任何变化时
  • 完全移除后端配置时

您不需要记住这些确切情况。Terraform 会检测出何时需要初始化,并适时地显示错误消息。Terraform 不会自动初始化,因为它可能需要用户提供其他信息或执行状态迁移等。

  1. 在 Cloud Shell 工具栏上,点击打开终端,然后初始化 Terraform:
terraform init
  1. 应用更改。出现提示时输入 yes 进行确认:
terraform apply

Cloud Shell 编辑器现在应该会在 terraform/state 目录中显示名为 terraform.tfstate 的状态文件。

  1. 检查您的状态文件:
terraform show

您的 google_storage_bucket.test-bucket-for-state 资源应该会显示。

添加一个 Cloud Storage 后端

Cloud Storage 后端将状态作为对象存储在 Cloud Storage 上指定存储桶的可配置前缀中。此后端也支持状态锁定。这会锁定您的状态,防止被所有可以写入状态的操作更改。这可以防止其他人获得状态锁,杜绝其破坏您的状态的可能性。

所有可以写入状态的操作都会自动触发状态锁定。您不会看到有任何消息指出正在发生状态锁定。如果状态锁定失败,Terraform 将不会继续操作。您可以使用 -lock 标志对大多数命令停用状态锁定,但不建议这样做。

  1. 重新定位到编辑器中的 main.tf 文件。现在您需要将当前本地后端替换为 gcs 后端。

  2. 如需更改现有的本地后端配置,请将以下配置复制到您的文件中,并替换 local 后端:

terraform { backend "gcs" { bucket = "# REPLACE WITH YOUR BUCKET NAME" prefix = "terraform/state" } } 注意:请务必更新 bucket 的变量定义。如果您未更改该配置,系统将使用 google_storage_bucket 资源中的 name。此存储桶将用于托管状态文件。
  1. 再次初始化您的后端,这次是为了自动迁移状态:
terraform init -migrate-state

出现提示时输入 yes 进行确认。

  1. 在 Cloud 控制台的导航菜单中,点击 Cloud Storage > 存储桶

  2. 点击存储桶并定位至文件 terraform/state/default.tfstate。您的状态文件现在已保存在 Cloud Storage 存储桶中。

注意: 如果您不再需要使用任何后端,只需从文件中移除该配置即可。Terraform 会像检测任何其他变更一样检测到这一变更,并提示您重新初始化。

在重新初始化的过程中,Terraform 会询问您是否要将状态迁移回正常的本地状态。完成后,Terraform 将恢复默认行为。

刷新状态

terraform refresh 命令用于使 Terraform(通过它的状态文件)所了解到的状态与真实的基础设施保持一致。这可用于检测与上次已知状态的偏差并更新状态文件。

此命令不会修改基础设施,但会修改状态文件。如果状态有变化,此命令可能会导致在下次执行 plan 或 apply 命令期间发生变化。

  1. 在 Cloud 控制台中返回到您的存储桶。选中名称旁边的复选框。

  2. 点击标签标签页。

  3. 点击添加标签。设置键 1 = key值 1 = value

  4. 点击保存

  5. 返回 Cloud Shell 并使用以下命令更新状态文件:

terraform refresh
  1. 检查更新:
terraform show

"key" = "value" 键值对应显示在配置的 labels 属性中。

点击“检查我的进度”以验证是否完成了以下目标: 使用后端

清理工作区

在继续下一个任务之前,需销毁您预配的基础设施。

  1. 首先,将后端恢复为 local,以便您可以删除对应存储桶。使用以下命令复制并替换 gcs 配置:
terraform { backend "local" { path = "terraform/state/terraform.tfstate" } }
  1. 再次初始化 local 后端:
terraform init -migrate-state

出现提示时输入 yes 进行确认。

  1. main.tf 文件中,向 google_storage_bucket 资源中添加 force_destroy = true 参数。删除存储桶时,此布尔选项会删除包含的所有对象。如果您尝试删除包含对象的存储桶,Terraform 将使该运行失败。您的资源配置应如下所示:
resource "google_storage_bucket" "test-bucket-for-state" { name = "qwiklabs-gcp-03-c26136e27648" location = "US" uniform_bucket_level_access = true force_destroy = true }
  1. 应用更改:
terraform apply

出现提示时输入 yes 进行确认。

  1. 现在可以成功销毁您的基础设施:
terraform destroy

出现提示时输入 yes 进行确认。

任务 2. 导入 Terraform 配置

在本部分中,您会将现有的 Docker 容器和映像导入一个空的 Terraform 工作区,以此来了解将真实基础设施导入 Terraform 的策略和注意事项。

默认的 Terraform 工作流涉及完全使用 Terraform 创建和管理基础设施。

  • 编写一项 Terraform 配置,定义您要创建的基础设施。

  • 检查该 Terraform 方案,确保配置将产生预期的状态和基础设施。

  • 应用配置,以创建您的 Terraform 状态和基础设施。

Terraform 工作流示意图

使用 Terraform 创建基础设施后,您可以更新配置并对这些更改运行 plan 和 apply 命令。最终,当不再需要该基础设施时,您将使用 Terraform 将其销毁。此工作流假定 Terraform 将创建一个全新的基础设施。

但是,您可能需要管理不是由 Terraform 创建的基础设施。Terraform 导入功能可以将支持的资源加载到 Terraform 工作区的状态中,因而可解决此问题。

不过,导入命令不会自动生成配置来管理该基础设施。因此,将现有基础设施导入 Terraform 的过程需要执行多个步骤。

将现有基础设施置于 Terraform 的控制之下涉及五个主要步骤:

  • 确定要导入的现有基础设施。
  • 将基础设施导入您的 Terraform 状态。
  • 编写与该基础设施相匹配的 Terraform 配置。
  • 检查该 Terraform 方案,确保配置与预期的状态和基础设施相匹配。
  • 应用配置以更新您的 Terraform 状态。

Terraform 导入工作流示意图

在本部分,首先您将使用 Docker CLI 创建一个 Docker 容器。接下来,您需要将它导入到一个新的 Terraform 工作区。然后,您需要使用 Terraform 更新容器的配置,最终,在完成这些操作后将其销毁。

警告:导入基础设施会影响 Terraform 的状态,可能会使现有 Terraform 项目处于无效状态。对真实的 Terraform 项目使用 Terraform 导入之前,请备份您的 terraform.tfstate 文件和 .terraform 目录,并将它们妥善存储。

创建 Docker 容器

  1. 使用来自 Docker Hub 的最新 NGINX 映像创建一个名为 hashicorp-learn 的容器,并通过端口 80 (HTTP) 在 Cloud Shell 虚拟机上预览该容器:
docker run --name hashicorp-learn --detach --publish 8080:80 nginx:latest
  1. 验证容器是否正在运行:
docker ps
  1. 在 Cloud Shell 窗格中,点击网页预览,然后点击在端口 8080 上预览

 “网页预览”选项

Cloud Shell 会在新的浏览器窗口中打开其代理服务的预览网址,并显示 NGINX 默认索引页面。现在您有一个 Docker 映像和容器可以导入到您的工作区并使用 Terraform 进行管理。

将容器导入 Terraform

  1. 克隆示例代码库:
git clone https://github.com/hashicorp/learn-terraform-import.git
  1. 切换到该目录:
cd learn-terraform-import

此目录包含两个 Terraform 配置文件,它们构成您将在本指南中使用的配置:

  • main.tf 文件配置了 Docker 提供程序。
  • docker.tf 文件将包含管理您在上一步中创建的 Docker 容器所需的配置。
  1. 初始化您的 Terraform 工作区:
terraform init 注意:如果出现 Error: Failed to query available provider packages(错误:未能查询到可用的提供程序包)这样的错误,则运行以下命令:terraform init -upgrade
  1. 在 Cloud Shell 编辑器中,定位到 learn-terraform-import/main.tf

  2. 找到 provider: docker 资源,将 host 参数注释掉或删除

provider "docker" { # host = "npipe:////.//pipe//docker_engine" } 注意: 这是目前用于暂时解决与 Docker 初始化错误相关的某个已知问题的方法。
  1. 接下来,定位到 learn-terraform-import/docker.tf

  2. docker.tf 文件中注释掉的代码下方,定义一个空的 docker_container 资源,它表示 Terraform 资源 ID 为 docker_container.web 的一个 Docker 容器:

resource "docker_container" "web" {}
  1. 找到您要导入的容器的名称:在本示例中为您在上一步中创建的容器:
docker ps
  1. 运行下面的 terraform import 命令,将现有 Docker 容器附加到刚刚创建的 docker_container.web 资源。Terraform 导入操作需要用到此 Terraform 资源 ID 和完整的 Docker 容器 ID。命令 docker inspect -f {{.ID}} hashicorp-learn 会返回完整的 SHA256 容器 ID:
terraform import docker_container.web $(docker inspect -f {{.ID}} hashicorp-learn) 注意terraform import 接受的 ID 因资源类型而异,可导入到 Terraform 的资源的提供程序文档中会加以说明。对于本示例,请查阅 Docker 提供程序文档
  1. 检验容器是否已导入到您的 Terraform 状态中:
terraform show

此状态包含 Terraform 所知晓的有关您刚刚导入的 Docker 容器的一切信息。但是,Terraform 导入操作不会为资源创建配置。

创建配置

您需要先创建 Terraform 配置,然后才能使用 Terraform 管理此容器。

  1. 运行以下代码:
terraform plan 注意: 当缺少必需参数 imagename 时,Terraform 会显示错误。Terraform 无法为缺少必需参数的资源生成方案。

您可以使用两种方法来更新 docker.tf 中的配置,使其与您导入的状态相匹配。您可以按原样将资源的整个当前状态导入到您的配置,也可以逐一选择需要的属性来导入到您的配置。这两种方法分别适用于不同的情形。

  • 使用当前状态通常更快,但可能会导致配置过于冗长,因为无论配置中是否需要,每个属性都会包含在状态中。

  • 逐一选择需要的属性会使配置更易于管理,但前提是您了解需要在配置中设置哪些属性。

鉴于本实验的目的,您将使用资源的当前状态。

  1. 将您的 Terraform 状态复制到 docker.tf 文件中:
terraform show -no-color > docker.tf 注意> 符号会将 docker.tf 的所有内容替换为 terraform show 命令的输出。虽然这适用于本示例,但要将资源导入到已在管理资源的配置,需要修改 terraform show 的输出,移除您不想完全替换其配置的现有资源,并将新资源合并到现有配置中。
  1. 检查 docker.tf 文件,查看其内容是否已替换为您刚刚运行的 terraform show 命令的输出。

  2. 运行以下代码:

terraform plan

Terraform 会显示关于已弃用参数 (links) 的警告和错误,以及几个只读参数(ip_addressnetwork_datagatewayip_prefix_lengthid)。

这些只读参数是 Docker 容器的值,Terraform 将它们存储在其状态中,但无法通过配置来设置这些值,因为它们在 Docker 内部管理。Terraform 可以使用配置来设置 links 参数,但仍会显示警告,因为它已弃用,并且可能不受 Docker 提供程序的未来版本支持。

由于此处所示的方法会加载 Terraform 状态中表示的所有属性,因此您的配置包括可选属性,它们的值与其默认值相同。哪些属性是可选的以及属性的默认值因提供程序而异,提供程序文档中会列明这些信息。

  1. 您现在可以有选择地移除这些可选属性。移除所有这些属性,仅保留必需的属性imagenameports移除这些可选属性后,您的配置应如下所示:
resource "docker_container" "web" { image = "sha256:87a94228f133e2da99cb16d653cd1373c5b4e8689956386c1c12b60a20421a02" name = "hashicorp-learn" ports { external = 8080 internal = 80 ip = "0.0.0.0" protocol = "tcp" } }

导入真实基础设施时,请查阅提供程序文档,了解每个参数的作用。这有助于您确定如何处理方案步骤中的任何错误或警告。例如,links 参数的相关信息包含在 Docker 提供程序文档中。

  1. 验证错误是否已解决:
terraform plan

方案现在应该能成功执行。请注意,该方案指出 Terraform 将更新容器,以添加 attachlogsmust_runstart 属性。

Terraform 使用这些属性来创建 Docker 容器,但 Docker 并不存储这些属性。因此,terraform import 没有将它们的值加载到状态中。当您对配置运行 plan 和 apply 命令时,Docker 提供程序会为这些属性分配默认值并将它们保存在状态中,但它们不会影响正在运行的容器。

  1. 应用更改,并完成将更新的 Terraform 配置和状态与它们所表示的 Docker 容器同步的过程。出现提示时输入 yes 进行确认。
terraform apply

现在您的配置文件、Terraform 状态和容器全部都已同步,接下来您可以像在通常情况下一样,使用 Terraform 来管理 Terraform 容器。

创建映像资源

在某些情况下,您无需使用 terraform import 命令,也能将资源置于 Terraform 的控制之下。使用单个唯一 ID 或标记定义的资源(例如 Docker 映像)通常就属于这种情况。

docker.tf 文件中,docker_container.web 资源指定用于创建容器的映像的 SHA256 哈希 ID。这是 docker 在内部存储映像 ID 的方式,因此 terraform import 将映像 ID 直接加载到了您的状态中。但是,映像 ID 不像映像标记或名称那样易于理解,并且可能与您的意图不符。例如,您可能希望使用最新版本的“nginx”映像。

  1. 如需检索映像的标记名称,请运行以下命令,并将 <IMAGE-ID> 替换为 docker.tf 中的映像 ID:
docker image inspect -f {{.RepoTags}}
  1. 在您的 docker.tf 文件中添加以下配置,将此映像表示为一个资源:
resource "docker_image" "nginx" { name = "nginx:latest" } 注意:暂时不要替换 docker_container.web 资源中的映像值,否则 Terraform 会销毁并重新创建您的容器。由于 Terraform 尚未将 docker_image.nginx 资源加载到状态中,因此它没有可与硬编码的映像 ID 进行比较的映像 ID,这会导致 Terraform 认为必须替换该容器。为避免这种情况,请先创建映像,然后再更新容器以使用它,如本实验所示。
  1. 在状态中创建一个映像资源:
terraform apply

现在,Terraform 已经为映像创建了一个资源,接下来您可以在容器的配置中引用它了。

  1. 更改 docker_container.web 的映像值以引用新的映像资源:
resource "docker_container" "web" { image = docker_image.nginx.image_id name = "hashicorp-learn" ports { external = 8080 internal = 80 ip = "0.0.0.0" protocol = "tcp" } }
  1. 查找变化:
terraform apply

由于 docker_image.nginx.latest 将与您替换的硬编码映像 ID 相匹配,因此此时运行 terraform apply 不会显示任何变化。

注意:如果标记“nginx:latest”的映像 ID 在您第一次创建 Docker 容器到运行此命令期间发生了变化,系统将会销毁此容器并使用新映像重新创建一个。

使用 Terraform 管理容器

现在 Terraform 已接管 Docker 容器,接下来使用 Terraform 更改配置。

  1. 在您的 docker.tf 文件中,将容器的外部端口从 8080 改为 8081
resource "docker_container" "web" { name = "hashicorp-learn" image = docker_image.nginx.image_id ports { external = 8081 internal = 80 ip = "0.0.0.0" protocol = "tcp" } }
  1. 应用更改:
terraform apply

出现提示时输入 yes 进行确认。

这会导致 Terraform 销毁容器并使用新的端口配置重新创建容器。

  1. 验证容器是否已替换为具有新配置的新容器:
docker ps

请注意,容器 ID 已更改。因为更改端口配置需要销毁并重新创建容器,所以这是一个全新的容器。

销毁基础设施

现在,您已将 Docker 容器和用于创建它的映像导入到了 Terraform。

  1. 销毁容器和映像:
terraform destroy

出现提示时输入 yes 进行确认。

  1. 验证容器是否已销毁:
docker ps --filter "name=hashicorp-learn" 注意:因为您已将映像添加到 Terraform 配置和容器中,所以映像将从 Docker 和容器中移除。如果有另一个容器也在使用该映像,销毁步骤将会失败。请记住,将资源导入 Terraform 意味着 Terraform 将管理该资源的整个生命周期,包括销毁阶段。

限制和其他注意事项

将资源导入 Terraform 时需要注意几个重要事项。

Terraform 导入功能只能知晓 Terraform 提供程序所报告的当前基础设施状态,而不会知晓以下信息:

  • 基础设施是否正常运作。
  • 基础设施的意图。
  • 您对不由 Terraform 控制的基础设施(例如,Docker 容器文件系统的状态)所做的更改。

导入过程涉及容易出错的手动步骤,特别是如果导入资源的人不了解最初创建这些资源的方式和原因的背景信息,出错的几率会更高。

导入过程会操作 Terraform 状态文件,因此您可能需要在导入新的基础设施之前创建备份。

Terraform 导入操作不会检测或生成基础设施之间的关系。

Terraform 不会检测不需要在配置中设置的默认属性。

并非所有提供程序和资源都支持 Terraform 导入。

将基础设施导入 Terraform 并不意味着可以销毁并重新创建 Terraform。例如,导入的基础设施可能依赖于其他非托管基础设施或配置。

遵循基础设施即代码 (IaC) 最佳实践(如不可变基础设施)有助于防止许多此类问题,但手动创建的基础设施不太可能遵循 IaC 最佳实践。

Terraformer 等工具可以自动执行与导入基础设施相关的一些手动步骤。但是,这些工具不是 Terraform 本身的一部分,也不受 HashiCorp 的背书或支持。

恭喜!

在本实验中,您学习了如何使用 Terraform 管理后端和状态。您创建了本地和 Cloud Storage 后端来管理状态文件,刷新了状态,并将配置导入到了 Terraform。然后,您更新了配置,并手动进行修改以使用 Terraform 完全管理 Docker 容器。

后续步骤/了解详情

请务必查看以下资源,以获得更多关于 Terraform 的实操练习机会:

Google Cloud 培训和认证

…可帮助您充分利用 Google Cloud 技术。我们的课程会讲解各项技能与最佳实践,可帮助您迅速上手使用并继续学习更深入的知识。我们提供从基础到高级的全方位培训,并有点播、直播和虚拟三种方式选择,让您可以按照自己的日程安排学习时间。各项认证可以帮助您核实并证明您在 Google Cloud 技术方面的技能与专业知识。

上次更新手册的时间:2024 年 1 月 26 日

上次测试实验的时间:2023 年 12 月 11 日

版权所有 2024 Google LLC 保留所有权利。Google 和 Google 徽标是 Google LLC 的商标。其他所有公司名和产品名可能是其各自相关公司的商标。