Terraform是一个强大的工具,用于在多个云提供商中自动化基础设施的部署和管理。无论你是基础设施即代码的新手,还是想深入了解Terraform,本指南都将为你提供必要的知识和技能,以便在项目中有效地管理基础设施,不管你使用什么技术栈。Terraform是我在工作和个人项目中使用的工具,可以轻松地将应用程序基础设施部署到AWS云上。
基础设施即代码(IaC)
当你已经开始决定将所有应用程序的基础设施需求转移到云端后,下一步是高效地管理和配置该基础设施,这就是基础设施即代码(IaC)发挥作用的地方。IaC允许你使用代码自动创建、配置和管理云资源。这种方法确保了一致性、可重复性和可扩展性,使基础设施管理更加可靠,减少错误。
无论你需要启动一个简单的Web应用程序还是编排一个复杂的多层架构,IaC都能让你轻松定义、部署和管理所有这些。在可用的IaC工具中,Terraform是最受欢迎的,也是最明显的选择。
Terraform简介
Terraform是当今最流行的IaC工具之一,允许你使用统一的语法管理多个云提供商的基础设施。无论你使用的是AWS、Azure、Google Cloud还是本地基础设施,Terraform的声明式语言都能让你以可扩展和可维护的方式定义资源和依赖关系。
安装Terraform
首先,让我们在你的机器上安装Terraform。请按照此文档中的说明进行安装。如果你使用Windows并想通过Chocolatey安装,请以管理员权限运行以下命令安装Chocolatey:
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
安装Chocolatey后,让我们安装Terraform:
choco install terraform
你可以通过在命令行运行terraform --version
来验证安装。
在撰写本文时,最新的稳定版本是1.9.5。我们将主要使用Visual Studio Code编辑器来处理Terraform,因为它为编写此类脚本提供了最佳体验。请确保安装了以下扩展以改善你的开发体验:
- HashiCorp Terraform
这将提供语法高亮、验证和建议等附加功能,使编写terraform文件变得更加顺畅。
Terraform提供者
Terraform提供者就像插件,指示Terraform使用特定的云提供商,如AWS、Azure、GCP等。请注意,使用Terraform也可以实现多云架构。但在本指南中,我们将保持简单。
例如,如果你需要部署AWS S3存储桶,你需要使用AWS Terraform提供者。AWS提供者提供了一组资源,对应于AWS资源,如ECS、VPN等。截至今天,有超过200种AWS服务可用。
首先,创建一个providers.tf
文件,并添加以下内容:
terraform {
required_version = "~> 1.9.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.64.0"
}
}
}
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
Environment = "staging"
Owner = "Mukesh Murugan"
Project = "codewithmukesh"
}
}
}
在terraform块中,我们将定义所需的版本并将其设置为1.9.5,这是terraform的当前最新版本。接下来,我们将定义terraform aws提供者的版本,即5.64.0,这也是aws提供者的最新可用版本。
在provider块中,我们将Area设置为us-east-1
,并提到一些默认标签,这些标签将添加到我们创建的每个资源中。我们将添加Environment、Owner和Project等标签。
这指示Terraform使用AWS作为提供者,并将资源部署到us-east-1
区域。
在Terraform中编写你的第一个S3存储桶
现在我们已经添加了提供者,让我们编写我们的第一个资源,即AWS S3存储桶。创建一个buckets.tf
并添加以下内容:
resource "aws_s3_bucket" "codewithmukesh" {
bucket = "codewithmukesh-bucket"
}
检查这段简单的代码。Terraform中S3存储桶的资源名称是”aws_s3_bucket”,这个特定资源的标识符是”codewithmukesh”。在这个资源块内,我们可以定义支持的S3存储桶属性,如名称和其他配置。你可以通过访问此链接了解此资源支持的其他属性。
以下是步骤:
- 决定创建资源A。
- 你需要了解如何在云上手动创建资源A,以及与之相关的每个细节。
- 导航到Terraform文档,在适当的提供者(在我们的例子中是AWS)下搜索你需要的资源。
- 根据文档进行修改。
**没有开发人员或DevOps工程师会(或被期望)记住每个资源脚本。**相反,文档应该始终被视为唯一的真相来源,因为它们会随着新版本的发布而变化。不要试图记忆terraform资源和语法,只需知道如何从文档中适应它们。
例如,如果我想通过Terraform部署ECS服务,我会参考https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service。
到目前为止,我们已经编写了terraform
资源来部署AWS S3存储桶,但还没有部署它。在此之前,我们需要熟悉Terraform CLI命令和生命周期。
Terraform生命周期和CLI命令
Terraform
遵循特定的生命周期来管理基础设施即代码。以下是关键步骤和相应的CLI命令:
terraform init
此命令初始化Terraform工作目录。它下载必要的提供者插件,将它们安装在本地,并为进一步的命令准备项目。在新的项目目录中或在更改提供者或模块配置后,首先使用此命令。
terraform plan
此命令创建一个执行计划,显示当你应用更改时Terraform将做什么。它比较当前状态与你的期望状态(在.tf文件中定义),并列出达到期望状态所需的操作。这对于分析和调试非常重要。
terraform apply
此命令将计划的更改应用到基础设施。Terraform会在进行实际更改之前提示你批准执行计划。我倾向于使用terraform apply -auto-approve
来跳过提示。但是,请谨慎使用。
terraform show
此命令显示当前状态或保存的计划的详细信息。它在应用更改后用于查看更改。
terraform destroy
此命令销毁在Terraform文件中定义的管理基础设施。当你不再需要资源时使用它。
terraform state
这组命令用于高级状态管理任务,如移动资源、删除资源或操作状态。
terraform fmt
此命令将你的Terraform配置文件格式化为标准样式。
terraform validate
此命令检查配置文件在语法上是否有效并且内部一致。
terraform output
此命令显示配置中定义的输出变量的值。
工作流程
因此,在正常的工作流程中,你会这样部署资源:
- 通过运行
terraform init
初始化Terraform存储库。 - 运行plan命令以查看将修改/添加或删除哪些资源。
terraform plan
- 一旦你对
plan
命令的结果满意,你就会想通过运行terraform apply
命令将这些更改应用到你的实际基础设施。 - 要销毁资源,运行
terraform destroy
命令。
验证Terraform以管理AWS中的资源
现在,有多种方法可以确保Terraform经过身份验证以代表你管理AWS资源。你可以修改providers
块以包含AWS凭证(Secret Key和Access Key),或使用AWS CLI配置文件来确保你的开发机器已通过身份验证。
- 通过提供者块:
provider "aws" {
region = "us-west-2"
access_key = "my-access-key"
secret_key = "my-secret-key"
}
虽然这是一种相当简单的方法,但存在许多安全问题,因为你现在将AWS Secret Key暴露给公众。但是,如果你只是测试东西,而不一定将任何代码推送到版本控制系统(如GitHub或GitLab),你可以使用这种方法。
- AWS CLI配置文件
这是从本地机器使用Terraform的推荐方法。只需使用secret key/access key配置AWS CLI配置文件,并在Terraform中的AWS提供者块中引用AWS配置文件。
provider "aws" {
region = "us-west-2"
profile = "mukesh"
}
在上述情况下,我配置了一个名为mukesh
的AWS CLI配置文件,并在提供者块下引用了它。这允许Terraform CLI使用AWS配置文件配置并验证到AWS以管理资源。你可以从这里了解更多关于AWS CLI配置文件的信息。
部署 S3 存储桶
现在我们已经了解了工作流程会是什么样子,让我们尝试部署我们的第一个 S3 存储桶。
- 首先通过运行
terraform init
来初始化我们的 Terraform 脚本。
这将下载 AWS Provider,并创建一些必要的 terraform 文件,如锁定文件和状态文件。
- 接下来,运行
terraform plan
命令。
执行命令后会显示变更集的详细信息,即将添加/修改或销毁的内容。在我们的例子中,它说 aws_s3_bucket.codewithmukesh 将被创建
,以及其内部属性。
terraform plan
命令用于创建执行计划,本质上是 Terraform 将对基础设施进行的更改的预览。Terraform 检索基础设施的当前状态(从状态文件或实际基础设施),并将其与配置文件中定义的期望状态进行比较。基于比较,Terraform 确定使当前基础设施与期望状态一致所需的操作。这些操作可能包括创建、更新或删除资源。
terraform plan
只生成计划;它不会对基础设施进行任何更改。它只是向你展示建议的更改,让你在应用之前进行审查。
- 一旦你对
terraform plan
的输出感到满意,运行terraform apply
来应用你的基础设施更改。在下一个提示中,输入yes
以确认部署。我通常使用terraform apply -auto-approve
来跳过这个确认提示。
如你所见,S3 存储桶已经配置完成。你也可以在 AWS 管理控制台上交叉检查这一点!
现在我们已经成功通过 Terraform 部署了我们的第一个 AWS 资源,让我们学习 Terraform 中的变量和输出。
Terraform 变量
Terraform 中的变量允许你使配置文件更加灵活和可重用。通过使用变量,你可以参数化诸如资源名称、区域或实例类型等值。这样,你可以避免硬编码值,并且可以轻松修改配置,而无需更改实际的 .tf
文件。
变量类型
Terraform 支持不同类型的变量,例如:
- 字符串: 单行文本。
- 数字: 数值,如整数或浮点数。
- 布尔值: 布尔值(
true
或false
)。 - 列表: 有序的值序列(例如,
["a", "b", "c"]
)。 - 映射: 一组键值对(例如,
{key1 = "value1", key2 = "value2"}
)。
定义变量
变量在 .tf
文件中使用 variable
块定义。让我们通过实施来学习这一点。创建一个名为 variables.tf
的新文件,并添加以下内容:
variable "region" {
description = "要部署资源的 AWS 区域"
type = string
default = "us-east-1"
}
你可以在 Terraform 配置中使用语法 var.{variable_name}
来引用变量。在我们的例子中,使用 region
变量的正确位置是 providers.tf
文件,我们在其中将 region 属性硬编码为 us-east-1
。你可以按如下方式修改 provider 块:
provider "aws" {
region = var.region
default_tags {
tags = {
Environment = "staging"
Owner = "Mukesh Murugan"
Project = "codewithmukesh"
}
}
}
设置变量
有多种方法可以设置变量值:
- 默认值:在变量块中定义,如我们上面所做的那样。
- 命令行标志:使用 -var 选项设置。这可以通过运行
terraform apply -var="region=us-east-1"
来完成。 - 环境变量:使用
TF_VAR_
环境变量。运行export TF_VAR_region="us-east-1"
。 - 变量文件:使用 .tfvars 文件指定变量,并在运行时通过执行
terraform apply -var-file="variables.tfvars"
使用它。
在处理大型 Terraform 基础设施代码时,使用变量文件是我的首选方法。
Terraform 输出
Terraform 中的输出用于从你的配置中提取和显示有用的信息。它们帮助你在 Terraform 创建或更新基础设施后查看关键结果,如资源 ID、端点或连接字符串。
定义输出
你使用配置中的 output 块定义输出。例如,在我们的情况下,只需创建一个新的 output.tf 文件,其中包含以下代码:
output "bucket_name" {
description = "S3 存储桶的名称"
value = aws_s3_bucket.my_bucket.id
}
输出会在 terraform apply
命令完成后立即显示。以下是我应用 Terraform 更改后显示的内容:
你还可以使用 terraform output
命令随时检索输出。
通过利用变量和输出,你可以创建更加动态、可重用和模块化的 Terraform 配置。这提高了基础设施即代码的可维护性和可扩展性。
状态管理
Terraform 使用状态文件来跟踪它管理的资源。状态文件存储有关你的基础设施的元数据,并作为 Terraform 的真实来源。当你运行 terraform plan
或 terraform apply
等命令时,Terraform 会将真实世界的基础设施与状态文件进行比较,以确定需要进行哪些更改。
在terraform 目录中有额外的文件,如 terraform.tfstate
、terraform.tfstate.backup
等。
为什么状态很重要?
- 跟踪资源: Terraform 需要状态文件来将真实资源映射到你的配置。
- 性能: Terraform 使用状态文件来高效计算更改,而不是从云提供商查询每个资源。
- 协作: 在团队工作时,正确管理状态对于确保基础设施更改的一致性至关重要。
使用 S3 和 DynamoDB 的远程后端
默认情况下,Terraform 将其状态文件存储在本地。然而,对于生产环境或团队协作,将状态存储在远程后端中更可靠。最常见的后端之一是 Amazon S3。当你将状态存储在 S3 中时,它可以在团队成员之间共享,并受到保护,避免意外的本地删除。
最常见的选择是将状态存储在 Amazon S3 中,使用 DynamoDB 进行状态锁定,以防止可能损坏状态的并发操作。
使用 S3 和 DynamoDB 设置远程后端
创建 S3 存储桶 首先,在 AWS 中创建一个 S3 存储桶来存储你的 Terraform 状态文件。存储桶应该是私有的,并且应该启用版本控制,以便在状态损坏的情况下进行回滚。我将手动创建一个名为
cwm-tfstates
的新存储桶用于此目的。创建用于状态锁定的 DynamoDB 表 为了防止多个 Terraform 进程同时修改状态,我们使用 DynamoDB 进行状态锁定。DynamoDB 确保一次只能运行一个操作,有助于避免状态损坏。我使用管理控制台创建了一个名为
cwm-state-locks
的新 DynamoDB 表,分区键为LockID
(字符串)。这个表将处理锁定,确保状态的安全并发使用。资源清理 运行
terraform destroy
命令,确保你的资源已清理,并删除terraform.tfstate
文件。在 Terraform 中配置后端: 在你的 Terraform 配置中,使用 backend 块来定义 S3 存储桶作为你的远程后端。创建一个名为
main.tf
的新文件,并添加以下内容:
terraform {
backend "s3" {
bucket = "cwm-tfstates"
key = "demo/beginners-guide/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "cwm-state-locks"
encrypt = true
}
}
- bucket 属性指定存储状态文件的 S3 存储桶。
- key 属性指定存储桶内状态文件的路径和名称。
- region 定义存储桶和 DynamoDB 表所在的位置。
- dynamodb_table 属性确保状态锁定由 DynamoDB 处理。
- encrypt 属性确保状态文件在 S3 中静态加密。
- 初始化后端 在配置中定义后端后,你需要初始化 Terraform 以设置远程后端。这可以通过运行
terraform init
命令来完成。但在此之前,运行terraform destroy
命令确保你的资源已清理,并删除terraform.tfstate
文件。
如图所示,我们的 S3 后端现在已成功配置,并带有 DynamoDB 表。从现在开始,当运行 terraform plan
或 terraform apply
时,terraform 将交叉检查远程后端(s3 和 dynamodb)中存在的状态文件,以决定如何修改资源。每次运行 terraform apply
命令时,S3 上可用的状态文件都会更新。
使用 S3 和 DynamoDB 进行远程状态管理的好处
- 协作:多个团队成员可以访问和修改状态文件而不会发生冲突,这要归功于 S3 中的集中存储和 DynamoDB 中的状态锁定。
- 一致性:状态存储在可靠和安全的远程位置,减少了数据丢失或意外删除的机会。
- 安全性
允许你为状态文件启用加密和版本控制,而 DynamoDB 通过在使用期间锁定状态确保安全的状态操作。 - 审计
中的版本控制使回滚到以前的状态成为可能,使审计基础设施更改和从问题中恢复变得容易。
这种状态管理方法对于生产环境至关重要,在这些环境中,你需要确保你的基础设施得到一致管理,并且不受并发问题的影响。将 S3 和 DynamoDB 结合使用,创建了一个强大的系统来管理和锁定你的 Terraform 状态。
部署 EC2 实例
现在我们已经清楚了所有基本概念,继续做一个小练习,通过 Terraform 部署一个新的 EC2 实例。创建一个名为 ec2.tf
的新文件,并尝试从 terraform 文档中找出所需的代码。你需要添加以下内容:
resource "aws_instance" "demo" {
ami = "ami-066784287e358dad1"
instance_type = "t3.micro"
}
你可以直接从 AWS 管理控制台找到所需的 AMI 和实例类型。为了保持简单和小型,我选择了免费层中可用的最小 EC2 实例。
尝试应用你的 terraform 更改。
如图,我们的 S3 存储桶和 EC2 实例都已部署。
销毁资源
本文到此结束。为了控制你的 AWS 账单,建议销毁你为测试目的创建的资源。运行 terraform destroy
以销毁当前状态下通过 terraform 创建的所有资源。