构建自定义 Terraform 模块

0 股票
0
0
0
0

介绍

Terraform 模块允许您将基础设施中不同的资源组合成一个统一的资源。您可以稍后重用这些模块,并根据需要进行自定义,而无需每次都重复定义资源,这对于具有复杂结构的大型项目非常有用。您可以使用定义的输入变量自定义模块实例,也可以使用输出从中提取信息。除了创建自定义模块之外,您还可以使用 Terraform 注册表中公开发布的预构建模块。开发人员可以使用与您创建的模块类似的输入来使用和自定义这些模块,但它们的源代码存储在云端和云端之间。在本教程中,您将创建一个 Terraform 模块,该模块会在负载均衡器后启动多个 Droplet 以实现冗余。您还将使用 HashiCorp 配置语言 (HCL) 的 for_each 和 count 循环功能来同时部署多个自定义模块实例。.

先决条件
  • 个人 DigitalOcean 访问代码
  • Terraform 已安装在您的系统上,并且已使用 DO 提供程序设置了一个项目。
  • 数据类型和HCL循环简介
  • Terraform 输出及其用途简介

模块结构及优势

在本节中,您将了解模块带来的优势、它们在项目中的典型位置以及它们的结构。自定义 Terraform 模块用于封装通常在大型项目中使用的连接组件,这些组件通常会一起部署。它们是自包含的,仅包含所需的资源、变量和提供程序。模块通常存储在项目根目录下的一个中心文件夹中,每个模块都位于自己的子文件夹中。为了保持模块之间的清晰分离,请始终将模块设计为具有单一用途,并确保它们不包含子模块。将单个资源打包为模块可能会造成冗余,并逐渐破坏整体架构的简洁性。对于小型开发和测试项目,无需合并模块,因为它们在这些情况下不会带来显著的改进。模块的另一个优势是,只需在一个地方修改定义,然后更改就会传播到基础架构的其他部分。.

接下来,您可以在 Terraform 项目中定义、使用和自定义模块。.

创建模块

在本节中,您将定义多个 Droplet 和一个负载均衡器作为 Terraform 资源,并将它们打包成一个模块。您还将使用可配置的模块输入来配置生成的模块。.

将模块放置在名为“ 液滴磅您将把文件保存到名为 modules 的目录中。假设您位于之前创建的 terraform-modules 目录中,请运行以下命令同时安装两者:

mkdir -p modules/droplet-lb

-p 参数指示 mkdir 创建指定路径下的所有目录。.

去吧:

cd modules/droplet-lb

如前所述,模块包含它们使用的资源和变量。从 Terraform 0.13 开始,模块还必须包含它们使用的提供程序的定义。模块不需要任何特殊配置来表明代码代表一个模块,因为 Terraform 将包含 HCL 代码的任何目录(甚至包括项目根目录)都视为模块。.

模块中定义的变量会作为其输入公开,并可在资源定义中使用以进行自定义。您创建的模块将有两个输入:要创建的 Droplet 数量及其所属组的名称。要编辑名为 的文件 variables.tf 创建并打开用于存储变量的位置:

nano variables.tf

添加以下几行:

variable "droplet_count" {}
variable "group_name" {}

保存并关闭文件。.

您可以在名为以下名称的文件中定义 Droplet: 液滴.tf 保存后,创建并打开进行编辑:

nano droplets.tf

添加以下几行:

resource "digitalocean_droplet" "droplets" {
count = var.droplet_count
image = "ubuntu-22-04-x64"
name = "${var.group_name}-${count.index}"
region = "fra1"
size = "s-1vcpu-1gb"
lifecycle {
precondition {
condition = var.droplet_count >= 2
error_message = "At least two droplets must be created."
}
}
}

对于参数 数数您需要传入 `droplet_count` 变量,该变量指定要创建的资源实例数量。其值将在从主项目代码调用模块时确定。每个已部署的 Droplet 的名称都不同,这是通过将当前 Droplet 索引附加到提供的组名称来实现的。在区域中部署 Droplet fra1 它将运行 Ubuntu 22.04。.

部分 生命周期 包含一个 前提 此验证在资源实际部署之前执行。它确保至少创建两个 drop——如果只有一个 drop,则无法实现负载均衡。另一个验证示例可以在 k8s-bootstrapper 代码库中找到,该代码库包含使用 Terraform 设置 DigitalOcean Kubernetes 集群的模板。其中,验证用于确保集群中的节点数量在范围内。.

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

定义好 Droplet 后,就可以继续创建负载均衡器了。在名为 `<filename>` 的文件中定义其源。 磅.tf 您需要保存它。运行以下命令创建并打开它以进行编辑:

nano lb.tf

添加其来源定义:

resource "digitalocean_loadbalancer" "www-lb" {
name = "lb-${var.group_name}"
region = "fra1"
forwarding_rule {
entry_port = 80
entry_protocol = "http"
target_port = 80
target_protocol = "http"
}
healthcheck {
port = 22
protocol = "tcp"
}
droplet_ids = [
for droplet in digitalocean_droplet.droplets:
droplet.id
]
}

