Terraform 初学者教程:从第一个文件到模块的基础设施即代码

  1. 首页
  2. 博客
  3. 开发运营

开发运营

Terraform 初学者教程:从第一个文件到模块的基础设施即代码

无需云帐户或意外账单即可学习 Terraform。从本地文件开始了解计划、应用和状态,然后转向真正的云资源、模块和对团队安全的工作流程。

阅读约 10 分钟
面向初学者的 Terraform 教程:从第一个文件到模块的基础设施即代码

要点速览

  • Terraform 从可保存在 Git 中的文本文件创建和更改基础架构。
  • 核心工作流程是 init、plan、apply 和 plan 在更改发生之前显示更改。
  • 状态文件记录 Terraform 管理的内容。保护它,并且永远不要将其提交到 Git。
  • 在团队中工作时,使用 modules 重用模式和锁定远程状态。

对于一台服务器来说,在云控制台周围单击就可以了。当您在暂存和生产中需要相同的设置时,或者当有人询问谁在去年三月更改了防火墙规则时,它就会崩溃。这个 Terraform 初学者教程 向您展示了一种更好的方法:用代码描述您的基础设施,并让工具使其成为现实。

大多数教程都是从云帐户开始,这会在您学到任何东西之前增加计费风险。我们从 Terraform 的 local 提供程序开始,它只是在您的计算机上创建文件,因此错误不会造成任何损失。这些示例和示例输出是标准插图,我们没有为本文执行这些示例,确切的措辞因版本而异。

什么是 Terraform?

Terraform 是 HashiCorp 的基础设施即代码 (IaC) 工具。您可以使用 HCL(HashiCorp 配置语言)编写配置文件,描述您想要的最终结果。然后,Terraform 计算出要创建、更改或删除哪些内容才能实现这一目标。

它通过名为 providers 的插件与平台进行通信。有适用于 AWS、Azure、Google Cloud、Kubernetes、GitHub、Cloudflare 等的提供商,因此您可以在所有这些提供商之间使用一种工作流程。

需要知道的一件事是:2023 年,HashiCorp 将 Terraform 移至商业源代码许可证。随后,社区创建了 OpenTofu,这是一个使用非常相似的命令和配置的开源分支。您在这里学到的内容很大程度上适用于两者。

为什么基础设施即代码?

问题 手动控制台工作 地形
谁改变了什么? 很难找到 Git 历史记录
我们可以将舞台复制到生产中吗? 小心点击 重用代码
这个改变会起到什么作用? 事后你会发现 terraform plan 首先向您展示
有人可以评论一下吗? 不容易 一个正常的拉取请求
灾难恢复 取决于人的记忆力 从代码重新创建,加上数据备份

Terraform 也是声明性的。您说“应该有三个服务器”,而不是“创建一个服务器,三次”。如果已经存在两个,则添加一个。一个简单地重复其步骤的脚本最终可能会创建另外三个步骤。

安装 Terraform

使用适用于您的操作系统的 HashiCorp 官方说明安装它,然后确认它是否有效:

terraform -version

为项目创建一个空文件夹。 Terraform 读取当前文件夹中的每个 .tf 文件,因此一个文件夹等于一个配置。

您的第一个配置

创建一个名为main.tf的文件:

terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}

resource "local_file" "greeting" {
  filename = "${path.module}/hello.txt"
  content  = "Hello from Terraform\n"
}

查看 resource 块,因为您编写的几乎所有内容都遵循此形状。 local_file 是资源类型,greeting 是您在配置中为其指定的名称。它们共同构成其地址:local_file.greeting。里面的参数描述了你想要什么。

工作流程:初始化、计划、应用

地形初始化

这将准备文件夹并下载您所需的提供程序。在开始时运行一次,并在添加提供程序或模块时再次运行。它还创建一个 .terraform.lock.hcl 文件,其中记录了确切的提供程序版本。将该文件提交到 Git。

terraform init

地形计划

这会将您的代码与现有代码进行比较并显示计划的更改,而不触及任何内容:

