Ansible 与 Terraform 在基础设施编排上如何选择搭配?

文章导读
在生产环境中,最稳妥的搭配方式是让 Terraform 负责云资源的创建与管理,Ansible 负责系统内部的配置与软件部署,两者通过状态文件对接,而不是互相替代。
📋 目录
  1. 核心分工与选型逻辑
  2. 实操落地:配置与对接
  3. 验证与排查
  4. 常见风险与规避
A A

在生产环境中,最稳妥的搭配方式是让 Terraform 负责云资源的创建与管理,Ansible 负责系统内部的配置与软件部署,两者通过状态文件对接,而不是互相替代。

先说结论:基础设施生命周期管理用 Terraform,应用配置与批量运维用 Ansible,两者结合实现从底层硬件到上层应用的全流程自动化。

  • 适合:需要跨云平台管理资源且要求环境一致性的场景。
  • 重点看:Terraform 管理资源“存在性”,Ansible 管理机器“内部状态”。
  • 别忽略:两者结合时需处理好 inventory 传递,避免状态漂移。

核心分工与选型逻辑

这两个工具的核心分工不同,强行混用会增加维护成本。Terraform 是声明式工具,关注“资源的存在状态”,比如是否需要创建一台虚拟机、一个负载均衡器或一个 VPC,它维护全局远程状态文件,适合基础设施生命周期管理。Ansible 则是基于 SSH 的无代理工具,关注“配置与运行时状态”,比如软件安装、服务配置、文件内容修改,适合机器配置与应用部署。

形象地说,Terraform 负责把房子建起来,Ansible 负责把房子收拾到能住。Terraform 声明“我要什么”,Ansible 告诉机器“你去干啥”。在生产实践中,Terraform 创建云资源并输出清单,Ansible 接管后续配置与部署,这种组合能发挥各自优势。

实操落地:配置与对接

以下是结合两者的典型实施步骤,确保每一步都有检查点,并修正了常见的对接误区。

Ansible 与 Terraform 在基础设施编排上如何选择搭配?

1. Terraform 基础设施定义

编写配置文件定义所需资源。注意不要硬编码 AMI ID,应使用 data source 动态获取,并配置远程后端以防止状态冲突。

# provider.tf
provider "aws" {
  region = var.aws_region
}

# backend.tf (防止状态冲突)
terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "prod/terraform.tfstate"
    region = "us-east-1"
  }
}

# variables.tf
variable "aws_region" {
  default = "us-east-1"
}

# main.tf
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"] # Canonical

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }
}

resource "aws_instance" "app_server" {
  count       = 3
  ami         = data.aws_ami.ubuntu.id
  instance_type = "t3.medium"

  tags = {
    Name = "app-server-${count.index}"
  }
}

output "instance_ips" {
  value = aws_instance.app_server.*.public_ip
}

2. Ansible 库存对接方案

注意:直接使用terraform output -json > inventory.json生成的格式 Ansible 无法直接识别。推荐以下两种方案:

方案 A:使用 Terraform Inventory 插件(推荐)
ansible.cfg或 playbook 中配置插件,直接读取 Terraform 状态。

Ansible 与 Terraform 在基础设施编排上如何选择搭配?
# ansible.cfg
[inventory]
enable_plugins = community.general.terraform_inventory

# inventory_plugins/terraform_inventory.yml (示例配置)
plugin: community.general.terraform_inventory
terraform_binary: /usr/bin/terraform
terraform_project_path: ./infra

方案 B:脚本转换
若不使用插件,需编写脚本解析 Terraform output 并生成标准 INI 或 JSON inventory。

# 示例:简单提取 IP 生成 inventory 文件
terraform output -raw instance_ips | tr -d '[]"' | tr ',' '\n' | \
awk '{print $0 " ansible_host=" $0}' > hosts.ini

3. Ansible 配置剧本

定义系统配置任务,如安装依赖、部署代码、配置防火墙。Ansible 的幂等性确保重复执行不会破坏系统。

# site.yml
- name: Configure App Servers
  hosts: all
  become: yes
  tasks:
    - name: Install Nginx
      apt:
        name: nginx
        state: present
        update_cache: yes

    - name: Start Nginx
      service:
        name: nginx
        state: started
        enabled: yes

验证与排查

部署完成后,需从基础设施和应用层分别验证:

  • 基础设施层:使用terraform state list查看资源状态,确认所有预期资源已创建且无漂移。检查.terraform/terraform.tfstate是否已锁定或上传至远程后端。
  • 连通性层:使用ansible -i hosts.ini -m ping all测试 Ansible 是否能通过 SSH 连通所有新创建的节点。若失败,检查安全组是否放行 SSH 端口。
  • 应用层:登录目标服务器,使用systemctl status nginx检查服务运行状态,或访问业务端口确认服务响应。

常见风险与规避

  • 库存格式错误:Terraform 输出的 JSON 结构与 Ansible Inventory 格式不兼容,直接重定向无法使用。务必使用插件或转换脚本。
  • 状态文件管理:Terraform 的 state 文件包含敏感信息,需妥善存储和保护。务必配置远程后端(如 S3 + DynamoDB)启用状态锁,避免多人协作冲突。
  • 硬编码资源 ID:避免在代码中硬编码 AMI ID 或子网 ID,这些资源具有区域依赖性。应使用 data source 动态查询或通过变量传递。
  • 忽略工具边界:不要试图用 Ansible 管理云资源生命周期,也不要试图用 Terraform 处理复杂的系统内部配置,这会导致自动化遭遇现实世界时暴露边界问题,如状态漂移或紧急变更困难。
  • 版本兼容性:确保工具版本满足基本要求,例如 Terraform 0.14+ 和 Ansible 2.10+,以避免语法或功能不支持的问题。

更多详细参数与最新用法,请参考 HashiCorp 官方文档及 Ansible 官方文档。