如何构建Terraform项目

来自菜鸟教程
跳转至:导航、​搜索

介绍

根据 Terraform 项目的用例和感知的复杂性适当地构建它们对于确保它们在日常操作中的可维护性和可扩展性至关重要。 必须采用系统化的方法来正确组织代码文件,以确保项目在部署期间保持可扩展性并且对您和您的团队可用。

在本教程中,您将了解如何根据一般用途和复杂性来构建 Terraform 项目。 然后,您将使用 Terraform 的更常见功能创建一个结构简单的项目:变量、本地变量、数据源和配置器。 最后,您的项目将在 DigitalOcean 上部署 Ubuntu 20.04 服务器(Droplet),安装 Apache Web 服务器,并将您的域指向 Web 服务器。

先决条件

  • DigitalOcean 个人访问令牌,您可以通过 DigitalOcean 控制面板创建它。 您可以在 DigitalOcean 产品文档中找到说明,如何创建个人访问令牌
  • 添加到您的 DigitalOcean 帐户的无密码 SSH 密钥,您可以按照 How To Use SSH Keys with DigitalOcean Droplets 创建该密钥。
  • Terraform 安装在本地计算机上。 有关根据您的操作系统的说明,请参阅 如何使用 Terraform 与 DigitalOcean 教程的 Step 1
  • Python 3 安装在本地机器上。 您可以为您的操作系统完成 如何为 Python 3 安装和设置本地编程环境的 步骤 1
  • 添加到您的 DigitalOcean 帐户的完全注册的域名。 有关如何执行此操作的说明,请访问 官方文档

注意: 本教程专门用 Terraform 1.0.2 测试过。


了解 Terraform 项目的结构

在本节中,您将了解 Terraform 对项目的看法、如何构建基础架构代码以及何时选择哪种方法。 您还将了解 Terraform 工作空间、它们的作用以及 Terraform 如何存储状态。

resource 是在 Terraform 代码中声明的云服务的实体(例如 DigitalOcean Droplet),它是根据指定和推断的属性创建的。 多种资源相互连接,形成基础设施。

Terraform 使用一种专门的编程语言来定义基础设施,称为 Hashicorp 配置语言 (HCL)。 HCL 代码通常存储在以扩展名 tf 结尾的文件中。 Terraform 项目是包含 tf 文件并已使用 init 命令初始化的任何目录,该命令设置 Terraform 缓存和默认本地状态。

Terraform state 是跟踪实际部署在云中的资源的机制。 状态存储在后端(本地磁盘或远程文件存储云服务或专用状态管理软件),以实现最佳冗余和可靠性。 您可以在 Terraform 文档 中阅读有关不同后端的更多信息。

Project workspaces 允许您在同一个后端拥有多个状态,并绑定到同一个配置。 这允许您部署同一基础架构的多个不同实例。 每个项目都从一个名为 default 的工作区开始——如果您没有明确创建或切换到另一个项目,将使用该工作区。

Terraform 中的 Modules(类似于其他编程语言中的库)是包含多个资源声明的参数化代码容器。 它们允许您抽象出基础设施的公共部分,并在以后使用不同的输入重用它。

Terraform 项目还可以包含用于动态数据输入的外部代码文件,它可以解析 CLI 命令的 JSON 输出 并将其提供给资源声明使用。 在本教程中,您将使用 Python 脚本执行此操作。

现在您已经了解了 Terraform 项目的组成部分,让我们回顾一下 Terraform 项目结构的两种通用方法。

结构简单

简单的结构适用于小型和测试项目,具有不同类型和变量的少量资源。 它有一些配置文件,通常每个资源类型一个(或多个辅助文件和一个主文件),并且没有自定义模块,因为大多数资源都是独一无二的,不足以泛化和重用。 在此之后,大部分代码都存储在同一目录中,彼此相邻。 这些项目通常有一些变量(例如用于访问云的 API 密钥),并且可能使用动态数据输入和其他 Terraform 和 HCL 功能,尽管并不突出。

