如何結構化一個 Terraform 項目

引言

根據用途和 perceived complexity 適當結構化 Terraform 項目是確保其可在日常生活中持續維護和擴展的重要關鍵。適當組織代碼文件 systematic approach 是確保项目在部署過程中保持可擴展性,以及對您和您的團隊可用的必要條件。

在這個教程中,您將學習如何根據一般的用途和複雜度結構化 Terraform 項目。然後,您將使用 Terraform 的更常見功能(變量、本地變量、數據來源和供应器)創建一個簡單結構的項目。最後,您的項目将在 DigitalOcean 上部署一個 Ubuntu 20.04 伺服器(Droplet),安裝 Apache 網頁伺服器,並將您的域名指向網頁伺服器。

前提

  • DigitalOcean 個人存取令牌,您可以通過 DigitalOcean 控制面板創建。您可以在 DigitalOcean 產品文件中找到指示,如何創建個人存取令牌

  • 添加到您的DigitalOcean帳户的無密码SSH密鑰,可通过following如何使用SSH密鑰與DigitalOcean液滴來创建。

  • 您的本地機上已安裝Terraform。有關於根據您的作業系統進行安裝的指示,請参閱使用Terraform與DigitalOcean的步驟1教程。

  • Python 3 已經在你的本地電腦上安裝。你可以為你的操作系统完成 步驟 1 中的 如何為 Python 3 安装和設定本地程式環境

  • 一個完全註冊的域名已添加到你的 DigitalOcean 帳號中。要了解如何進行,請訪問 官方文件

注意:此教程已經特別測試過與 Terraform 1.0.2 相配。

理解 Terraform 项目的結構

在這個部分中,您將學習什麼是Terraform認為的项目,如何結構 Infrastructure 代碼,以及何时選擇哪一種方法。您还将了解Terraform工作空間,它們是什麼,以及Terraform是如何存储狀態的。

在Terraform中,資源是被定義為雲服務實體(例如DigitalOcean Droplets)的entity,這些entity是在指定的和推導出的屬性基礎上根據Terraform代碼创建的。多個資源通過其相互連接構成了 infrastructures。resource是使用特殊编程语言定义的,称为Hashicorp Configuration Language(HCL)。HCL代码通常保存在以tf结尾的文件中。Terraform项目是指任何包含tf文件的目录,并且已经使用init命令进行了初始化,该命令设置Terraform缓存和默认本地状态。

Terraform使用特殊的编程语言来定义基础设施,这种语言被称为Hashicorp Configuration Language(HCL)。HCL代码通常保存在以.tf为后缀的文件中。一个Terraform项目是指任何包含.tf文件的目录,并且已经使用init命令进行了初始化,该命令会设置Terraform缓存和默认本地状态。

Terraform的状态机制是通过将部署到云中的资源跟踪记录下来的一种方式。状态存储在备份(可以是本地磁盘、远程文件存储云服务或专门的状态管理软件)中,以确保最佳冗余性和可靠性。您可以参阅Terraform文档了解更多关于不同后端的信息。

專案 工作空間 允許你在同一後端擁有多個狀態,與同一配置相關連。這讓你能部署相同 infrastructures 的多个不一樣实例。每個專案都以一個名為 default 的 workspace 開始——如果你沒有明確创建或切换到另一個的话,就會使用這個。

Terraform 的module(類似於其他编程語言的library)是parametrize的代码容器,包含multipleresource declaration。它們讓你abstractawaycommonpartofyourinfrastructureandreuseitlaterwithdifferentinputs。它们允许你将基础设施的常见部分封装为可参数化的代码容器,并稍后使用不同的输入进行重用。

一个Terraform项目也可以包括外部代码文件以用于动态数据输入,这些可以解析CLI命令的JSON输出并提供给资源声明使用。在本教程中,您将这样做的是一个Python脚本。

