摘要:基础设施即代码并不只是把命令写进脚本,而是用版本化、可评审、可重复的声明描述基础设施。Terraform 擅长创建和管理云资源生命周期,Ansible 擅长配置操作系统、服务和应用。本文分析二者的职责边界、工作流程、状态、安全、模块化、漂移、流水线和生产治理。

在这里插入图片描述

一、为什么需要基础设施即代码

人工在控制台创建虚拟机、网络、负载均衡和账号,初期很快,但随着环境增多会产生配置不一致、操作不可追溯、灾难后难以重建、知识依赖个人等问题。

基础设施即代码(IaC)把资源和配置写成代码,纳入版本控制和评审,通过流水线执行。目标包括:

  • 同一套定义能够重复创建开发、测试和生产环境;
  • 变更在执行前可以评审和预览;
  • 资源依赖由工具计算,降低手工顺序错误;
  • 配置和变更历史可以审计;
  • 灾难恢复时能够重建基础设施;
  • 通过模块和策略形成组织级标准。

IaC 不会自动消除风险,它只是把风险从临时人工操作转移到代码、状态、凭据和流水线治理上。

二、Terraform 与 Ansible 的职责边界

Terraform 是声明式资源编排工具,通过 Provider 调用云平台、OpenStack、Kubernetes、DNS、SaaS 等 API。它根据配置和 State 计算资源应创建、修改或销毁。

Ansible 是远程系统配置与自动化工具。控制节点读取 Inventory 和 Playbook,通过 SSH、WinRM 或 API 管理目标主机,常用于安装软件、修改配置、启动服务和部署应用。

推荐边界是:

  • Terraform 创建 VPC、子网、虚拟机、负载均衡、数据库、DNS 和安全策略等资源。
  • Ansible 配置操作系统、用户、软件包、中间件、应用和运行参数。
  • 镜像构建工具制作基础镜像,减少新主机启动后的可变配置。
  • Kubernetes 资源使用 Helm、Kustomize 或 GitOps 管理,避免职责过度重叠。

边界并非绝对,但同一资源最好只有一个权威管理者,否则 Terraform、Ansible、控制台和其他系统可能互相覆盖。

三、Terraform 工作原理

Terraform 官方工作流可概括为 Write、Plan、Apply。

1. Write

使用 HCL 定义 Provider、Resource、Data Source、Variable、Local、Output 和 Module。代码描述期望状态,而非逐步执行命令。

terraform {
  required_providers {
    openstack = {
      source = "terraform-provider-openstack/openstack"
    }
  }
}

resource "openstack_compute_instance_v2" "web" {
  name        = "web-01"
  image_name  = "ubuntu"
  flavor_name = "m1.small"
  network {
    name = "app-network"
  }
}

2. Plan

Terraform 读取配置、State 和远端资源,构建依赖图并生成执行计划。计划中的 create、update、replace 和 destroy 应由人或策略检查。

3. Apply

审批后,Terraform 按依赖关系执行变更。无依赖资源可以并行处理。执行结束后,实际资源标识和属性写入 State。

计划不是永久有效的承诺。如果计划和 Apply 之间远端资源或 State 发生变化,应重新生成并审查最终计划。

四、Terraform State 为什么重要

State 保存 Terraform 配置中的资源与真实平台对象之间的映射,例如 openstack_compute_instance_v2.web 对应哪个实例 ID。Terraform 还利用 State 保存依赖元数据、输出值和部分属性。

State 可能包含敏感数据。生产环境应使用支持以下能力的远端 Backend:

  • 加密存储和传输;
  • 严格访问控制;
  • 版本与恢复;
  • State Locking,避免多人同时 Apply;
  • 审计日志;
  • 可靠备份。

不要把 terraform.tfstate 提交到普通 Git 仓库,也不要手工编辑 JSON。资源改名、拆分模块或导入已有资源时,应使用 moved、import 和 terraform state 等受控方式。