为了便于识别,您需要在负载均衡器的名称中包含组名。您还需要在区域中定义负载均衡器及其对应的服务器。 fra1 接下来的两节将具体说明目标端口和监控端口及协议。.

高亮显示的 `droplet_ids` 代码块获取需要由负载均衡器管理的 Droplet 的 ID。由于 Droplet 数量众多且事先未知,因此使用 `for` 循环遍历 Droplet 集合(`digitalocean_droplet.droplets`)并获取它们的 ID。将 `for` 循环用方括号 `[]` 括起来,以便返回一个列表。.

保存并关闭文件。.

现在您已经为模块定义了 Droplet、负载均衡器和变量,接下来需要定义提供程序要求,并指定模块将使用的提供程序,包括它们的版本和位置。从 Terraform 0.13 开始,模块必须显式定义它们将使用的非 HashiCorp 提供程序资源。这是因为它们不会从父项目继承这些资源。.

您可以在名为“ provider.tf 保存后,运行以下命令即可进行编辑:

nano provider.tf

添加以下代码以指定 DigitalOcean 提供商:

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

完成后,保存并关闭文件。模块 液滴磅 现在轮到服务提供商了 DigitalOcean 需求。.

模块还支持输出,您可以使用这些输出提取有关其资源状态的内部信息。您可以定义一个显示负载均衡器 IP 地址的输出,并将其放在一个名为 `.htm.htm` 的文件中。 outputs.tf 保存。创建可编辑版本:

nano outputs.tf

添加以下定义:

output "lb_ip" {
value = digitalocean_loadbalancer.www-lb.ip
}

此输出将显示负载均衡器的 IP 地址。保存并关闭文件。.

模块 液滴磅 现在它已完全具备功能,可以部署了。您将从主代码中调用它,主代码将存储在项目根目录中。首先,双击文件目录的顶部菜单栏即可找到它:

cd ../..

然后一个名为 main.tf 创建并打开以供编辑,以便您将使用该模块:

nano main.tf

添加以下几行:

module "groups" {
source = "./modules/droplet-lb"
droplet_count = 3
group_name = "group1"
}
output "loadbalancer-ip" {
value = module.groups.lb_ip
}

在此公告中,模块 液滴磅 您调用源目录,该目录位于指定的目录中。它提供的输入是: 水滴计数组名 您可以将其配置为 group1,以便以后区分不同的实例。.

由于负载均衡器 IP 输出是在模块中定义的,因此在部署项目时不会自动显示。解决方法是通过检索其值 (loadbalancer_ip) 来创建另一个输出。.

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

运行该模块的方法如下:

terraform init

输出结果如下:

OutputInitializing modules...
- groups in modules/droplet-lb
Initializing the backend...
Initializing provider plugins...
- Finding digitalocean/digitalocean versions matching "~> 2.0"...
- Installing digitalocean/digitalocean v2.34.1...
- Installed digitalocean/digitalocean v2.34.1 (signed by a HashiCorp partner, key ID F82037E524B9C0E8)
...
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.

您可以安排项目执行时间,以查看 Terraform 在执行时将采取哪些操作:

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

输出结果将类似于这样:

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:
# module.groups.digitalocean_droplet.droplets[0] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-0"
...
}
# module.groups.digitalocean_droplet.droplets[1] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-1"
...
}
# module.groups.digitalocean_droplet.droplets[2] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-2"
...
}
# module.groups.digitalocean_loadbalancer.www-lb will be created
+ resource "digitalocean_loadbalancer" "www-lb" {
...
+ name = "lb-group1"
...
}
Plan: 4 to add, 0 to change, 0 to destroy.
...

该输出解释说,Terraform 创建了三个名为 group1-0、group1-1 和 group1-2 的 droplet,并创建了一个名为 group1-lb 的负载均衡器,用于处理进出这三个 droplet 的流量。.

您可以通过运行以下命令将项目部署到云端:

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

出现提示时,输入“是”。输出结果将显示所有操作,并显示负载均衡器的 IP 地址:

Outputmodule.groups.digitalocean_droplet.droplets[1]: Creating...
module.groups.digitalocean_droplet.droplets[0]: Creating...
module.groups.digitalocean_droplet.droplets[2]: Creating...
...
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Outputs:
loadbalancer-ip = ip_address

您创建了一个模块,其中包含可配置数量的 droplet 和一个负载均衡器,该负载均衡器会自动配置以管理其传入和传出的流量。.

重命名已部署的资源

在上一节中,您部署了已定义并将其命名为“Group”的模块。如果您想更改其名称,仅仅重命名模块调用并不能产生预期结果。重命名调用会导致 Terraform 销毁并重新创建资源,从而造成过长的停机时间。.

例如, main.tf 运行以下命令即可打开进行编辑:

nano main.tf

将 groups 模块重命名为 group_renamed,具体操作如下:

module "groups_renamed" {
source = "./modules/droplet-lb"
droplet_count = 3
group_name = "group1"
}
output "loadbalancer-ip" {
value = module.groups_renamed.lb_ip
}

保存并关闭文件。然后重新初始化项目:

terraform init