作为此方法的文件结构的示例,您将在本教程中构建的项目最终将如下所示:

.
└── tf/
    ├── versions.tf
    ├── variables.tf
    ├── provider.tf
    ├── droplets.tf
    ├── dns.tf
    ├── data-sources.tf
    └── external/
        └── name-generator.py

由于该项目将部署 Apache Web 服务器 Droplet 并设置 DNS 记录,因此项目变量、DigitalOcean Terraform 提供程序、Droplet 和 DNS 记录的定义将存储在各自的文件中。 最低要求的 Terraform 和 DigitalOcean 提供程序版本将在 versions.tf 中指定,而将为 Droplet 生成名称(并在 data-sources.tf 中用作动态数据源)的 Python 脚本将是存储在 external 文件夹中,以将其与 HCL 代码分开。

复杂的结构

与简单的结构相反,这种方法适用于大型项目,具有明确定义的子目录结构,其中包含多个复杂程度不同的模块,除了通常的代码。 这些模块可以相互依赖。 再加上版本控制系统,这些项目可以广泛使用工作空间。 这种方法适用于管理多个应用程序的大型项目,同时尽可能地重用代码。

开发、登台、质量保证和生产基础设施实例也可以通过依赖公共模块,放在不同目录下的同一个项目下,从而消除重复代码,使项目成为中心事实来源。 这是一个结构更复杂的示例项目的文件结构,包含多个部署应用程序、Terraform 模块和目标云环境:

.
└── tf/
    ├── modules/
    │   ├── network/
    │   │   ├── main.tf
    │   │   ├── dns.tf
    │   │   ├── outputs.tf
    │   │   └── variables.tf
    │   └── spaces/
    │       ├── main.tf
    │       ├── outputs.tf
    │       └── variables.tf
    └── applications/
        ├── backend-app/
        │   ├── env/
        │   │   ├── dev.tfvars
        │   │   ├── staging.tfvars
        │   │   ├── qa.tfvars
        │   │   └── production.tfvars
        │   └── main.tf
        └── frontend-app/
            ├── env/
            │   ├── dev.tfvars
            │   ├── staging.tfvars
            │   ├── qa.tfvars
            │   └── production.tfvars
            └── main.tf

如何使用 Terraform 管理基础架构系列中进一步探讨了这种方法。

您现在知道什么是 Terraform 项目,如何根据感知到的复杂性来最好地构建它,以及 Terraform 工作空间的作用。 在接下来的步骤中,您将创建一个具有简单结构的项目,该项目将提供一个安装了 Apache Web 服务器并为您的域设置 DNS 记录的 Droplet。 您将首先使用 DigitalOcean 提供程序和变量初始化您的项目,然后继续定义 Droplet、提供其名称的动态数据源和用于部署的 DNS 记录。

第 1 步 — 设置您的初始项目

在本节中,您将向项目添加 DigitalOcean Terraform 提供程序,定义项目变量,并声明一个 DigitalOcean 提供程序实例,以便 Terraform 能够连接到您的帐户。

首先使用以下命令为您的 Terraform 项目创建一个目录:

mkdir ~/apache-droplet-terraform

导航到它:

cd ~/apache-droplet-terraform

由于此项目将遵循简单的结构化方法,因此您将根据上一节中的文件结构将提供程序、变量、Droplet 和 DNS 记录代码存储在单独的文件中。 首先,您需要将 DigitalOcean Terraform 提供程序作为必需提供程序添加到您的项目中。

创建一个名为 versions.tf 的文件并通过运行打开它进行编辑:

nano versions.tf

添加以下行:

~/apache-droplet-terraform/versions.tf