既然你知道了一个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名稱的Python脚本(並作為data-sources.tf中的动态数据源使用)將存儲在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工作區發揮什麼作用。在下一步,您將創建一個具有簡單結構的項目,該項目將為您的網域名提供Droplet和安裝了Apache網頁服務器的DNS記錄。您將首先用DigitalOcean提供者和變量初始化您的項目,然後定義Droplet,一個動態數據源以提供其名稱,以及用於部署的DNS記錄。

步驟 1 — 設定您的初始項目

在這一節中,您將向您的項目中添加 DigitalOcean Terraform 提供者,定義項目變量,並宣告一個 DigitalOcean 提供者實例,這樣 Terraform 才能連接到您的帳戶。

首先,使用以下命令創建一個用於您的 Terraform 項目的目錄:

  1. mkdir ~/apache-droplet-terraform

進入目錄:

  1. cd ~/apache-droplet-terraform

由於這個項目將遵循簡單的分層結構,您將把提供者、變量、Droplet 和 DNS 記錄代碼存儲在不同的文件中,如同前一文檔中的文件結構一樣。首先,您需要向您的项目中添加 DigitalOcean Terraform 提供者作為必需的提供者。

創建一個名稱為 versions.tf 的文件,并通过运行以下命令來打開它進行編輯:

  1. nano versions.tf

添加以下行:

