terraform init 与 Provider
这一课你将能做到
- 说清楚
terraform init 到底做了哪几件事,哪些产物该提交 Git
- 正确声明 Terraform 和 provider 的版本约束,看懂锁文件
- 掌握 provider 的多别名配置、升级方法和初始化常见报错的处理
为什么要学
init 是 Terraform 所有命令的「入场券」:不 init,plan 和 apply 都跑不了。它看着简单(一行命令),但背后负责下载 provider 插件、初始化后端、拉取子模块、建立模块索引。团队协作中版本对不齐、插件下不动、锁文件冲突,几乎是每个人第一周都会撞上的问题。这一课把 init 一次讲明白,以后遇到初始化问题不再靠玄学。
人话:init 像项目开工前的「领料 + 进场」——按清单把工具(provider)领齐、确认仓库门(backend)在哪、把外包小组(modules)联系上,之后才能开工。
先建立图像
init 的输入和产物:
输入:*.tf 中的 required_providers、backend、module 源
│
├─ 下载 provider 插件 → .terraform/providers/
├─ 生成/校验依赖锁 → .terraform.lock.hjson
├─ 初始化 backend → 本地目录 或 S3 等远程存储
└─ 拉取子模块 → .terraform/modules/
Git 提交策略:
| 文件/目录 | 提交 Git? | 原因 |
|---|
*.tf | 是 | 配置本体 |
.terraform.lock.hjson | 是 | 保证全员用同版本 provider |
.terraform/ | 否 | 体积大、含平台相关二进制 |
terraform.tfstate | 本地练习可留;团队用远程 backend | 含敏感信息且需加锁 |
*.tfvars 含密钥时 | 否 | 密钥不进仓库 |
跟着做
步骤 1:写版本约束
新建 init-demo/versions.tf:
terraform {
required_version = ">= 1.7.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # 允许 5.x,不允许 6.0
}
random = {
source = "hashicorp/random"
version = ">= 3.5.0, < 4.0.0"
}
}
}
~> 5.0 是最常用的约束:允许 5.0–5.x 的任何补丁/小版本,6.0 不自动升(大版本可能有破坏性变更)。
步骤 2:配置 provider
新建 providers.tf:
provider "aws" {
region = "ap-northeast-1"
}
此时还不需要真实 AWS 凭证即可 init——下载插件发生在凭证检查之前。
步骤 3:执行初始化
terraform init
输出中重点看三段:
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installed hashicorp/aws v5.x.x ...
Terraform has been successfully initialized!
打开生成的 .terraform.lock.hjson,能看到 provider 的版本和哈希。锁文件保证同事和 CI 拿到的是完全相同的插件版本。
步骤 4:provider 多别名(同一账号两个区域)
provider "aws" {
region = "ap-northeast-1" # 默认:东京
}
provider "aws" {
alias = "singapore"
region = "ap-southeast-1" # 备用:新加坡
}
使用非默认 provider 时要在资源上显式声明:
resource "aws_s3_bucket" "backup" {
provider = aws.singapore
bucket = "my-backup-bucket-12345"
}
不加 provider 的资源全部走默认(东京)配置。跨账号、跨区域架构都靠 alias 实现。
步骤 5:升级 provider
# 在约束范围内升级并刷新 lock
terraform init -upgrade
然后 git diff .terraform.lock.hjson 确认升级了什么,跑一遍 plan 验证后再提交。没有 -upgrade 时,init 严格按 lock 里的版本安装,这正是锁文件的意义。
步骤 6:从干净环境复现
删掉 .terraform 目录(模拟新同事拉代码):
Remove-Item -Recurse -Force .terraform
terraform init
init 按 lock 文件精确还原插件版本——这一步在 CI 里每次都会发生,所以 lock 必须提交。
讲清楚要点
- init 是安全且可重复运行的:改了 provider 配置、加了模块、换了 backend 参数,重新 init 即可,它不会动你的资源。
- 三级版本约束要分清:Terraform 核心版本(required_version)、provider 版本(version)、锁文件记录实际选中的版本。约束给范围,锁定给事实。
- provider 来源是注册表地址:
hashicorp/aws 表示 registry.terraform.io 上的官方插件;也可以用第三方或本地文件系统源。
- 凭证不写在配置里:AWS provider 按顺序从环境变量
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY、共享凭证文件、IAM 角色(EC2/IRSA)取凭证。硬编码 AK/SK 是事故级错误。
- backend 初始化是 init 的一部分:配置了 S3 backend 后,init 会询问并迁移现有本地 state,第 5 课完整演示。
你可能会懵的地方
-
init 之后改了 provider 版本,要做什么?
重新 terraform init。若新约束与 lock 冲突,会提示用 -upgrade;普通改约束后 init 会自动更新 lock。
-
.terraform.lock.hjson 合并冲突怎么办?
最稳妥:删掉 lock 文件后重新 terraform init 生成,再 plan 验证一次提交。别手工编辑哈希。
-
为什么 CI 里 init 报插件哈希校验失败?
lock 是在别的操作系统生成且未包含对应平台哈希。多平台团队执行一次 terraform providers lock -platform=windows_amd64 -platform=linux_amd64 把各平台哈希都写入。
-
provider 下载慢/超时怎么办?
企业网络可搭 provider 网络镜像(network_mirror),或在 CI 预置插件缓存目录并设置 TF_PLUGIN_CACHE_DIR,避免每次重复下载。
-
一个配置能用多个云的 provider 吗?
能,required_providers 里同时声明 aws、azurerm、google 即可,但要评估 state 和 blast radius,生产通常按云/系统拆配置。
错法对照
| 错法 | 问题 | 正解 |
|---|
provider "aws" { access_key = "AKIA..." } | 密钥进 Git,泄露风险 | 用环境变量/凭证文件/角色 |
| 不写 version 约束 | 今天和下个月装的版本不同 | ~> 5.0 固定大版本 |
提交 .terraform/ 目录 | 仓库膨胀、跨平台报错 | gitignore 忽略 |
| lock 提交了但从不更新 | 错过安全补丁 | 定期 init -upgrade 并验证 |
| 多个 provider alias 却不在资源上指定 | 资源全落到默认 region | 需要时写 provider = aws.别名 |
卡点急救
Failed to query available provider packages:网络不通或镜像问题。检查代理设置,或配置 network_mirror;公司环境确认 registry.terraform.io 是否在白名单。
Unsupported Terraform Core version:本机 Terraform 太老。升级 CLI 到 required_version 要求的版本,别为了跑通而删约束。
Provider configuration not present / already declared:多 alias 时资源引用了不存在的别名,或同一个 alias 声明了两次,核对 providers.tf。
面试常问
-
terraform init 做了哪些事?
初始化 backend;按 required_providers 下载并校验插件、生成锁文件;下载配置引用的模块;建立工作目录。它不管理任何真实资源。
-
.terraform.lock.hjson 的作用?为什么要提交?
记录每个 provider 的选中版本和包哈希,保证团队成员和 CI 在约束范围内使用完全一致的插件,防止「我机器上能跑」和供应链被替换问题。
-
如何让 Terraform 同时操作两个 AWS 区域?
声明两个 provider 块,其中一个用 alias,资源上通过 provider = aws.别名 选择;跨区域资源也可以分模块各自传 providers 参数。
自测三问
~> 5.0、>= 5.0、= 5.40.0 三种约束分别允许哪些版本?
- 哪些 init 产物该进 Git,哪些不该?为什么?
- 同事的 CI 报 provider 哈希校验失败,你怀疑是什么原因,怎么修?
小结一句话
init 负责按版本约束领齐 provider、锁死版本、接好 backend 和模块,lock 提交、.terraform 忽略,是协作不翻车的起点。
延伸