terraform {
  required_providers {
    digitalocean = {
      source = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

在此 terraform 块中,您列出了所需的提供程序(DigitalOcean,版本 2.x)。 完成后,保存并关闭文件。

然后,按照将不同资源类型存储在单独代码文件中的方法,定义您的项目将在 variables.tf 文件中公开的变量:

nano variables.tf

添加以下变量:

~/apache-droplet-terraform/variables.tf

variable "do_token" {}
variable "domain_name" {}

保存并关闭文件。

do_token 变量将保存您的 DigitalOcean 个人访问令牌,而 domain_name 将指定您所需的域名。 部署的 Droplet 将自动安装由 SSH 指纹识别的 SSH 密钥。

接下来,让我们为这个项目定义 DigitalOcean 提供者实例。 您将把它存储在一个名为 provider.tf 的文件中。 通过运行创建并打开它进行编辑:

nano provider.tf

添加提供者:

~/apache-droplet-terraform/provider.tf

provider "digitalocean" {
  token = var.do_token
}

完成后保存并退出。 您已经定义了 digitalocean 提供程序,它对应于您之前在 provider.tf 中指定的所需提供程序,并将其标记设置为变量的值,该变量将在运行时提供。

在此步骤中,您为项目创建了一个目录,请求 DigitalOcean 提供程序可用,声明项目变量,并设置与 DigitalOcean 提供程序实例的连接以使用稍后提供的身份验证令牌。 您现在将编写一个脚本,该脚本将为您的项目定义生成动态数据。

第 2 步 — 为动态数据创建 Python 脚本

在继续定义 Droplet 之前,您将创建一个 Python 脚本,该脚本将动态生成 Droplet 的名称并声明一个数据源资源来解析它。 该名称将通过连接一个常量字符串 (web) 与本地机器的当前时间来生成,以 UNIX 纪元格式 表示。 当根据命名方案生成多个 Droplet 时,命名脚本可能很有用,以便轻松区分它们。

您将把脚本存储在一个名为 name-generator.py 的文件中,该文件位于一个名为 external 的目录中。 首先,通过运行创建目录:

mkdir external

external 目录位于项目的根目录中,将存储非 HCL 代码文件,例如您将编写的 Python 脚本。

external下创建name-generator.py并打开编辑:

nano external/name-generator.py

添加以下代码:

外部/名称生成器.py

import json, time

fixed_name = "web"
result = {
  "name": f"{fixed_name}-{int(time.time())}",
}

print(json.dumps(result))

此 Python 脚本导入 jsontime 模块,声明一个名为 resultdictionary,并设置 name 键的值到一个插值字符串,它结合了 fixed_name 和它运行的机器的当前 UNIX 时间。 然后,将 result 转换为 JSON 并在 stdout 上输出。 每次运行脚本时输出都会不同:

Output{"name": "web-1597747959"}

完成后,保存并关闭文件。

注意: 大型和复杂的结构化项目需要更多地考虑如何创建和使用外部数据源,尤其是在可移植性和错误处理方面。 Terraform 期望执行的程序将人类可读的错误消息写入 stderr 并以非零状态优雅地退出,由于任务的简单性,这在此步骤中未显示。 此外,它希望程序没有副作用,因此可以根据需要多次重新运行。

有关 Terraform 期望的更多信息,请访问关于数据源的 官方文档


现在脚本已准备就绪,您可以定义数据源,它将从脚本中提取数据。 您将按照简单的结构化方法将数据源存储在项目根目录中名为 data-sources.tf 的文件中。

通过运行创建它以进行编辑:

nano data-sources.tf

添加以下定义:

~/apache-droplet-terraform/data-sources.tf

data "external" "droplet_name" {
  program = ["python3", "${path.module}/external/name-generator.py"]
}

保存并关闭文件。

此数据源称为 droplet_name 并使用 Python 3 执行 name-generator.py 脚本,该脚本位于您刚刚创建的 external 目录中。 它会自动解析其输出并在其 result 属性下提供反序列化数据,以供在其他资源定义中使用。

通过现在声明的数据源,您可以定义 Apache 将在其上运行的 Droplet。

第 3 步 — 定义 Droplet

在此步骤中,您将编写 Droplet 资源的定义并将其存储在专用于 Droplet 的代码文件中,按照简单的结构化方法。 它的名称将来自您刚刚创建的动态数据源,并且每次部署时都会有所不同。

创建并打开 droplets.tf 文件进行编辑:

nano droplets.tf

添加以下 Droplet 资源定义:

~/apache-droplet-terraform/droplets.tf

data "digitalocean_ssh_key" "ssh_key" {
  name = "your_ssh_key_name"
}

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-20-04-x64"
  name   = data.external.droplet_name.result.name
  region = "fra1"
  size   = "s-1vcpu-1gb"
  ssh_keys = [
    data.digitalocean_ssh_key.ssh_key.id
  ]
}

您首先声明一个名为 ssh_key 的 DigitalOcean SSH 密钥资源,它将通过其名称从您的帐户中获取密钥。 确保将突出显示的代码替换为您的 SSH 密钥名称。

然后,您声明一个名为 web 的 Droplet 资源。 它在云中的实际名称会有所不同,因为它是从 droplet_name 外部数据源请求的。 为了在每次部署时使用 SSH 密钥引导 Droplet 资源,将 ssh_key 的 ID 传递到 ssh_keys 参数中,以便 DigitalOcean 知道要应用哪个密钥。

目前,与 droplet.tf 相关的配置已经完成,完成后保存并关闭文件。

您现在将为 DNS 记录编写配置,将您的域指向刚刚声明的 Droplet。

第 4 步 — 定义 DNS 记录

该过程的最后一步是配置指向您域中的 Droplet 的 DNS 记录。

您将 DNS 配置存储在名为 dns.tf 的文件中,因为它是与您在前面步骤中创建的其他资源类型不同的资源类型。 创建并打开它进行编辑:

nano dns.tf

添加以下行:

~/apache-droplet-terraform/dns.tf

resource "digitalocean_record" "www" {
  domain = var.domain_name
  type   = "A"
  name   = "@"
  value  = digitalocean_droplet.web.ipv4_address
}

此代码在您的域名处声明一个 DigitalOcean DNS 记录(使用变量传入),类型为 A。 该记录的名称为 @,它是到域本身的占位符路由,并且 Droplet IP 地址作为其 value。 您可以将 name 值替换为其他值,这将导致创建子域。

完成后,保存并关闭文件。

现在您已经配置了 Droplet、名称生成器数据源和 DNS 记录,您将继续在云中部署项目。

第 5 步 — 规划和应用配置

在本节中,您将初始化 Terraform 项目,将其部署到云中,并检查所有内容是否已正确配置。

现在项目基础架构已经完全定义,在部署它之前剩下要做的就是初始化 Terraform 项目。 通过运行以下命令来执行此操作:

terraform init

您将收到以下输出:

OutputInitializing the backend...

Initializing provider plugins...
- Finding digitalocean/digitalocean versions matching "~> 2.0"...
- Finding latest version of hashicorp/external...
- Installing digitalocean/digitalocean v2.10.1...
- Installed digitalocean/digitalocean v2.10.1 (signed by a HashiCorp partner, key ID F82037E524B9C0E8)
- Installing hashicorp/external v2.1.0...
- Installed hashicorp/external v2.1.0 (signed by HashiCorp)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

您现在可以使用动态生成的名称和随附的域将您的 Droplet 部署到您的 DigitalOcean 帐户。

首先将域名、SSH 密钥指纹和您的个人访问令牌定义为环境变量,这样您就不必在每次运行 Terraform 时复制这些值。 运行以下命令,替换突出显示的值:

export DO_PAT="your_do_api_token"
export DO_DOMAIN_NAME="your_domain"

您可以在 DigitalOcean 控制面板中找到您的 API 令牌。

使用传入的变量值运行 plan 命令,以查看 Terraform 将采取哪些步骤来部署您的项目:

terraform plan -var "do_token=${DO_PAT}" -var "domain_name=${DO_DOMAIN_NAME}"

输出将类似于以下内容:

OutputTerraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.web will be created
  + resource "digitalocean_droplet" "web" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + id                   = (known after apply)
      + image                = "ubuntu-20-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "web-1625908814"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "fra1"
      + resize_disk          = true
      + size                 = "s-1vcpu-1gb"
      + ssh_keys             = [
          + "...",
        ]
      + status               = (known after apply)
      + urn                  = (known after apply)
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }

  # digitalocean_record.www will be created
  + resource "digitalocean_record" "www" {
      + domain = "your_domain'"
      + fqdn   = (known after apply)
      + id     = (known after apply)
      + name   = "@"
      + ttl    = (known after apply)
      + type   = "A"
      + value  = (known after apply)
    }

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

以绿色 + 开头的行表示 Terraform 将创建随后的每个资源——这正是应该发生的情况,因此您可以 apply 配置:

terraform apply -var "do_token=${DO_PAT}" -var "domain_name=${DO_DOMAIN_NAME}"

输出将与以前相同,只是这次您将被要求确认:

OutputPlan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: `yes`

输入 yes,Terraform 将配置您的 Droplet 和 DNS 记录:

Outputdigitalocean_droplet.web: Creating...
...
digitalocean_droplet.web: Creation complete after 33s [id=204432105]
digitalocean_record.www: Creating...
digitalocean_record.www: Creation complete after 1s [id=110657456]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Terraform 现在已在其状态中记录了已部署的资源。 要确认 DNS 记录和 Droplet 已成功连接,您可以从本地状态中提取 Droplet 的 IP 地址,并检查它是否与您域的公共 DNS 记录匹配。 运行以下命令以获取 IP 地址:

terraform show | grep "ipv4"

您将收到您的 Droplet 的 IP 地址:

Outputipv4_address       = "your_Droplet_IP"
...

您可以通过运行检查公共 A 记录:

nslookup -type=a your_domain | grep "Address" | tail -1

输出将显示 A 记录指向的 IP 地址:

OutputAddress: your_Droplet_IP

它们应该是相同的,这意味着成功配置了 Droplet 和 DNS 记录。

要使下一步中的更改发生,请通过运行以下命令销毁已部署的资源:

terraform destroy -var "do_token=${DO_PAT}" -var "domain_name=${DO_DOMAIN_NAME}"

出现提示时,输入 yes 继续。

在此步骤中,您已创建基础架构并将其应用到您的 DigitalOcean 帐户。 您现在将对其进行修改,以使用 Terraform 配置器在配置的 Droplet 上自动安装 Apache Web 服务器。

第 6 步 — 使用 Provisioner 运行代码

现在,您将通过使用 remote-exec 配置程序执行自定义命令,在已部署的 Droplet 上设置 Apache Web 服务器的安装。

Terraform 配置器可用于对创建的远程资源(remote-exec 配置器)或代码正在执行的本地计算机(使用 local-exec 配置器)执行特定操作。 如果provisioner失败,该节点将在当前状态下被标记为tainted,这意味着它将在下次运行时被删除并重新创建。

要连接到已配置的 Droplet,Terraform 需要在 Droplet 上设置的 SSH 私钥。 传递私钥位置的最好方法是使用变量,所以打开variables.tf进行编辑:

nano variables.tf

添加突出显示的行:

~/apache-droplet-terraform/variables.tf

variable "do_token" {}
variable "domain_name" {}
variable "private_key" {}

您现在已将一个名为 private_key 的新变量添加到您的项目中。 保存并关闭文件。

接下来,您将连接数据和远程供应商声明添加到您的 Droplet 配置中。 通过运行打开 droplets.tf 进行编辑:

nano droplets.tf

使用突出显示的行扩展现有代码:

~/apache-droplet-terraform/droplets.tf

data "digitalocean_ssh_key" "ssh_key" {
  name = "your_ssh_key_name"
}

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-20-04-x64"
  name   = data.external.droplet_name.result.name
  region = "fra1"
  size   = "s-1vcpu-1gb"
  ssh_keys = [
    data.digitalocean_ssh_key.ssh_key.id
  ]

  connection {
    host        = self.ipv4_address
    user        = "root"
    type        = "ssh"
    private_key = file(var.private_key)
    timeout     = "2m"
  }

  provisioner "remote-exec" {
    inline = [
      "export PATH=$PATH:/usr/bin",
      # Install Apache
      "apt update",
      "apt -y install apache2"
    ]
  }
}