~/apache-droplet-terraform/versions.tf
terraform {
  required_providers {
    digitalocean = {
      source = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

在這個 terraform 區塊中,您列出了必需的提供者(DigitalOcean,版本 2.x)。完成后,保存並關閉文件。

然後,在 variables.tf 文件中定義您的項目將暴露的變量,並按照將不同資源類型存儲在不同的代碼文件中的方法進行:

  1. nano variables.tf

添加以下變量:

~/apache-droplet-terraform/variables.tf
variable "do_token" {}
variable "domain_name" {}

保存並關閉文件。

`do_token` 變量將儲存您的 DigitalOcean 個人訪問令牌,而 `domain_name` 將指定您所需的域名。部署的 Droplet 將 automatically have the SSH key, identified by the SSH fingerprint, installed.

接下來,讓我們為這個項目定義 DigitalOcean 提供者實例。您將把它存儲在一個名為 `provider.tf` 的文件中。通過運行以下命令來創建並打開它以進行編輯:

  1. nano provider.tf

新增提供者:

~/apache-droplet-terraform/provider.tf
provider "digitalocean" {
  token = var.do_token
}

完成後保存並退出。您已經在 `provider.tf` 中定義了對應於早先指定的必要提供者的 `digitalocean` 提供者,並將其令牌設定為變量的值,這將在運行時提供。

在這一步,您為您的項目創建了一個目錄,要求 DigitalOcean 提供者可用,宣告了項目變量,並設定到 DigitalOcean 提供者實例的連接以使用後續提供的身份验证令牌。現在,您將撰寫一個腳本,用於為您的項目定義生成動態數據。

步驟 2 — 創建用於動態數據的 Python 腳本

在繼續定義Droplet之前,您將建立一個Python腳本,該腳本將動態生成Droplet的名稱,並宣告一個數據源資源以解析它。名稱通過將常數字符串(web)與本地機器的當前時間(以UNIX時間戳格式表示)串接而成。命名脚本在根據命名方案生成的多個Droplet中,可用于輕鬆區分它們。

您將腳本存儲在一個名稱為name-generator.py的文件中,該文件位於名為external的目錄中。首先,通過運行以下命令創建目錄:

  1. mkdir external

external 目錄位於您的項目根目錄中,用於存儲非HCL代碼文件,如您將寫的Python腳本。

external目錄下創建name-generator.py,並打開進行編輯:

  1. nano external/name-generator.py

添加以下代碼:

external/name-generator.py
import json, time

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

print(json.dumps(result))

此Python腳本導入了jsontime模塊,宣告了一個字典名稱為result,並將name鍵的值設定為插值字符串,該字符串結合了fixed_name與機器運行端的當前UNIX時間。然後,result被轉換為JSON並输出到stdout。每次運行腳本時,輸出將不相同:

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

完成後,請保存並關閉檔案。

注意: 大型且複雜的結構化項目需要更多思考 external data sources 的創建和使用,特別是關於可携性和錯誤處理。Terraform 期望執行中的程序將可閱讀的錯誤消息寫入 stderr,并以非零狀態正常退出,這在這個步驟中沒有展示,因為任務太簡單。另外,它期望程序沒有副作用,以便可以重複執行。

有關 Terraform 對 data sources 的期望,請訪問 官方文件

現在腳本已經準備好,您可以定義 data source,它將從腳本中提取數據。您將 data source 存儲在命名為 data-sources.tf 的文件中,該文件位於项目的根目錄下,符合簡單結構方法。

通過運行以下命令來創建並編輯它:

  1. nano data-sources.tf

添加以下定義:

~/apache-droplet-terraform/data-sources.tf
data "external" "droplet_name" {
  program = ["python3", "${path.module}/external/name-generator.py"]
}

保存並關閉文件。

這個 data source 稱為 droplet_name 並使用 Python 3 執行 name-generator.py 腳本,該腳本位於剛剛創建的 external 目錄中。它會自動解析其輸出,並將反序列化的數據放置在其 result 屬性下,供其他資源定義中使用。

現在已經宣告了 data source,您可以定義 Apache 將運行的 Droplet。

第三步:定义液滴

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

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

  1. 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
  ]
}

首先声明一个DigitalOcean SSH密钥资源,名为ssh_key,该资源将从您的账户获取具有特定名称的密钥。请确保将高亮显示的代码替换为您的SSH密钥名称。

然后,声明一个Droplet资源,名为web。其实际名称在云中将是不同的,因为它是从droplet_name外部数据源请求的。为了每次部署时启动Droplet资源,将ssh_key的ID传递给ssh_keys参数,这样DigitalOcean就知道应该应用哪个密钥了。

目前,您只需要配置与droplet.tf相关的部分,所以保存并关闭文件。

现在您将编写指向您刚刚声明的液滴的DNS记录的配置。

步驟 4 — 定義 DNS 记录

processes 中的最後一步是配置 DNS 记录,將其指向您域名下的 Droplet。

您將把 DNS 配置存儲在一個名為 dns.tf 的文件中,因為它與您在先前的步驟中創建的其他資源類型是分開的。創建並打開它以供編輯:

  1. 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 記錄,接下來您將移至 cloud 中部署項目。

步驟 5 — 规划和應用配置

在本節中,您將初始化您的Terraform項目,將其部署到雲,並檢查所有內容是否已正確提供。

現在该项目的基础设施已完全定義,而在部署之前所剩的事情就是初始化Terraform項目。請通過運行以下命令來進行初始化:

  1. terraform init

您將收到以下輸出:

Output
Initializing 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.

現在,您將能夠使用 dynamically generated name 和陪同的 domain 将您的 Droplet 部署到您的 DigitalOcean 帳號。

首先,定義域名、SSH 金鑰指紋和您的個人訪問令牌作為環境變量,這樣您在運行 Terraform 時就不需要複製這些值。運行以下命令,替換突出的值:

  1. export DO_PAT="your_do_api_token"
  2. export DO_DOMAIN_NAME="your_domain"

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

運行 plan 命令並將變量值傳遞進去,以查看 Terraform 將采取哪些步驟來部署您的項目:

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

輸出將與以下类似:

Output
Terraform 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 将被创建 + 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 将被创建 + 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 配置:

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

輸出與之前相同,除非這次您會被要求確認:

Output
Plan: 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 記錄。

Output
digitalocean_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紀錄和液滴連接成功,您可以從本地狀態提取液滴的IP地址並檢查它是否與您的域名的公開DNS紀錄相匹配。執行以下命令以獲取液滴的IP地址:

  1. terraform show | grep "ipv4"

您將收到液滴的IP地址:

Output
ipv4_address = "your_Droplet_IP" ...

您可以使用以下命令检查public A记录:

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

輸出將會顯示A記錄指向的IP地址:

Output
Address: your_Droplet_IP

它們相同,如應該的,这意味着液滴和DNS記錄成功地配置。

為了進行下一步更改,請运行以下命令摧毁部署的資源:

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

當提示時,輸入 yes 繼續。

在這一步中,您已在DigitalOcean上创建了 infrastructures并将其应用。您现在将修改它以使用Terraform provisioners自动在已部署的Droplet上安装Apache Web服务器。

步6—使用提供程序运行代码

現在,您将通过使用remote-exec提供程序在已部署的液滴上执行自定义命令来设置Apache Web服务器的安装。

Terraform 提供了用于在创建的远程资源上执行特定操作的 Provisioner,例如使用 remote-exec 提供程序或在运行代码的本地机器上执行操作(使用 local-exec 提供程序)。如果提供程序失败,节点将被标记为 污染,这意味着它将在下一次运行中被删除并重新创建。

要连接到已配置的 Dropleton,Terraform 需要 Droplet 上设置的私钥。传递私钥位置的最佳方式是使用变量,因此打开 variables.tf 进行编辑:

  1. nano variables.tf

添加高亮显示的行:

~/apache-droplet-terraform/variables.tf
variable "do_token" {}
variable "domain_name" {}
variable "private_key" {}

您现在已经向您的项目添加了一个新变量,名为 private_key 。保存并关闭文件。

接下来,您将添加Droplet配置中的连接数据和远程提供程序声明。打开 droplets.tf 编辑文件:

  1. 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"
    ]
  }
}

