告别手写 Inventory:Terraform 与 Ansible 在 Azure 上的联动,动态清单自动接管云主机

一、为什么要把Terraform和Ansible 放在一起看

很多人会把 Terraform 和 Ansible 分开学:

  • Terraform 用来创建云资源
  • Ansible 用来配置服务器

单独看都没问题,但真正落地时,问题往往出在两者怎么接起来

最常见的低效做法是:

  1. 先用 Terraform 创建 Azure 虚拟机
  2. 再手动整理 IP
  3. 再手写 Ansible inventory
  4. 机器一变更,inventory 又得改

这套流程最大的问题就是:基础设施已经自动化了,主机清单还是半手工维护

Ansible 官方提供的 azure.azcollection.azure_rm 动态清单插件,就是为了解决这个问题:

它可以直接从 Azure Resource Manager 查询虚拟机信息,不再依赖手工维护静态 hosts 文件,在主机经常变化的云环境中,减少维护静态 inventory 的负担。

所以这篇文章是一个思路:

Terraform 负责创建 Azure 资源并打标签,Ansible 通过 Azure 动态清单按标签自动发现并分组,最后执行配置。


二、整体架构思路

整个流程可以概括成下面四步:

  1. Terraform 创建 Azure VM、网卡、公网 IP、NSG 等资源
  2. Terraform 在 VM 上打标签,例如:
    • env=dev
    • role=web
    • app=demo
  3. Ansible 使用 azure_rm 动态清单插件,从 Azure 拉取虚拟机信息
  4. Ansible Playbook 按标签生成的主机组执行配置任务

这种方式的好处是:

  • 不需要手工维护 inventory
  • 扩容新主机后,Ansible 下次执行自动发现
  • 可以按环境、角色、应用自动分组
  • Terraform 和 Ansible 的职责边界更清晰

三、为什么推荐"动态清单 + 标签分组",而不是 Terraform 直接生成 inventory 文件

Terraform 确实可以通过 local_file 在本地生成 inventory 文件。

这种方式适合简单 demo,但不适合作为主方案。云主机 IP、数量、角色都可能变化。 如果 inventory 是 Terraform 渲染出来的静态文件,那它仍然是一份"产物文件",而不是实时视图。

如果换一台机器执行 Terraform,而本地文件不存在,Terraform 会把它识别为需要重建的资源,这容易带来额外 diff 噪音。

我知道有provisioner 这个东西,但是Terraform 官方也明确建议: provisioner 应该是最后手段,因为 Terraform 的核心职责是管理资源生命周期,而不是承担复杂的后置配置逻辑。

因此,在 Azure 场景下,更推荐的方式是:

  • Terraform:创建 VM 并打好标签
  • Ansible:通过 Azure 动态清单实时读取 Azure 里的VM
  • Playbook:按标签生成的分组执行配置

四、准备工作

Azure 动态清单依赖 Ansible 的 Azure Collection。

azure.azcollection.azure_rm 是官方支持的 Azure Resource Manager inventory 插件,需要在执行 Ansible 的控制节点上安装相应 collection 和依赖。该插件要求 inventory 配置文件名以 azure_rm.ymlazure_rm.yaml 结尾。

1. 安装Ansible与Azure Collection

bash 复制代码
sudo apt update
sudo apt install -y pipx
pipx ensurepath
pipx install ansible
ansible-galaxy collection install azure.azcollection
pipx runpip ansible install -r ~/.local/share/pipx/venvs/ansible/lib/python*/site-packages/ansible_collections/azure/azcollection/requirements.txt

实际 requirements.txt 路径可能因安装方式不同而略有差异,可先用 ansible-galaxy collection listpython -c 等方式确认安装目录。

2. 准备Azure 凭证

azure_rm 支持多种认证方式,包括 autoenvcredential_fileclimsi

本地测试时可以直接使用 Azure CLI 登录;

bash 复制代码
az login
az account set --subscription "<your-subscription-id>"
``

CI/CD 或自动化环境更推荐服务主体等非交互式方式。

例如使用环境变量:

bash 复制代码
export AZURE_SUBSCRIPTION_ID="your_subscription_id"
export AZURE_CLIENT_ID="your_client_id"
export AZURE_SECRET="your_client_secret"
export AZURE_TENANT="your_tenant_id"

五、Terraform:创建Azure VM并打标签

下面示例不是完整生产模板,只演示关键思想:

Terraform 创建虚拟机时,把后续 Ansible 需要的分组信息提前写进标签。

