远程 Mac 共享 Runner上,terraform init 常被跨境拉取 provider 拖慢,并伴随 TLS 抖动与锁文件无意义 diff。本文给出阈值表、镜像决策矩阵、可复制环境变量与 terraform.rc、init 有界重试、CI 门禁与 FAQ。内链:首页博客列表Helm OCI 决策矩阵(均免登录)。

痛点:(1)多 job 并发 init 争用 Registry 与插件缓存;(2).terraform.lock.hcl 若未在与生产一致的平台集合上生成,易出噪音 PR;(3)重试需上限+退避,避免坏镜像拖死队列。

评测维度与阈值

下列阈值为跨境 + 共享 APFS起步值,请用你们真实 job 的 p95 init、Registry 5xx、锁文件 diff 频率校准。

维度 建议起步阈值 判读与动作
terraform init(含 provider 安装)p95 耗时 主干流水线 < 120s;夜间大批量可放宽至 240s 先补镜像再调 TF_REGISTRY_CLIENT_TIMEOUT
TF_REGISTRY_CLIENT_TIMEOUT(秒) 同城/同区 10–20;跨洲公网 30–60 配合≤4 次有界重试;坏镜像勿只靠加长超时。
同一宿主机并发 init 作业数 共享盘为 APFS 时建议 2–4 路;独占 NVMe 节点可试 4–6 缓存锁争用则每作业子目录或排队。
插件缓存与 workspace 磁盘水位 可用空间 > 15% 且绝对值建议 > 20GiB 再跑大批量 init 低于水位快速失败,防半写入缓存。
.terraform.lock.hcl 变更治理 受保护分支上 禁止无说明的哈希漂移;PR 必须附 terraform providers lock 命令记录 锁刷新只在黄金镜像执行并留命令记录。

可引用:TF_LOG=INFO 区分 429/5xx 与本地解压;锁文件须含 darwin_arm64include/exclude 对齐出站白名单。

对比表或决策矩阵

决策焦点:谁提供可信 ZIP 与校验和direct 简单但怕跨境;network_mirror 靠企业 HTTPS;filesystem_mirror 靠离线同步目录;混合时必须写清 include/exclude

模式 最适配场景 主要风险 一句话结论
direct 直连 registry.terraform.io 早期原型、海外团队、无合规限制 跨境抖动、Rate limit、DNS 分叉 监控 p95,生产勿单吊公网。
network_mirror 企业 HTTPS 镜像 已有统一工件域、需审计出站 镜像索引滞后、证书链不一致 锁文件在与 CI 同镜像生成。
filesystem_mirror 本地目录 强隔离区、间歇性断网、批量同版本 init 目录更新竞态、权限与挂载只读 发布同步 ZIP;只读挂载 + 作业临时目录。
plugin_cache_dir + 作业级子路径 重复拉同一 minor provider、节省带宽 多租户缓存污染、锁文件与缓存一致性 先读官方 plugin_cache_may_break_dependency_lock_file 再开团队缓存。

可执行命令与环境变量清单

仓库根示例 ${CI_PROJECT_DIR}五步走:钉死 Terraform 版本 → 生成 .terraformrc+TF_CLI_CONFIG_FILE → 设 TF_PLUGIN_CACHE_DIR → 有界重试 initvalidate+锁 diff。

export TF_IN_AUTOMATION=1
export TF_INPUT=0
export TF_CLI_CONFIG_FILE="${CI_PROJECT_DIR}/.terraformrc"
export TF_PLUGIN_CACHE_DIR="${CI_PROJECT_DIR}/.tf-plugin-cache-${CI_JOB_ID:-local}"
export TF_REGISTRY_CLIENT_TIMEOUT="${TF_REGISTRY_CLIENT_TIMEOUT:-45}"
# 短时排障可开:export TF_LOG=INFO

mkdir -p "${TF_PLUGIN_CACHE_DIR}"

.terraformrc 示例;其中路径为字面量,CI 可用 envsubst 生成以与 TF_PLUGIN_CACHE_DIR 对齐。

# 生成后内容示例(路径按作业替换)
plugin_cache_dir = "/tmp/tf-plugin-cache-job-12345"

provider_installation {
  filesystem_mirror {
    path    = "/usr/local/share/terraform/providers-mirror"
    include = ["registry.terraform.io/hashicorp/*"]
  }
  network_mirror {
    url     = "https://terraform-mirror.internal.example.com/"
    include = ["registry.terraform.io/*/*"]
  }
  direct {
    exclude = ["registry.terraform.io/*/*"]
  }
}
# 与 CI 相同平台上刷新或校验锁文件(示例:Apple Silicon)
terraform providers lock \
  -platform=darwin_arm64 \
  -platform=linux_amd64 \
  -fs-mirror=/usr/local/share/terraform/providers-mirror

terraform init -input=false -no-color -upgrade=false

terraform validate
# init 有界重试(2s / 4s / 8s,最多 4 次)
run_init() {
  local n=1 d=2
  while [ "$n" -le 4 ]; do
    echo "terraform init attempt ${n}/4"
    terraform init -input=false -no-color -upgrade=false && return 0
    [ "$n" -eq 4 ] && return 1
    sleep "$d"; d=$((d*2)); n=$((n+1))
  done
}
run_init

CI 门禁要点(建议全选)

  • terraform fmt -check -recursiveterraform validate 在受保护分支必跑。
  • terraform init -lockfile=readonly 防止流水线悄悄改锁;锁更新只能在指定 bot job 执行。
  • git diff --exit-code -- .terraform.lock.hcl 或等价检查,确保 PR 意图与锁文件变更一致。
  • 磁盘水位脚本在 init 前执行,低于阈值直接 exit 42 让队列调度到其他节点。

FAQ

Q:镜像已配仍慢? 核对 include/exclude 是否命中;TF_LOG 看是否仍打公网(常漏社区命名空间)。

Q:缓存路径冲突?plugin_cache_dirTF_PLUGIN_CACHE_DIR 指向同一目录,以生成式 .terraformrc 为准。

Q:多根目录? 每根模块各一份 .terraform.lock.hcl,矩阵分别校验。

Q:每次清缓存? 默认否;仅在校验失败、哈希异常或磁盘水位触发清理。

总结与下一步

把超时、镜像、缓存、锁基线与重试上限写成一条策略,init 才可审计。需要稳定 Apple Silicon容量时可看定价购买帮助中心;更多文章见博客列表(均免登录)。