Terraform 基础 – 第6周:构建和使用你的第一个 Terraform 模块

发布: (2025年12月8日 GMT+8 05:41)
7 min read
原文: Dev.to

Source: Dev.to

前几周回顾

在过去的五周里,我们在学习 Terraform 核心概念的同时,构建了一个小而真实的 Azure 环境。我们先部署了第一台虚拟机(VM),随后引入了变量和 tfvars 文件,使配置更加灵活。我们通过网络安全组(NSG)和动态块添加了安全性,最后通过输出值(output)公开了有用的信息。

下面是我们目前基础设施的可视化表示:

Infrastructure

Visual Studio Code 中的文件夹结构:

Folder Structure

项目文件夹中的关键文件

  • nsg.tf – 网络安全组及其关联。
  • outputs.tf – 输出值。
  • providers.tf – AzureRM 提供程序块。
  • resource-group.tf – 资源组定义。
  • terraform.tfvars – 项目变量值。
  • variables.tf – 变量定义。
  • virtual-machine.tf – 虚拟机和网络接口卡(NIC)资源。
  • virtual-network.tf – 虚拟网络和子网资源。

此时我们已经拥有一个完整可用、参数化且安全的 VM 部署。随着配置的增长,重复的模式变得显而易见,使得管理多个相似资源变得困难。这正是引入 Terraform 模块的最佳时机。

前几周

系列的 GitHub 仓库:

什么是 Terraform 模块,为什么在 Terraform 中使用模块?

Terraform 模块是一组资源的集合,能够作为单个单元重复使用。与其为每次部署都重新编写相同的 VM、NIC 或 NSG 块,我们只需在模块内部定义一次,然后在需要新实例时调用该模块。

包含主 Terraform 文件的文件夹是 根模块。任何包含 .tf 文件的子文件夹都成为 子模块,且不能单独运行。根模块提供输入,子模块返回输出。这种关系实现了基础设施模式的清晰复用,而无需复制代码。

在真实环境中,模块是必不可少的。想象一个团队需要在开发、预发布和生产环境中管理十台 VM。如果不使用模块,每个环境都会拥有一份相同资源块的副本。一次简单的更改——比如更新标签或调整 NSG 规则——必须在多个地方重复执行,导致漂移并增加维护工作量。

通过将逻辑集中在模块中,我们可以实现:

  • 环境之间的一致性。
  • 减少重复。
  • 更容易的维护和基础设施扩展。

理解模块的输入和输出

模块输入

输入是模块创建资源所需的值。它们在模块内部被定义为变量,根模块在调用模块时提供实际值。对于 VM 模块,典型的输入包括:

  • 资源组名称和位置
  • 子网 ID
  • VM 大小
  • 管理员凭证
  • NIC 设置
  • 允许的端口

模块输出

输出将子模块内部的值暴露给根模块。这样根配置就可以使用模块内部创建的信息,而无需直接访问其内部资源。常见的 VM 模块输出有:

  • VM ID
  • NIC 名称
  • 私有 IP 地址

这些输出可以在配置的其他位置引用,或在部署后显示。

创建我们的第一个 Terraform 模块

注意: 这是一种将已有代码重构为可复用模块的做法,而不是从零构建模块。它映射了真实场景中将一组资源转化为可复用组件的常见过程。

我们将把 VM、NIC 和 NSG 资源移动到 modules/vm 文件夹,同时保留根配置中的资源组、虚拟网络和子网。现有的 variables.tfoutputs.tfterraform.tfvars 仍然保留在根目录,并继续为模块提供值。

步骤 1:创建模块文件夹结构

modules/
└── vm/
    ├── main.tf
    ├── variables.tf
    └── outputs.tf

File Structure

步骤 2:在模块中填充 main.tf

将原始 virtual-machine.tfnsg.tf 文件中的虚拟机、NIC、NSG 以及 NSG 关联资源块复制到 modules/vm/main.tf 中。

Main.tf

(图片展示了复制的资源定义。)

步骤 3:定义模块变量

modules/vm/variables.tf 中声明模块所需的所有输入(例如 resource_group_namesubnet_idvm_size 等)。使用与根配置中先前定义的变量名称和类型保持一致。

步骤 4:定义模块输出

modules/vm/outputs.tf 中暴露有用的值,如 VM ID、NIC 名称和私有 IP 地址。

步骤 5:在根配置中调用模块

在根文件夹中添加一个 module 块(例如在 main.tf 或专门的 vm-module.tf 文件中),引用新模块并传递所需变量:

module "vm" {
  source = "./modules/vm"

  resource_group_name = var.resource_group_name
  location            = var.location
  subnet_id           = azurerm_subnet.main.id
  vm_size             = var.vm_size
  admin_username      = var.admin_username
  admin_password      = var.admin_password
  allowed_ports       = var.allowed_ports
}

根目录中现有的 outputs.tf 现在可以引用模块的输出,例如:

output "vm_private_ip" {
  value = module.vm.private_ip
}

有了模块,整体配置仍然保持功能完整,同时获得了复用性和更易维护的优势。

Back to Blog

相关文章

阅读更多 »

第7天 – Terraform中的类型约束

在第5天,我们看到了变量的实际使用。今天我们深入探讨 Terraform 中的类型约束。Primitive Types(原始类型)是基本构建块:str...

AWS Terraform 生命周期规则

介绍 基础设施即代码(IaC)在您能够完全控制资源在更新、替换和删除过程中的行为时最为强大。Terr…

Terraform 数据源 (AWS)

Terraform 数据源是什么?Terraform 中的数据源是对现有资源的只读查找。Terraform 并不是创建新资源,而是查询…