五、依赖图与生命周期

Terraform 能从资源引用推断隐式依赖。例如子网引用网络 ID,实例引用子网 ID,工具会自动按顺序执行。只有无法从属性关系推断时才使用 depends_on。

生命周期参数可以控制替换顺序和保护策略:

  • create_before_destroy:先创建新资源再删除旧资源,但需要平台容量和名称允许。
  • prevent_destroy:防止误删关键资源,但不是完整权限控制。
  • ignore_changes:忽略特定属性变化,过度使用会掩盖真实漂移。

任何触发 Replace 的变更都要确认数据、IP、连接和停机影响。

六、模块化设计

Module 是可复用的基础设施组件,例如标准 VPC、Kubernetes 节点组、OpenStack 三层网络或应用负载均衡。

好的模块应该:

  • 有明确职责和稳定输入输出;
  • 提供合理默认值,但暴露真正需要变化的参数;
  • 固定 Provider 和模块版本范围;
  • 包含示例、说明、测试和升级记录;
  • 不把所有资源塞进一个“万能模块”;
  • 避免输出不必要的敏感信息。

根模块通常负责组合环境,子模块负责可复用能力。开发、测试和生产环境可以共享模块,但应使用独立 State 和凭据。

七、Ansible 核心模型

Ansible 官方入门模型由 Control Node、Inventory 和 Managed Nodes 构成。Playbook 是 YAML 自动化蓝图,包含 Play、Task 和 Module。

Inventory

Inventory 描述目标主机、分组和变量,可以是静态 INI/YAML,也可以从云平台、OpenStack 或 CMDB 动态获取。

all:
  children:
    web:
      hosts:
        web-01:
          ansible_host: 192.0.2.10

Playbook

- name: Configure web servers
  hosts: web
  become: true
  tasks:
    - name: Install nginx
      ansible.builtin.package:
        name: nginx
        state: present

    - name: Start nginx
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

Role 与 Collection

Role 用固定目录组织 Tasks、Handlers、Templates、Defaults 和 Variables。Collection 用于分发模块、插件和角色。生产环境应固定依赖版本并审查第三方内容来源。

八、幂等性与可重复执行

幂等表示重复执行后系统保持同一目标状态。使用 package、user、template、service 等声明式模块通常比 shell 和 command 更容易保持幂等。

但 Ansible 并不会保证所有任务天然幂等。自定义脚本、数据库迁移、API 调用和无条件重启都可能每次产生变化。应正确设置 changed_when、failed_when、检查模式和 Handler。

Handler 只在被通知时执行,适合配置变化后重启服务。批量更新时可以使用 serial、健康检查和负载均衡摘除,避免同时中断所有节点。

九、Terraform 与 Ansible 如何衔接

典型流程如下:

  1. Terraform 创建网络、实例、磁盘、安全组和 DNS。
  2. Terraform 输出实例 IP、角色、环境和连接信息。
  3. 流水线将输出转换为动态 Inventory,或由 Ansible 直接查询云 API。
  4. Ansible 等待 SSH/WinRM 可用,配置主机和应用。
  5. 测试阶段验证端口、健康检查和业务请求。
  6. 成功后登记 CMDB、发布记录和监控标签。

不要通过大量 local-exec 或 remote-exec 把完整 Ansible 流程塞进 Terraform。Provisioner 难以重试、审计和单独复用,应该作为最后手段。

十、漂移与现有资源接管

漂移是实际资源与代码期望不一致。它可能来自控制台手工修改、自动扩缩容、其他工具或平台默认值变化。

治理方法包括:

  • 定期运行只读 Plan 检测漂移;
  • 限制生产控制台修改权限;
  • 紧急修改后及时回写代码;
  • 对平台自动管理的属性谨慎使用 ignore_changes;
  • 使用 Import Block 或导入命令逐步接管已有资源;
  • 接管前确认不会触发意外替换或删除。

