- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
导读
本文是 90DaysOfDevOps 挑战中「基础设施即代码(Infrastructure as Code)」专题的收官章节(对应仓库文档 2022/zh_cn/Days/day62.md),围绕三件事展开:为什么 IaC 代码会「腐烂」、如何用内置命令与第三方工具把 IaC 测试做扎实,以及除了 Terraform 之外还有哪些值得评估的替代方案。读完本文,你将掌握terraform fmt / validate / plan的定位差异、tflint / Checkov / tfsec 等扫描与合规工具的分工、如何用 Terratest 编写 Go 语言驱动的真实基础设施集成测试,并能对照 CloudFormation、Pulumi 等方案理解「云厂商锁定」与「多云统一管理」的取舍。
本专题从 Day 57 起依次覆盖了虚拟化(VirtualBox)、容器(Docker)、Kubernetes 与多环境管理,相关演示代码都沉淀在仓库 2022/Days/IaC 目录中,本文的源码佐证也主要来自该目录。
为什么 IaC 也需要测试:先认识「代码腐烂(Code Rot)」
与普通应用代码不同,基础设施代码往往「跑一次」之后就被长期闲置。文档里给出的场景非常典型:用 Terraform 在 AWS 上部署一套虚拟机环境,第一次执行就成功,环境也随之稳定运行——但正因为环境不常变化,这份 Terraform 代码可能被搁置数月甚至数年,状态文件虽然存放在中央位置,代码本身却再也没人改动。
就在这段「无人问津」的时间里,基础设施却可能悄悄发生变化,最终导致代码与真实环境脱节。文档明确列出了四类最常见的腐烂来源:
- 带外变更(Out of band changes):有人绕开 Terraform 直接在控制台或 CLI 里改了资源,状态文件没有同步,下次
apply时 Terraform 会把环境「拉回」代码描述的状态,可能造成意外的资源重建或销毁; - 未锁定的版本(Unpinned versions):provider 或 module 版本未固定,
terraform init时悄悄拉入新版本,行为差异在毫无预警的情况下进入环境; - 废弃的依赖(Deprecated dependencies):旧版 provider、module 或 AMI 被上游废弃,配置虽然在语法上仍然合法,但已无法获得更新与安全修复;
- 未应用的变更(Unapplied changes):代码已经修改、计划也已生成,但
apply从未执行,代码与真实状态长期背离。
理解代码腐烂是理解 IaC 测试的前提——测试的目的不只是「验证代码写得对不对」,更是「验证代码描述的期望状态与真实环境是否始终一致」。
Terraform 内置测试命令:从格式化到执行计划
针对上述问题,Terraform 自带了一套开箱即用的校验命令。文档给出如下对照表,这也是每个 IaC 工程落地前应至少跑一遍的「基础测试」:
| 命令 | 说明 |
|---|---|
terraform fmt | 将 Terraform 配置文件重写为规范的格式与风格(对齐、缩进),消除团队间格式分歧 |
terraform validate | 校验目录中的配置文件,仅基于配置本身(引用合法性、语法、provider schema)进行验证,不访问远端状态 |
terraform plan | 生成执行计划,让你预览 Terraform 将要做出的所有变更(创建、更新、删除) |
| 自定义校验(Custom validation) | 对输入变量做自定义校验规则,确保传入值符合预期 |
这四者的定位可以这样理解:fmt负责「格式正确」,validate负责「配置自洽」,plan负责「变更可预期」,而自定义校验负责「输入有边界」。文档特别强调,validate只参考配置本身,不依赖远端状态,因此适合在 CI 中作为快速门禁;而plan才是真正对接真实环境的「预演」,能发现validate发现不了的状态偏差。
仓库中的变量声明与校验空间
仓库 2022/Days/IaC/Terratest/examples/vars.tf 展示了本专题演示里最朴素的变量声明方式——AWS_ACCESS_KEY、AWS_SECRET_KEY为无默认值的必填变量,AWS_REGION与AMIS则带有默认值。在实际工程中,这些变量块就是自定义校验的挂载点:可以追加validation { condition = ...; error_message = ... }对区域白名单、实例类型、AMI 有效性等做前置约束,把「配置能解析」升级为「配置符合业务预期」,这正是表格中第四行「Custom validation」的落地位置。
外部测试与扫描工具:按职责分层
内置命令只能覆盖「Terraform 自己的正确性」,而安全、合规、最佳实践层面的问题则需要专门工具。文档将外部工具按职责做了清晰分组,值得逐一对照:
Lint 与静态分析
- tflint:定位「代码风格与潜在错误」,主要能力包括:发现可能存在的错误、对废弃语法与未使用声明给出警告、强制执行最佳实践与命名约定。它站在代码层做「编译器之外」的静态检查,是 CI 流水线里非常前置的一环。
安全与合规扫描
- Checkov:在基础设施部署之前扫描云基础设施配置,提前发现错误配置(misconfigurations),覆盖 Terraform 之外还包括 CloudFormation、Kubernetes 等多种 IaC 形态;
- tfsec:面向 Terraform 代码的静态分析安全扫描器,聚焦安全漏洞维度;
- terrascan:面向 IaC 的静态代码分析器,擅长把配置与策略(如 CIS 基准)比对;
- terraform-compliance:轻量级、面向安全与合规的测试框架,核心价值是支持「负向测试」(negative testing)——即显式断言某些配置不允许出现;
- Snyk:扫描 Terraform 文件中的错误配置与安全缺陷,优势在于与依赖漏洞库联动。
这一类工具共同的特点是「部署前门禁」:把扫描结果接入 CI,让带有高危配置的代码根本走不到apply。
策略即代码(Policy as Code)
- Terraform Sentinel:嵌入在 HashiCorp 企业级产品中的策略即代码框架,支持细粒度、基于逻辑的策略决策,并可通过数据源扩展引入外部信息。与上文的扫描工具不同,Sentinel 表达的是「组织级准入策略」——哪些资源、哪些配置允许进入生产,由策略代码说了算。
自动化测试
- Terratest:Gruntwork 出品的 Go 库,提供测试基础设施的通用模式与辅助函数。它把
terraform init/apply/destroy封装进 Go 测试,并可在资源就绪后发起真实请求验证行为——这是文档列出的工具中最接近「应用级集成测试」的一个,仓库中恰好有完整示例(见下一节)。
值得单独一提的周边工具
- Terraform Cloud:HashiCorp 的托管服务,消除团队与组织在生产中使用 Terraform 时对额外工具链和文档的依赖,内置远程状态、远程执行与策略入口;
- Terragrunt:薄封装层,用于保持配置 DRY、组织多模块复用、统一管理远程状态;
- Atlantis:Terraform 的 Pull Request 自动化工具,在 PR 中自动执行
plan并把结果回帖,评审通过后再执行apply,把「计划-评审-应用」嵌入 Git 工作流。
源码纵深:仓库中的 Terratest 端到端示例
文档提到 Terratest 是「Go 库 + 测试模式」,仓库 2022/Days/IaC/Terratest 目录正好给出了一个可运行的 AWS Hello World 实例,是理解「自动化测试 IaC」的最佳教材。整个示例由两层构成:
被测的基础设施(examples 目录)
- versions.tf:声明
required_version = ">= 0.12.26",锁定 Terraform 本体版本下限; - vars.tf:声明 AWS 凭证、区域与 AMI 映射变量;
- provider.tf:配置 AWS provider,从变量读取凭证与区域;
- securitygroup.tf:放行 8080 端口的入站规则(
0.0.0.0/0,仅用于演示); - instance.tf:创建
t2.micro实例,并在启动时通过user_data用 busybox 起一个返回 "Hello, World!" 的 8080 Web 服务; - output.tf:导出实例公网 IP,供测试阶段读取;
- terraform.tfvars:以
AWS_ACCESS_KEY = "XXXX"等占位符形式演示变量注入方式(实际值需替换为真实凭证)。
测试驱动(test 目录)
test/terraform_test.go 是这份示例的灵魂,它演示了 Terratest 的标准测试套路:
terraform.WithDefaultRetryableErrors构造terraform.Options,并把TerraformDir指向../examples;defer terraform.Destroy保证测试结束后资源被清理(避免测试留下昂贵账单);terraform.InitAndApply依次执行init与apply,任何错误都会让测试失败;terraform.Output读取public_ip输出;http_helper.HttpGetWithRetry以重试方式请求http://<IP>:8080,断言返回 200 且响应体为 "Hello, World!"。
这个测试把「部署—验证—销毁」三个环节全部代码化:验证的不仅是 Terraform 配置语法,而是真实环境中的真实行为——实例能启动、Web 服务能响应、端口能访问。这正是 IaC 测试区别于validate/plan的地方,也是文档中「automated testing」分类想要表达的核心价值。从源码结构看,该测试采用t.Parallel()并行模式,适合在 CI 中对多个环境的配置做并发验证。
替代方案:云厂商原生 vs 云无关
文档在 Day 57 开篇时就预告过 Terraform 之外存在其他选择,本节给出了一张对照表:
| 云厂商专属 | 云无关 |
|---|---|
| AWS CloudFormation | Terraform |
| Azure Resource Manager(ARM) | Pulumi |
| Google Cloud Deployment Manager | — |
作者坦承,上表中除 Terraform 外使用最多的是 AWS CloudFormation。云厂商专属方案的优势在于与该云深度原生集成(例如 CloudFormation 与 IAM、StackSets、Change Set 的联动),但文档点出了核心痛点:一旦涉及多云环境,要么为迁移这些配置而费尽周折,要么被迫为每一朵云维护一套独立的管理平面。对于多云的团队,「云无关」的价值不在于单个云的深度,而在于一套代码、一种心智模型覆盖所有目标环境。
Pulumi:以通用编程语言取代 HCL
文档作者明确把 Pulumi 列为下一步想深入学习的对象,并引用了 Pulumi 官网的对比说明:
Terraform 与 Pulumi 都采用「期望状态」的基础设施即代码模型——代码描述期望的基础设施状态,部署引擎把期望状态与栈(stack)的当前状态比对,确定哪些资源需要创建、更新或删除。
这一句点明了两者在核心模型上的一致性:都是 desired-state 声明式模型,都由引擎做状态收敛。真正的分水岭在表达语言:Terraform 使用 HashiCorp Configuration Language(HCL),而 Pulumi 允许使用 Python、TypeScript、JavaScript、Go、.NET 等通用编程语言。这意味着 Pulumi 代码可以复用现有语言生态——循环、函数、抽象、类型检查、单元测试框架全部可用,把 IaC 从「领域专用 DSL」升级为「你熟悉语言的普通代码」。文档评价其交互引导「易用且选择丰富」,但也隐含了一个需要权衡的点:通用语言更灵活,相应地也更需要团队约束与代码评审来避免失控。
章节收尾:从 IaC 迈向配置管理
文档在末尾预告了下一阶段的学习路径:结束基础设施即代码专题后,将进入与配置管理(Configuration Management)相交叠的部分,并特别指出后续会使用Ansible来做配置管理的实战演示。这正好衔接了仓库中 2022/Days/Configmgmt 目录(包含大量*.yml与 Jinja2 模板)即将展开的内容。衔接下一篇文章可参阅 2022/zh_cn/Days/day63.md。
延伸学习指引
本专题在社区中被反复讨论,如果希望继续深入,可以按以下方向自行检索学习:基础设施即代码的定义与工具差异("What is Infrastructure as Code" 主题)、Terraform 入门到进阶课程、HashiCorp Terraform Associate 认证备考、Terraform 实战项目集合,以及 Pulumi 的"用你熟悉的语言写 IaC"官方介绍。同时,仓库 2022/Days/IaC 中还有 Docker(docker.tf)、Docker-Wordpress(docker-wordpress.tf)、Hello-world(main.tf)、Kubernetes(kubernetes.tf)与 VirtualBox(virtualbox.tf)等完整演示配置,可以配合前几天的文档(如 2022/zh_cn/Days/day61.md 的 Kubernetes 与多环境部署)逐一复现,把本文的测试与工具链知识落到真实环境里。
- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
相关推荐
90DaysOfDevOps 第 62 天:基础设施即代码的测试、工具与 Terraform 替代方案
90DaysOfDevOps 第 62 天:基础设施即代码的测试、工具与 Terraform 替代方案 导读 本文是 90DaysOfDevOps 挑战计划中“
文档/教程90DaysOfDevOps Day 62:Terraform 基础设施即代码的测试、工具与替代方案实战指南
90DaysOfDevOps Day 62:Terraform 基础设施即代码的测试、工具与替代方案实战指南 本篇文章是 90DaysOfDevOps 挑战中「
文档/教程90DaysOfDevOps Day 62:Terraform 基础设施测试、工具链与替代方案实战指南
90DaysOfDevOps Day 62:Terraform 基础设施测试、工具链与替代方案实战指南 本文是 90DaysOfDevOps 学习路线中 Inf
文档/教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考