connection 块指定 Terraform 应如何连接到目标 Droplet。 provisioner 块包含命令数组,在 inline 参数中,它将在配置后执行。 也就是说,更新包管理器缓存并安装 Apache。 完成后保存并退出。

您也可以为私钥路径创建一个临时环境变量:

export DO_PRIVATE_KEY="private_key_location"

注意: 私钥以及您希望从 Terraform 中加载的任何其他文件都必须放在项目中。 您可以查看 如何在 Linux 服务器上配置基于 SSH 密钥的身份验证 教程,了解有关在 Ubuntu 20.04 或其他发行版上设置 SSH 密钥的更多信息。


再次尝试应用配置:

terraform apply -var "do_token=${DO_PAT}" -var "domain_name=${DO_DOMAIN_NAME}" -var "private_key=${DO_PRIVATE_KEY}"

出现提示时输入 yes。 您将收到与之前类似的输出,但随后是来自 remote-exec 供应商的长输出:

Outputdigitalocean_droplet.web: Creating...
digitalocean_droplet.web: Still creating... [10s elapsed]
digitalocean_droplet.web: Still creating... [20s elapsed]
digitalocean_droplet.web: Still creating... [30s elapsed]
digitalocean_droplet.web: Provisioning with 'remote-exec'...
digitalocean_droplet.web (remote-exec): Connecting to remote host via SSH...
digitalocean_droplet.web (remote-exec):   Host: ...
digitalocean_droplet.web (remote-exec):   User: root
digitalocean_droplet.web (remote-exec):   Password: false
digitalocean_droplet.web (remote-exec):   Private key: true
digitalocean_droplet.web (remote-exec):   Certificate: false
digitalocean_droplet.web (remote-exec):   SSH Agent: false
digitalocean_droplet.web (remote-exec):   Checking Host Key: false
digitalocean_droplet.web (remote-exec): Connected!
...
digitalocean_droplet.web: Creation complete after 1m5s [id=204442200]
digitalocean_record.www: Creating...
digitalocean_record.www: Creation complete after 1s [id=110666268]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