IaC 的权威来源应明确。代码、State、真实环境和 CMDB 之间出现差异时,团队必须有统一处理流程。

十一、CI/CD 流水线设计

一个相对完整的 Terraform 流水线包括:

  1. 格式检查和语法验证;
  2. Provider 与模块依赖锁定;
  3. 静态安全和合规扫描;
  4. 测试环境 Plan 或集成测试;
  5. 生产 Plan 生成与人工审批;
  6. 使用同一份已审批计划 Apply;
  7. 保存日志、结果、State 版本和审计信息。

Ansible 流水线还应包含 YAML/Lint、语法检查、角色测试、Check Mode、分批执行、健康检查和失败回滚或停止策略。

生产 Apply 不应由开发者笔记本随意执行。流水线应使用短期凭据、受保护分支、环境审批和最小权限执行身份。

十二、秘密管理

Terraform 变量标记为 sensitive 只会减少部分输出展示,不代表秘密不会进入 State。应尽量传递密钥引用而不是秘密本身,并使用云密钥服务、Vault 或流水线秘密存储。

Ansible Vault 可以加密变量文件,但解密密钥仍需安全管理。模板渲染、调试输出、失败堆栈和命令参数都可能泄露秘密,应使用 no_log 并限制日志访问。

十三、测试策略

基础设施代码也需要测试:

  • 静态测试:格式、语法、Lint、安全规则和策略。
  • 单元或模块测试:验证变量、输出和资源属性。
  • 集成测试:在隔离账号或项目中创建真实资源并验证。
  • 合约测试:检查网络、端口、DNS、证书和监控是否符合平台约定。
  • 灾难恢复测试:验证从代码、State 备份和数据备份恢复环境。

“Plan 成功”只表示配置可计算,不表示业务一定可用。

十四、常见误区与局限

Terraform 不是通用脚本工具

它擅长管理具有 API 和生命周期的资源,不适合长时间编排每个操作系统步骤或数据库业务迁移。

Ansible 不是资源状态数据库

Ansible 通常不维护类似 Terraform 的持久 State。它适合将节点配置到目标状态,但资源销毁、依赖图和云资源生命周期不是其最强领域。

自动化不能替代架构设计

代码可以快速复制错误。网络、权限、备份、容量和故障域设计不合理时,自动化只会更快地产生问题。

多团队协作需要治理成本

模块版本、State 拆分、Provider 升级、策略例外和责任边界都需要平台团队长期维护。

十五、适用场景

  • 公有云、OpenStack 和多云资源交付;
  • Kubernetes 集群与节点基础设施;
  • 网络、DNS、负载均衡和安全策略标准化;
  • 大规模 Linux/Windows 主机配置;
  • 中间件、监控 Agent 和应用部署;
  • 灾难恢复环境重建和临时测试环境。

只有少量长期不变的主机时,可以从 Ansible 或简单 Terraform 模块开始,不必一次建设复杂平台。

十六、生产最佳实践

  • 每个环境或责任域使用独立 State,控制爆炸半径。
  • 使用远端 State、锁、加密、版本和备份。
  • 固定 Provider、Module、Collection 和 Role 版本。
  • 所有变更经过 Pull Request、Plan 和审批。
  • 生产使用短期凭据与最小权限服务账号。
  • 避免控制台漂移,紧急变更必须回写代码。
  • 对销毁、替换和数据库资源设置额外保护策略。
  • Terraform 与 Ansible 保持清晰职责边界。
  • 定期演练 State 恢复、资源导入和环境重建。

十七、总结

Terraform 与 Ansible 并不是竞争关系。Terraform 负责“需要哪些基础资源以及它们如何关联”,Ansible 负责“主机和应用最终应处于什么配置状态”。将二者放入 Git、评审、策略、流水线和审计体系后,基础设施交付才能从个人经验转变为可重复的工程能力。

参考资料:

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