terraform plan

# local_file.greeting will be created
+ resource "local_file" "greeting" {
    + content  = "Hello from Terraform\n"
    + filename = "./hello.txt"
  }

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

学习符号,因为你会读到很多计划:

符号 含义
+ 创建
~ 更新到位
- 摧毁
-/+ 摧毁并重建

地形应用

这会再次显示计划,要求确认并进行更改:

terraform apply

输入 yes,然后出现 hello.txt。现在再次运行terraform plan。它应该报告没有任何更改,因为现实已经与您的代码匹配。重复运行该属性不会导致进一步的更改,该属性称为幂等性。

改变与破坏

编辑 content 行并运行 terraform plan。 Terraform 发现了差异并提出了更改。对于此资源,它会替换文件。请注意实际基础设施上的替换,因为重新创建数据库可能意味着丢失数据。

接下来,手动删除hello.txt并重新规划。 Terraform 注意到它丢失并提出重新创建它。代码与现实之间的差异称为漂移,检测它是该工具的主要优点之一。

要删除此配置管理的所有内容,请运行:

terraform destroy

变量和输出

硬编码值会阻止您重用代码。输入变量使配置灵活,输出报告有用的值:

# variables.tf
variable "environment" {
  type        = string
  description = "Deployment environment"
  default     = "dev"

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Use dev, staging or prod."
  }
}

# main.tf
resource "local_file" "config" {
  filename = "${path.module}/${var.environment}.txt"
  content  = "environment=${var.environment}\n"
}

# outputs.tf
output "config_path" {
  value = local_file.config.filename
}

在命令行上设置值,或将它们保存在名为 terraform.tfvars 的文件中,该文件会自动加载:

terraform apply -var="environment=staging"

在输出中使用 local_file.config.filename 也是资源相互引用的方式。 Terraform 读取这些引用来确定创建事物的正确顺序。

地形状态

申请后,你会发现一个名为terraform.tfstate的文件。这是 Terraform 对其管理内容的记录,将您的代码映射到真实对象。如果没有它,Terraform 将不知道 local_file.greeting 是该特定文件。

这里有三个规则很重要:

  1. 永远不要向 Git 提交状态。它可以以纯文本形式包含密码和其他秘密。
  2. 请勿手动编辑。使用terraform state list和terraform state mv等命令。
  3. 为团队项目使用远程后端。共享后端集中存储状态并锁定它,因此两个人不能同时申请。

以下是使用 Amazon S3 的典型后端,其中包含您提前创建的存储桶:

terraform {
  backend "s3" {
    bucket       = "my-company-terraform-state"
    key          = "shop/prod/terraform.tfstate"
    region       = "ap-south-1"
    encrypt      = true
    use_lockfile = true
  }
}

提示: 每个项目都以 .gitignore 开始,不包括 .terraform/、*.tfstate、*.tfstate.* 和任何包含机密的 *.tfvars 文件。

真正的云资源

当您迁移到云时,工作流程不会改变。这是 AWS 上的 S3 存储桶。首先检查定价,并销毁你在练习时创建的任何东西:

provider "aws" {
  region = "ap-south-1"
}