您现在可以在 Web 浏览器中导航到您的域。 您将看到默认的 Apache 欢迎页面。

这意味着 Apache 已成功安装,并且 Terraform 正确配置了所有内容。

要销毁已部署的资源,请运行以下命令并在提示时输入 yes

terraform destroy -var "do_token=${DO_PAT}" -var "domain_name=${DO_DOMAIN_NAME}" -var "private_key=${DO_PRIVATE_KEY}"

您现在已经完成了一个结构简单的小型 Terraform 项目,该项目将 Apache Web 服务器部署在 Droplet 上并为所需域设置 DNS 记录。

结论

您已经了解了两种根据复杂性构建 Terraform 项目的通用方法。 遵循简单的结构化方法,并使用 remote-exec 配置程序执行命令,然后您部署了一个运行 Apache 的 Droplet,并为您的域提供 DNS 记录。

作为参考,这里是您在本教程中创建的项目的文件结构:

.
└── tf/
    ├── versions.tf
    ├── variables.tf
    ├── provider.tf
    ├── droplets.tf
    ├── dns.tf
    ├── data-sources.tf
    └── external/
        └── name-generator.py

根据本教程第一部分中概述的简单项目结构,您定义的资源(Droplet、DNS 记录和动态数据源、DigitalOcean 提供程序和变量)都存储在自己的单独文件中。

有关 Terraform 配置器及其参数的更多信息,请访问 官方文档

本教程是 如何使用 Terraform 管理基础架构系列的一部分。 该系列涵盖了许多 Terraform 主题,从首次安装 Terraform 到管理复杂的项目。