块指定 Terraform 如何连接到目标 Droplet。 块包含要执行的命令数组,位于 参数中,在提供程序之后。即更新包管理器缓存并安装Apache。保存并退出。

您还可以创建一个临时环境变量来指定私钥路径:

  1. export DO_PRIVATE_KEY="private_key_location"

注意:
私鑰和其他希望從项目中载入的檔案,必須放置於專案中。有關於在Ubuntu 20.04或其他發行版上设置SSH密钥based authentication的詳細信息,請参閱How To Configure SSH Key-Based Authentication on a Linux Server教程。

再次應用配置:

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

輸入yes回應提示。您將獲得與之前相似的輸出,但之後會跟隨來自remote-exec供應商的長輸出:

Output
digitalocean_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.

現在您可以使用網頁瀏覽器前往您的domain。您將會看到default Apache歡迎頁面。這表示Apache已成功安裝,且Terraform provisions了所有正確的資源。

要摧毁部署的資源,執行以下命令並輸入yes回應提示:

您已經完成了一個簡單結構的Terraform專案,它部署了Apache伺服器和為指定的domain設定DNS記錄。

  1. 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来管理云资源,以及如何自动化部署复杂的网络基础设施。通过这样的实践练习,你可以更好地理解Terraform的工作原理,并能够将其应用到更复杂的场景中。

以下為根據您的指示翻譯的結果:

您已經瞭解了兩種一般的Terraform專案結構方式,根據其複雜性來決定。依據簡單的架構方式,並使用remote-exec provisions来執行命令,然後部署了一个运行Apache的Droplet以及为您的域名设置了DNS记录。

以下為您创建的这个教程的项目檔案结构:

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

根据本教程的第一部分所述的简单项目结构,您定义的資源(运行Apache的Droplet、DNS记录和动态数据源、DigitalOcean提供程序和变量)存储在不同的文件中。

有关Terraform provisioners及其参数的更多信息,请参阅官方文档

此教程是《如何使用Terraform管理基础设施》系列的一部分。该系列涵盖了多个Terraform主题,从安装Terraform到管理复杂项目。

Source:
https://www.digitalocean.com/community/tutorials/how-to-structure-a-terraform-project