resource "aws_s3_bucket" "reports" {
  bucket = "my-unique-reports-bucket-2026"

  tags = {
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

Terraform 从您的 AWS CLI 设置或环境变量获取凭证。切勿将访问密钥写入 .tf 文件。

模块

模块只是 Terraform 文件的文件夹,您可以使用不同的输入调用它们。它的工作原理很像一个函数,让您定义一次模式并重用它:

project/
  main.tf
  modules/
    reports_bucket/
      main.tf
      variables.tf
      outputs.tf
module "staging_reports" {
  source      = "./modules/reports_bucket"
  environment = "staging"
}

module "prod_reports" {
  source      = "./modules/reports_bucket"
  environment = "prod"
}

公共 Terraform 注册表也有现成的模块,但在依赖它们之前请先阅读它们,并固定版本。不要过早构建模块。等到您将某个模式重复至少两次。

安全的团队工作流程

  1. 创建一个分支并更改 .tf 文件。如果您需要复习,请参阅我们的 Git 初学者教程 。
  2. 运行 terraform fmt 和 terraform validate。
  3. 打开拉取请求,并附上 terraform plan 的输出以供审核。
  4. 批准后,从一个受控位置(最好是管道)应用保存的计划。

保存计划可确保您准确应用已审核的内容:

terraform plan -out=tfplan
terraform apply tfplan

这自然适合 CI/CD 和 GitHub Actions。 Terraform 通常会配置集群,然后 Kubernetes 等工具在其上运行应用程序。

常见错误

  • 在不阅读计划的情况下进行申请。 在数据库上进行-/+ 可能会带来非常昂贵的意外。
  • 在一台笔记本电脑上保留状态。 丢失该笔记本电脑,Terraform 就会失去对您的基础设施的跟踪。
  • 手动进行控制台更改。它们会导致漂移,下一次应用可能会撤消它们。
  • 使用未固定的版本。固定提供程序和模块版本,以便有目的地进行升级。
  • 使用一个庞大的配置。按环境或系统进行拆分可以限制任何错误的损害。

最后的话

您现在已经了解了几乎所有 Terraform 工作背后的想法:声明资源、审查计划、应用计划和保护状态。与 local 提供商一起练习,直到工作流程感觉自然,然后在免费帐户中管理一小部分实际资源。一旦涉及多个人或多个环境,就引入远程状态和模块。

常见问题

Terraform 有何用途?

Terraform 用于通过用代码描述而不是手动配置来创建和管理基础设施,例如服务器、网络、数据库和 DNS。

Terraform 是免费的吗?

Terraform CLI 可以根据其商业源许可证免费使用,但条款限制了一些竞争性商业用途。 HCP Terraform 具有付费等级,而 OpenTofu 是开源的。

Terraform 和 Ansible 之间有什么区别?

Terraform 主要以声明方式提供基础设施。 Ansible 主要在现有机器上配置软件。许多团队都使用这两种方法,先使用 Terraform,然后使用 Ansible。

什么是 Terraform 状态文件?

它是将您的配置映射到实际资源的记录。 Terraform 使用它来计算更改。它可以保存秘密,因此请安全地存储它并远离 Git。

我需要了解编程才能学习 Terraform 吗?

并不真地。 HCL 简单且具有声明性。了解您管理的平台(例如 AWS 网络)通常比语言本身更难。

继续学习

与Stack Quora合作

需要测试、WordPress 或 SEO 方面的帮助?

我们帮助团队交付更好的软件并发展他们的网站。告诉我们您正在做什么,我们将建议明确的下一步。

继续阅读

更多指南 测试、人工智能和现代开发

喜欢这篇文章吗?选择一个主题并直接跳至我们最新的教程。

人工智能

人工智能幻觉解释:语言模型为何会产生幻觉以及如何减少它

人工智能幻觉解释:它们是什么,为什么语言模型产生它们,常见类型,如何通过基础和提示来减少它们,以及我们进行的简单检查。

阅读文章 →
DevOps

环境变量解释:.env 文件、秘密和配置正确完成

使用我们运行的 Python 示例解释环境变量:读取和设置它们、为什么每个值都是字符串、.env 文件、进程继承、秘密和验证。

阅读文章 →
软件开发

API 速率限制解释:算法、标头和处理 429 错误

API 速率限制通过我们运行的模拟进行了解释:令牌桶、固定窗口、滑动窗口、429 响应、速率限制标头、带回退的重试和测试限制。

阅读文章 →
测试自动化

Python 中的模拟:unittest.mock、补丁以及导致测试谎言的错误

使用unittest.mock 在Python 中进行模拟,经过测试:模拟和return_value、side_effect、修补使用名称的位置、spec 和autospec、模拟日期以及常见错误。

阅读文章 →
软件测试

代码覆盖率解释:行覆盖率与分支覆盖率以及 100% 的真正含义

用真实的coverage.py运行来解释代码覆盖率:行、分支和条件覆盖率,阅读报告,为什么100%覆盖率仍然会错过错误,以及合理的目标。

阅读文章 →
数据库与 SQL

SQL 中的 DELETE、TRUNCATE 和 DROP:差异、回滚以及何时使用它们

DELETE、TRUNCATE 和 DROP 通过经过测试的 SQL 进行了解释:各自删除什么、回滚、触发器、身份重置、速度,以及 PostgreSQL、MySQL、SQL Server 和 SQLite 有何不同。

阅读文章 →
数据库与 SQL

SQL 视图解释:创建、使用和避免陷阱(附示例)

SQL 视图通过我们运行的查询进行解释:创建视图、实时结果、隐藏列、性能、可更新和物化视图、破坏的依赖关系和最佳实践。

阅读文章 →
软件开发

TypeScript 接口与类型:真正的差异,使用编译器进行测试

TypeScript 接口与类型,使用真实编译器进行检查:两者都可以做什么,只有一个可以做什么,声明合并,扩展与交集以及要遵循的简单规则。

阅读文章 →
软件开发

Python *args 和 **kwargs 解释:灵活的函数和清晰的示例

Python *args 和 **kwargs 用我们运行的代码进行了解释:打包和解包、参数顺序、仅关键字和仅位置参数、装饰器和常见错误。

阅读文章 →
软件开发

Python Lambda 函数:语法、实际用途以及何时不使用它们

Python lambda 函数用我们运行的代码进行了解释:语法、使用键排序、映射和过滤器、闭包、后期绑定陷阱,以及何时普通 def 是更好的选择。

阅读文章 →
人工智能

什么是人工智能代理?它们是如何工作的,只需运行一个简单的代理循环

什么是人工智能代理?关于代理循环、工具、内存和护栏的简单指南,以及我们运行的一个小型 Python 循环、真正的风险以及何时简单的聊天机器人是更好的选择。

阅读文章 →
DevOps

监控与可观察性:真正的区别,包括日志、指标和跟踪

监控与可观察性解释:已知和未知的故障、日志、指标和跟踪、检查事件演练、黄金信号、OpenTelemetry 和有用的警报。

阅读文章 →
DevOps

Docker Volumes 与 Bind Mounts:以正确的方式保留容器数据

Docker 卷与绑定挂载解释:为什么容器数据消失、命名卷、绑定挂载、tmpfs、Compose 示例、备份、权限以及何时使用它们。

阅读文章 →
测试自动化

TDD 与 BDD:主要区别、以两种方式构建的一个功能以及何时使用每种方式

TDD 与 BDD 的解释是通过一种双向构建的折扣功能:使用我们运行的代码进行红绿重构、Given-When-Then 场景、工具、权衡以及何时使用每种方案。

阅读文章 →
软件测试

用户验收测试 (UAT):流程、清单和真实示例

用户验收测试解释:谁运行它、它与 QA 有何不同、七步流程、UAT 测试用例模板、清单、签核标准和常见错误。

阅读文章 →
数据库与 SQL

SQL NULL 值解释:IS NULL、COALESCE、NULLIF 和要避免的陷阱

通过我们运行的查询解释了 SQL NULL 值:三值逻辑、IS NULL、COALESCE、NULLIF,聚合、连接和排序如何处理 NULL,以及它悄悄引起的错误。

阅读文章 →
数据库与 SQL

SQL CASE WHEN 语句:语法、实例和常见错误

SQL CASE WHEN 解释了我们运行的查询:简单和搜索表单、条件顺序、SUM 透视、COUNT 技巧、自定义排序、更新和要避免的 NULL 陷阱。

阅读文章 →
软件开发

什么是智威汤逊?通过工作示例解释 JSON Web 令牌

什么是智威汤逊? JSON Web Tokens 解释:这三个部分,在我们运行的代码中构建和篡改的令牌,JWT 与会话,存储,刷新令牌和安全错误。

阅读文章 →
软件开发

JavaScript 事件循环解释:调用堆栈、微任务和计时器以及示例

JavaScript 事件循环用我们运行的代码进行了解释:调用堆栈、任务和微任务队列、为什么 setTimeout 0 不是立即执行、阻塞、饥饿和面试测验。

阅读文章 →
软件开发

Python 生成器和 Yield 解释:通过真实示例节省内存

Python 生成器和yield 用我们运行的代码进行了解释:它们如何暂停和恢复、测量内存节省、管道、无限序列、yield from、发送和常见陷阱。

阅读文章 →
人工智能

什么是嵌入?向量和余弦相似度简单解释

什么是嵌入?关于向量、余弦相似度和语义搜索的简单语言指南,其中包含我们运行的一个小示例、常见用途、选择模型和已知限制。

阅读文章 →
DevOps

蓝绿部署与金丝雀部署:差异、权衡以及如何选择

蓝绿部署与金丝雀部署解释:每种部署的工作原理、成本、风险和回滚、我们测试的稳定用户分桶、数据库迁移、滚动更新以及如何选择。

阅读文章 →
测试自动化

不稳定的测试:造成这些问题的原因以及如何彻底解决它们

我们运行的演示解释了不稳定的测试:主要原因、如何确认和诊断、正确的时间修复、共享状态和日期以及隔离过程。

阅读文章 →
软件测试

负载测试与压力测试:差异、指标和 k6 示例

负载测试与压力测试的解释:各自证明什么、峰值和浸泡测试、重要的指标、为什么平均值会误导、k6 个示例以及如何计划测试。

阅读文章 →
软件测试

测试用例与测试场景:主要区别、示例以及何时使用它们

测试用例与测试场景的解释:清晰的定义、并排的表格、从场景到案例的密码重置功能、模板以及何时使用每个功能。

阅读文章 →
数据库与 SQL

SQL 查询优化:读取执行计划并修复慢速查询(带计时)

对一百万行进行 SQL 查询优化测试:读取执行计划、添加正确的索引、修复不可控制的过滤器、使用复合索引和键集分页。

阅读文章 →
数据库与 SQL

SQL UNION 与 UNION ALL:差异、示例和性能测试

SQL UNION 与 UNION ALL 通过我们运行的查询进行了解释:重复、都遵循的规则、真实的数据错误、测量的性能、INTERSECT 和 EXCEPT 以及何时使用它们。

阅读文章 →
软件开发

JavaScript Fetch API 教程:GET、POST、错误处理和超时

针对本地服务器测试的 JavaScript Fetch API 教程:GET 和 POST、为什么不抛出 404、可重用的帮助程序、查询字符串、超时、CORS 和常见错误。

阅读文章 →
软件开发

Python 文件处理:读取、写入、CSV、JSON 和 pathlib 以及示例

使用我们运行的代码解释了 Python 文件处理:打开模式、使用、读取大文件、CSV、JSON、pathlib、二进制文件、安全写入、错误处理和常见错误。

阅读文章 →
软件开发

Python 类和对象:带有实际示例的 OOP 教程

用我们运行的代码解释 Python 类和对象:__init__、方法、类与实例属性、继承、属性、dunder 方法、数据类和常见错误。

阅读文章 →
人工智能

什么是大语言模型?法学硕士如何运作,在没有炒作的情况下进行解释

什么是大语言模型?法学硕士用简单的语言解释:标记、嵌入、注意力、训练、温度和上下文窗口、一个微小的下一个单词演示和真正的限制。

阅读文章 →
DevOps

适合初学者的 Linux 命令:带有示例的基本终端指南

适合初学者的 Linux 命令,按任务分组:导航、文件、查看日志、grep、管道、权限、进程和档案,并附有实用的日志分析示例。

阅读文章 →
测试自动化

Selenium 与 Playwright:主要区别、代码比较以及选择

Selenium 与 Playwright 比较:架构、等待、浏览器和语言支持、调试、两种工具中的相同测试、迁移建议以及如何选择。

阅读文章 →
软件测试

等价划分:通过实例解释测试设计技术

等效分区解释:如何找到有效和无效分区,年龄、密码和优惠券的工作示例,我们运行的测试,以及为什么将其与边界配对。

阅读文章 →
软件测试

软件测试中的严重性与优先级:差异、矩阵和实例

软件测试中的严重性与优先级解释:清晰的定义、带有示例的四向矩阵、级别尺度、谁设置每个级别以及如何运行错误分类。

阅读文章 →
数据库与 SQL

SQL 子查询教程:类型、相关子查询和 EXISTS 以及示例

SQL 子查询教程,其中包含我们运行的查询:标量、IN、FROM 和 SELECT 子查询、相关子查询、EXISTS、NOT IN NULL 陷阱以及子查询与 JOIN 与 CTE。

阅读文章 →
数据库与 SQL

SQL 事务和 ACID 解释:COMMIT、ROLLBACK 和隔离级别

SQL 事务和 ACID 通过我们运行的银行转账进行了解释:COMMIT、ROLLBACK、保存点、锁、隔离级别、脏读、死锁和最佳实践。

阅读文章 →
软件开发

Git 命令备忘单:您实际使用的命令,以及示例

Git 命令备忘单按任务分组:设置、暂存、分支、远程、存储、历史记录和撤消错误,以及来自真实演示存储库的输出。

阅读文章 →
软件开发

JavaScript Promise 解释:then、catch、Promise.all 和常见错误

JavaScript 承诺用我们运行的代码进行了解释:状态、then 和 catch 链、错误处理、Promise.all、allSettled、race 和 any、事件循环和常见错误。

阅读文章 →
软件开发

Python 字典教程:方法、示例和常见模式

Python 字典教程,包含我们运行的代码:创建、读取和更新字典、关键方法、合并、理解、计数和分组模式以及常见错误。

阅读文章 →
人工智能

什么是 RAG?通过工作示例解释检索增强生成

什么是RAG?检索增强生成逐步解释:索引、分块、嵌入、检索、一个小型的 Python 工作示例、评估和常见故障。

阅读文章 →
DevOps

Terraform 初学者教程:从第一个文件到模块的基础设施即代码

适合初学者的 Terraform 教程:从没有云帐户开始,学习初始化、计划和应用,然后是变量、输出、状态、模块和安全的团队工作流程。

阅读文章 →
DevOps

Docker 与 Kubernetes:主要区别、它们如何协同工作以及您需要哪些

Docker 与 Kubernetes 的解释:各自的作用、同一个应用程序同时运行、Docker Compose 和 Swarm 的比较、dockershim 的变化以及如何决定您需要什么。

阅读文章 →
测试自动化

Pytest 初学者教程:夹具、参数化和真实示例

面向初学者的 pytest 教程,其中包含我们在 pytest 9.2 上运行的测试:断言、固定装置、参数化、conftest、标记、tmp_path、monkeypatch、有用的标志和 CI。

阅读文章 →
软件测试

软件测试生命周期 (STLC):6 个阶段、进入和退出标准、示例

软件测试生命周期解释:六个 STLC 阶段,包括进入和退出标准、可交付成果、有效的登录功能示例、STLC 与 SDLC 以及敏捷中的 STLC。

阅读文章 →
软件开发

Git merge 与 rebase 的区别:示例及如何选择

用真实的 log 输出、对比表、rebase 黄金法则和安全的团队工作流,讲清 Git merge 与 rebase 的区别。

阅读文章 →
软件开发

Python 列表推导式:语法、示例与何时避免使用

Python 列表推导式详解:语法、过滤、if-else、嵌套循环、实测耗时,以及何时普通 for 循环更合适。

阅读文章 →
数据库与 SQL

SQL JOIN 详解:附示例(INNER、LEFT、RIGHT、FULL)

通过示例表和查询,一步步讲解 SQL JOIN:INNER、LEFT、RIGHT、FULL、CROSS 和 SELF,并介绍常见错误与性能技巧。

阅读文章 →