json 复制代码
resource "azurerm_linux_virtual_machine" "web" {
  name                = "vm-web-01"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  size                = "Standard_B2s"
  admin_username      = "azureuser"
  network_interface_ids = [
    azurerm_network_interface.web_nic.id
  ]

  admin_ssh_key {
    username   = "azureuser"
    public_key = file("~/.ssh/id_rsa.pub")
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts"
    version   = "latest"
  }

  tags = {
    env  = "dev"
    role = "web"
    app  = "demo"
  }
}

这里最重要的不是 VM 本身,而是 tags

因为后面 Ansible 动态清单就可以基于这些标签自动分组。

六、使用Azure动态清单自动发现主机

inventory目录下创建一个文件,名称必须以 azure_rm.yml 结尾,例如:

yaml 复制代码
plugin: azure.azcollection.azure_rm #指定 Azure 动态清单插件
auth_source: auto
include_vm_resource_groups:  #限制查询范围,避免全订阅扫描,效率更高
  - rg-demo-dev
plain_host_names: yes #避免默认 inventory 主机名过长

#按标签自动生成组
keyed_groups:  
  - prefix: tag
    key: tags
  - prefix: azure_loc
    key: location

#显式生成web、dev 这样的逻辑组
conditional_groups:
  web: tags.role is defined and tags.role == 'web'
  dev: tags.env is defined and tags.env == 'dev'

#控制 ansible_host 取公网IP 或私网IP
hostvar_expressions:
  ansible_host: (public_ipv4_addresses + private_ipv4_addresses) | first

验证一下:

bash 复制代码
ansible-inventory -i inventory/myazure_rm.yml --graph

如果 Terraform 创建的 VM 已经存在且认证没问题,你就应该能看到按标签或条件生成的主机组。

七、让Terraform和Ansible 联动起来

terraform apply 后,Azure 里已经有了带标签的 VM;

Ansible 运行时直接去 Azure 读取当前状态。

也就是说,两者之间的"桥梁"不是一个中间文件,而是 Azure 资源本身的标签元数据

这样做有几个好处:

  • Terraform 扩容一台新 role=web 的 VM 后,Ansible 下次执行会自动把它归入 web
  • 如果某台主机删除了,它也会从动态清单里自然消失
  • 不需要写额外的 inventory 渲染逻辑
  • 不需要担心静态 hosts 文件和真实云资源状态不一致

八、示例 playbook

例如你要给所有 web 主机安装 Nginx,在playbooks目录创建web.yml:

yaml 复制代码
- name: Configure web servers
  hosts: web
  become: true
  tasks:
    - name: Install nginx
      ansible.builtin.package:
        name: nginx
        state: present

    - name: Ensure nginx is running
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

执行方式:

bash 复制代码
ansible-playbook -i inventory/myazure_rm.yml playbooks/web.yml \
  -u azureuser --private-key ~/.ssh/id_rsa

如果 Terraform 后续又新增了两台 role=web 的虚拟机,只要标签一致,Ansible 不需要改 inventory,就能自动把它们纳入执行范围。

相关推荐
wd5i8kA8i17 小时前
ansible介绍、按照及配置
ansible
Ashmcracker1 天前
Codex Desktop如何接入Azure OpenAI?AI Foundry部署GPT‑5.3‑codex 实操
人工智能·gpt·microsoft·azure
zfoo-framework1 天前
[推荐]ansible在主控机执行实现多个worker机器免密登录
linux·运维·ansible
Ashmcracker1 天前
Azure Key Vault 证书如何在 AKS 中同步为 Kubernetes Secret?附权限配置与 YAML 示例
kubernetes·flask·azure
SPC的存折1 天前
10、Ansible 生产级故障排查与运维最佳实践
linux·运维·ansible
SPC的存折3 天前
8、Ansible之Playbook---Roles
linux·服务器·ansible
左手厨刀右手茼蒿4 天前
Flutter 三方库 flutter_azure_tts 深度链接鸿蒙全场景智慧语音中枢适配实录:强势加载云端高拟真情感发音合成系统实现零延迟超自然多端协同-适配鸿蒙 HarmonyOS ohos
flutter·harmonyos·azure
我爱学习好爱好爱5 天前
Ansible变量介绍 vars变量 inventory针对主机设置变量
linux·自动化·ansible
我爱学习好爱好爱5 天前
inventory针对主机组设置变量 host_vars group_vars playbook执行时传入值 Ansible-register
运维·自动化·ansible