资源抽象与统一管理:Terraform 核心概念、Provider 配置、资源编排基础
好,我们进入第二章。这一章,我打算聊聊多云环境里最基础、也最绕不开的一个话题——资源抽象。
你想想看,AWS 有 AWS 的写法,Azure 有 Azure 的语法,GCP 又自成一套。如果每个云平台都单独维护一套脚本,那运维团队迟早要崩溃。我个人习惯用 Terraform 来做这件事。它就像一个翻译官,把不同云厂商的 API 差异,统一成一套 HCL 语言。
2.1 Terraform 的核心概念
先说说 Terraform 的几个核心概念。搞懂了这些,后面的编排才能顺起来。
- State(状态):Terraform 会维护一个状态文件,记录你当前管理的所有资源。说白了,它就是 Terraform 的「小本本」,记着哪些资源已经创建了、属性是什么。我在项目中遇到过有人不小心删了 state 文件,结果 Terraform 以为资源不存在,又重新创建了一遍,导致一堆重复资源。嗯,这是个坑。
- Resource(资源):这是你要管理的具体对象,比如一台云服务器、一个数据库实例、一个 DNS 记录。每个资源都有一个类型和名称。
- Module(模块):把一组相关的资源打包起来,方便复用。比如你写了一个「Web 服务器模块」,里面包含了 ECS、安全组、负载均衡器。下次再建同样的环境,直接调用模块就行。
- Provider(提供者):这是 Terraform 和云平台之间的桥梁。每个云厂商都有自己的 Provider。
核心要点:Terraform 的核心思想是「声明式配置」。你告诉它「我要什么」,而不是「怎么去做」。它自己会算出执行计划,然后按顺序创建或更新资源。
2.2 Provider 配置
Provider 配置是 Terraform 的第一步。没有它,Terraform 连云平台的 API 都连不上。
一个典型的 Provider 配置长这样:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
provider "azurerm" {
features {}
}
这里有几个点要注意:
- source:指定 Provider 的来源。官方的一般是
hashicorp/xxx。 - version:锁定版本。我建议不要用
latest,否则哪天 Provider 升级了,你的配置可能就炸了。 - region / features:每个 Provider 有自己的配置参数。AWS 要指定区域,Azure 要开启 features 块。
注意:如果你同时管理多个云平台,记得给每个 Provider 起一个 alias 别名。否则 Terraform 会搞混,不知道用哪个 Provider 去创建资源。
我曾经在一个项目里同时管理 AWS 和阿里云,结果忘了加 alias,Terraform 一直报错说找不到 Provider。排查了半天才发现是这个问题。嗯,细节决定成败。
2.3 资源编排基础
资源编排,说白了就是写 HCL 代码来定义你的基础设施。我习惯把资源编排分成三步:定义资源、配置依赖、执行计划。
2.3.1 定义资源
每个资源块的基本结构是:
resource "资源类型" "资源名称" {
参数1 = 值1
参数2 = 值2
}
举个例子,创建一个 AWS EC2 实例:
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "WebServer"
}
}
这里 aws_instance 是资源类型,web_server 是你在 Terraform 里给这个资源起的名字。注意,这个名字只在 Terraform 内部使用,不会影响云平台上的实际名称。
2.3.2 配置依赖
资源之间经常有依赖关系。比如,你得先创建 VPC,才能在里面创建子网。Terraform 会自动分析依赖关系,但有时候它分析不出来,你就得手动声明。
手动声明依赖用 depends_on:
resource "aws_subnet" "main" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
depends_on = [aws_vpc.main]
}
小技巧:尽量让 Terraform 自动推断依赖关系。只有遇到循环依赖或者隐式依赖时,才用 depends_on。滥用它会让你的代码变得又臭又长。
2.3.3 执行计划
写完了配置,别急着 apply。先跑一遍 terraform plan,看看 Terraform 打算做什么。它会输出一个执行计划,告诉你哪些资源要创建、哪些要修改、哪些要删除。
我每次都会仔细看 plan 的输出。特别是 destroy 操作,一旦误删了生产环境的数据库,那可就麻烦了。我曾经见过有人没看 plan 直接 apply,结果把整个 VPC 给删了……嗯,那场面,相当刺激。
2.4 实战:编排一个简单的 Web 应用
光说不练假把式。我们来写一个完整的例子,编排一个简单的 Web 应用:一台 EC2 实例 + 一个安全组。
# 配置 AWS Provider
provider "aws" {
region = "ap-southeast-1"
}
# 创建安全组
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Allow HTTP and SSH"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# 创建 EC2 实例
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.web_sg.id]
tags = {
Name = "WebServer"
}
}
这个例子很简单,但包含了资源编排的核心要素:Provider 配置、资源定义、隐式依赖(EC2 引用了安全组的 ID)。
跑一下 terraform apply,Terraform 会先创建安全组,再创建 EC2 实例。顺序不会错,因为它已经分析出了依赖关系。
2.5 避坑指南
最后,分享几个我踩过的坑:
- State 文件要妥善保管:最好用远程后端(比如 S3、Terraform Cloud)存储 state 文件。别放在本地,否则换台电脑就找不到了。
- Provider 版本要锁定:用
version参数固定版本,避免意外升级导致配置不兼容。 - 不要手动修改云平台上的资源:如果你在 AWS 控制台手动修改了某个资源,Terraform 下次 apply 时会尝试把它改回来。这就是所谓的「配置漂移」。我曾经因为这个,半夜被报警电话吵醒……
- 先 plan,再 apply:这个习惯一定要养成。plan 是你的安全网。
总结一下:Terraform 的核心就是「声明式配置 + 状态管理」。Provider 是连接云平台的桥梁,资源编排是定义基础设施的蓝图。掌握了这些,你就能在多云环境中游刃有余地管理资源了。
下一章,我们会深入 Terraform 的状态管理和远程后端。到时候聊聊怎么多人协作、怎么避免状态冲突。嗯,那才是真正的实战。