现在你可以开始规划项目了:

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

输出结果会很长,但大致如下所示:

Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
- destroy
Terraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] will be destroyed
...
# module.groups_renamed.digitalocean_droplet.droplets[0] will be created
...

Terraform 要求您销毁现有实例并创建新实例。这既不必要又具有破坏性,并且可能导致意外崩溃。.

或者,您可以使用 `migrated` 代码块指示 Terraform 将旧资源迁移到新名称。打开 `main.tf` 文件进行编辑,并在文件末尾添加以下几行:

moved {
from = module.groups
to = module.groups_renamed
}

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

现在你可以开始规划项目了:

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

当您在 main.tf 中使用已移动的代码块进行编程时,Terraform 会选择移动资源而不是重新创建它们:

OutputTerraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] has moved to module.groups_renamed.digitalocean_droplet.droplets[0]
...
# module.groups.digitalocean_droplet.droplets[1] has moved to module.groups_renamed.digitalocean_droplet.droplets[1]
...

移动资源在 Terraform 模式下会改变其位置,这意味着实际的云资源不会被更改、销毁或重新创建。.

由于下一步您将对配置进行重大更改,请运行以下命令更新已部署的资源:

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

当被问及此事时, 是的 输入。输出结果以以下内容结尾:

Output...
Destroy complete! Resources: 4 destroyed.

在本节中,您重命名了 Terraform 项目中的资源,而没有销毁它们。现在,您将使用 for_each 和 count 从同一段代码部署模块的多个实例。.

部署多个模块实例

在本节中,您可以使用 count 和 for_each 多次部署 droplet-lb 模块并进行自定义。.

 使用计数

同时部署模块多个实例的一种方法是向 count 参数传递一个数量,该参数会自动为每个模块提供。打开 main.tf 进行编辑:

nano main.tf

删除现有的输出定义和已移动的代码块,将其更改为以下内容:

module "groups" {
source = "./modules/droplet-lb"
count = 3
droplet_count = 3
group_name = "group1-${count.index}"
}

将计数设置为 3,即可指示 Terraform 部署该模块三次,每次使用不同的组名称。完成后,保存并关闭文件。.

运行以下命令安排部署:

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

输出结果会很长,格式如下:

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:
# module.groups[0].digitalocean_droplet.droplets[0] will be created
...
# module.groups[0].digitalocean_droplet.droplets[1] will be created
...
# module.groups[0].digitalocean_droplet.droplets[2] will be created
...
# module.groups[0].digitalocean_loadbalancer.www-lb will be created
...
# module.groups[1].digitalocean_droplet.droplets[0] will be created
...
# module.groups[1].digitalocean_droplet.droplets[1] will be created
...
# module.groups[1].digitalocean_droplet.droplets[2] will be created
...
# module.groups[1].digitalocean_loadbalancer.www-lb will be created
...
# module.groups[2].digitalocean_droplet.droplets[0] will be created
...
# module.groups[2].digitalocean_droplet.droplets[1] will be created
...
# module.groups[2].digitalocean_droplet.droplets[2] will be created
...
# module.groups[2].digitalocean_loadbalancer.www-lb will be created
...
Plan: 12 to add, 0 to change, 0 to destroy.
...

Terraform 在输出中解释说,这三个模块实例中的每一个都关联了三个 Droplet 和一个负载均衡器。.

使用 for_each

当您需要更复杂的实例自定义,或者实例数量取决于编写代码时未知的第三方数据(通常以映射形式提供)时,可以使用 for_each 来遍历模块。.

现在,您需要定义一个映射,将组名称与 droplet 数量配对,并基于此实现 droplet-lb 实例。运行以下命令打开 main.tf 进行编辑:

nano main.tf

按如下方式修改文件:

variable "group_counts" {
type = map
default = {
"group1" = 1
"group2" = 3
}
}
module "groups" {
source = "./modules/droplet-lb"
for_each = var.group_counts
droplet_count = each.value
group_name = each.key
}

首先,定义一个名为 `group_counts` 的映射,其中包含给定组中的 Droplet 数量。接下来,调用 `droplet-lb` 模块,但指定 `for_each` 循环应操作之前定义的映射 `var.group_counts`。`droplet_count` 接受 `each.value` 参数,即当前键值对的值,也就是当前组的 Droplet 数量。`group_name` 接受组名。.

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

请尝试运行以下命令应用配置:

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

输出结果详细展示了 Terraform 创建这两个包含 Droplet 和负载均衡器的组的操作:

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:
# module.groups["group1"].digitalocean_droplet.droplets[0] will be created
...
# module.groups["group1"].digitalocean_loadbalancer.www-lb will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[0] will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[1] will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[2] will be created
...
# module.groups["group2"].digitalocean_loadbalancer.www-lb will be created
...

至此,您已使用 count 和 for_each 从同一代码部署了模块的多个自定义实例。.

结果

在本教程中,您创建并实现了 Terraform 模块。您使用模块将逻辑相关的资源分组在一起,并对其进行自定义,以部署中心代码定义的多个不同实例。您还使用输出来显示模块中资源的属性。.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

您可能也喜欢