安装与快速上手
安装
Terraform 本体是单个二进制文件,安装方式很多,挑顺手的来。
macOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
直接 brew install terraform 装到的是 homebrew-core 里停留在 1.5.x 的旧版(许可变更前的最后一个 MPL 版本)。想用当前版本,走上面的 HashiCorp 官方 tap。
官网下载(macOS / Linux 通用)
到官网下载页拿对应平台的 zip,解压后把二进制放进 PATH:
# 以 Linux amd64 为例,版本号换成当时最新的
curl -LO https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_linux_amd64.zip
unzip terraform_1.9.8_linux_amd64.zip
sudo mv terraform /usr/local/bin/
macOS 在同一下载页选 darwin 包即可,步骤一样。
Linux 包管理器
# Ubuntu / Debian(HashiCorp 官方源)
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install -y terraform
# RHEL / CentOS / Fedora
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/fedora/hashicorp.repo
sudo dnf install -y terraform
用 tfenv 管多版本(推荐)
和 Node 的 nvm 一个思路:不同项目可能锁定不同的 Terraform 版本,tfenv 让你按目录切换。这类版本管理工具的安装思路和坑(镜像加速、目录自动切换)在 nvm 安装与镜像加速 里写过,可以对照着看。
# macOS
brew install tfenv
# 装一个指定版本并设为默认
tfenv install 1.9.8
tfenv use 1.9.8
# 项目目录放一个 .terraform-version 文件,进入目录自动切换
echo "1.9.8" > .terraform-version
验证
terraform version
Terraform v1.9.8
on darwin_arm64
第二行的 darwin_arm64 表示这是 Apple Silicon 的原生 arm64 构建;Intel Mac 显示 darwin_amd64,Linux 对应 linux_amd64 / linux_arm64。
第一个练习:local_file
第一个练习不碰任何云账号,用 hashicorp/local 这个官方 provider 在本机生成一个文件,把完整工作流跑一遍。
新建一个空目录,写一个 main.tf:
terraform {
required_version = ">= 1.9"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
resource "local_file" "hello" {
filename = "${path.module}/hello.txt"
content = "Hello from Terraform!\n"
}
逐块说明:
terraform块:整个配置的元信息。required_version限定 Terraform 本体版本;required_providers声明要用哪个 provider 及版本约束,hashicorp/local表示 registry 上 hashicorp 命名空间下的 local provider。resource块:声明一个资源。local_file是资源类型,hello是这个实例的名字,合起来的完整地址是local_file.hello。${path.module}是 HCL 插值,代表「当前模块所在目录」,所以filename最终就是当前目录下的hello.txt。
Terraform 命令要在 main.tf 所在目录执行,它会把当前目录所有 .tf 文件拼成一份完整配置。一个目录就是一套环境,别在一个目录里混两套互不相关的资源。
四步流程实操
第一步:terraform init
terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/local versions matching "~> 2.5"...
- Installing hashicorp/local v2.5.3...
- Installed hashicorp/local v2.5.3 (signed by HashiCorp)
Terraform has been successfully initialized!
init 做了三件事:
- 初始化 backend:决定 state 存哪里,默认本地文件,输出里第一行就是这一步。
- 下载 provider:按
required_providers的约束去 registry 找匹配版本,装进当前目录的.terraform/缓存目录。这个目录不进 git。 - 生成锁文件:
.terraform.lock.hcl记录每个 provider 的精确版本和校验哈希,保证团队所有人和 CI 下载到的是同一份插件。
第二步:terraform plan
terraform plan
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:
# local_file.hello will be created
+ resource "local_file" "hello" {
+ content = "Hello from Terraform!\n"
+ directory_permission = "0777"
+ file_permission = "0777"
+ filename = "./hello.txt"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
逐行解读:
+ create说明本计划里只有新建动作。Terraform 的符号约定:+新建、-删除、~原地修改、-/+先删后建(替换)。will be created加上每行属性前的+前缀,表示这些值即将被写入。(known after apply)表示这个值(这里是资源 id)要等真正创建后才知道。- 结尾的汇总
1 to add, 0 to change, 0 to destroy是最该扫一眼的一行:数字符合预期再继续,不符合就回头查配置。
plan 不改动任何真实资源,可以放心随便跑。养成「apply 前先 plan 看一遍」的习惯,它是你和生产事故之间的最后一道防线。
第三步:terraform apply
terraform apply
输出和 plan 相同,结尾多一个交互确认:
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
local_file.hello: Creating...
local_file.hello: Creation complete after 0s [id=46d27a1cd59c6b3f1f1298dd8a667232a1f2fe08]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
输入 yes 回车后真正执行。此时目录下多了两样东西:
hello.txt:练习的目标产物,cat一下就是那句Hello from Terraform!。terraform.tfstate:state 文件,Terraform 的账本,下一节细说。
CI 等自动化场景没人敲 yes,用 terraform apply -auto-approve 跳过确认——前提是这个 plan 已经被人 review 过。
第四步:terraform destroy
练完回收:
terraform destroy
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
Enter a value: yes
local_file.hello: Destroying... [id=46d27a1cd59c6b3f1f1298dd8a667232a1f2fe08]
local_file.hello: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.
hello.txt 被删除,state 随之清空。destroy 同样有确认交互,同样支持 -auto-approve。
认识 state
看一眼 terraform.tfstate 里记了什么(删减后):
{
"version": 4,
"terraform_version": "1.9.8",
"resources": [
{
"mode": "managed",
"type": "local_file",
"name": "hello",
"provider": "provider[\"registry.terraform.io/hashicorp/local\"]",
"instances": [
{
"attributes": {
"content": "Hello from Terraform!\n",
"filename": "./hello.txt",
"id": "46d27a1cd59c6b3f1f1298dd8a667232a1f2fe08"
}
}
]
}
]
}
本质是一张映射表:「配置里的 local_file.hello」对应「现实里 id 为 xxx 的那个文件」,外加属性快照。下次 plan 时 Terraform 拿着它和现实对比,才知道该增改删什么。
由此引出两条铁律:
- 不能删:删了 state,Terraform 就「失忆」了——文件还在磁盘上,但它不知道那是自己管的,plan 会当成全新资源再建一遍。放到云资源场景,这就是「配置里没有、现实里一堆」的孤儿资源事故。
- 不能绕过 Terraform 手改资源:直接改了现实资源(比如手工删掉 hello.txt),state 和现实就对不上了。下次 plan 会检测到漂移并试图拉回配置描述的状态——这是特性,但理解不了就会觉得「行为诡异」。
state 里可能存敏感信息(数据库密码、私钥的明文)。本地练习无所谓,上生产必须换远端 backend 并加密存储,同时不要把 terraform.tfstate 提交进 git。
常用配置块
main.tf 里会反复出现的几类块,先认个脸熟:
terraform {
required_version = ">= 1.9"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
# backend "s3" { ... } # 团队协作时 state 存远端,后续篇章细讲
}
provider "local" {
# 多数 provider 在这里填凭证、区域等参数;local provider 无可配项
}
要点:
required_version:约束 Terraform 本体版本,团队协作时写上,避免有人拿太老的版本执行出不一样的行为。~> 2.5的写法:叫悲观版本约束(pessimistic constraint),含义是「2.5 及以上、但不到 3.0」,即>= 2.5, < 3.0;再精确一点~> 2.5.0则是>= 2.5.0, < 2.6.0。日常用~> x.y即可:吃得到补丁更新,又不会被大版本变更偷袭。provider块:配凭证和默认参数的地方。local provider 不用配;换成 docker、aws 这类,就要在这里写地址或密钥。backend块:state 存哪里。默认本地,多人协作必须换远端(S3、OSS、Terraform Cloud 等),本篇先用默认,后续篇章细讲。
常见问题
拉 provider 慢或超时
init 卡在 Installing hashicorp/local... 或报网络超时,是访问 registry.terraform.io 不稳定的常见现象。解法按优先级:
- 给终端配好代理后重跑 init,最直接。
- 配 CLI 镜像:在
~/.terraformrc里写provider_installation块,指向国内镜像站或本地目录,让 Terraform 换地方下载。 - 公司有内网制品库的话,走私有 registry。
.terraform.lock.hcl 要不要提交 git
要。锁文件记录 provider 的精确版本和哈希,提交后团队和 CI 才能装到同一份插件,避免「我本地能跑、CI 上炸了」。反过来,.terraform/ 目录(插件缓存)和 state 文件要加进 .gitignore:
.terraform/
terraform.tfstate
terraform.tfstate.backup
Apple Silicon 注意 arm64
M 系 Mac 上确认装的是 darwin_arm64 构建(terraform version 第二行可看)。个别老 provider 没发布 arm64 版本时,init 会报「no available releases」,解法要么升级 provider 版本,要么临时用 Rosetta 跑 amd64 构建。如今主流 provider 都已补齐 arm64,遇到的多半是年代久远的小众插件。
小结
- 安装任选 brew / 官网 zip / 包管理器;多版本管理用 tfenv,思路和 nvm 一致。
- 第一个练习用
hashicorp/local的local_file,零云账号跑通全流程。 - 四步命令记牢:init 装插件、plan 看差异、apply 真执行、destroy 做回收;plan 输出重点看
Plan: x to add, y to change, z to destroy那行汇总。 - state 是 Terraform 的账本:不删、不手改、不进 git。
~>是悲观版本约束;.terraform.lock.hcl要提交,.terraform/和 state 要忽略。
环境跑通、流程走顺之后,下一篇开始讲变量、输出与 data source,给这套骨架填上血肉。