教程:使用 Ansible 配置 Azure 资源的动态库存

重要

需要 Ansible 2.8(或更高版本)才能运行本文中示例的 playbooks。

Ansible 动态清单功能消除了维护静态清单文件的负担。

在本教程中,将使用 Azure 的动态清单插件填充 Ansible 清单。

在这篇文章中,你将学会如何:

  • 配置两个测试虚拟机。
  • 将标记添加到 Azure 虚拟机
  • 生成动态清单
  • 使用条件组和键控组设置组成员身份
  • 在动态清单中的组上运行剧本

先决条件

  • Azure 订阅:如果没有 Azure 订阅,请在开始之前创建 一个免费帐户
  • Azure 服务主体创建服务主体,记下以下值: appIddisplayName密码租户

创建 Azure VM

  1. 登录到 Azure 门户

  2. 打开 Cloud Shell

  3. 创建一个 Azure 资源组来保存本教程的虚拟机。

    重要

    在此步骤中创建的 Azure 资源组必须具有完全小写的名称。 否则,动态清单的生成将失败。

    az group create --resource-group ansible-inventory-test-rg --location eastus
    
  4. 使用以下技术之一在 Azure 上创建两个 Linux 虚拟机:

    • Ansible playbook - 文章:使用 Ansible 在 Azure 中创建基本的 Linux 虚拟机使用 Ansible 在 Azure 中创建基本 Windows 虚拟机 ,其中演示了如何通过 Ansible playbook 创建虚拟机。

    • Azure CLI - 在 Cloud Shell 中发出以下命令,以创建两个虚拟机:

      az vm create \
      --resource-group ansible-inventory-test-rg \
      --name win-vm \
      --image MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest \
      --admin-username azureuser \
      --admin-password <password>
      
      az vm create \
      --resource-group ansible-inventory-test-rg \
      --name linux-vm \
      --image Ubuntu2204 \
      --admin-username azureuser \
      --admin-password <password>
      

      <password>替换为您的密码。

添加应用程序角色标记

标记用于组织和分类 Azure 资源。 通过分配 Azure VM 应用程序角色,可以使用标记作为 Azure 动态清单中的组名称。

运行以下命令来更新 VM 标记:

az vm update \
--resource-group ansible-inventory-test-rg \
--name linux-vm \
--set tags.applicationRole='message-broker' 

az vm update \
--resource-group ansible-inventory-test-rg \
--name win-vm \
--set tags.applicationRole='web-server' 

“定义标记策略”中详细了解 Azure 标记策略。

生成动态清单

Ansible 提供 Azure 动态清单插件

以下步骤将引导你完成使用插件:

  1. 创建名为 myazure_rm.yml 的动态清单

    plugin: azure_rm
    include_vm_resource_groups:
      - ansible-inventory-test-rg
    auth_source: auto
    

    关键点:

    • Ansible 使用清单文件名和扩展名来标识要使用的清单插件。 若要使用 Azure 动态清单插件,该文件必须以azure_rm结尾,并且文件扩展名为ymlyaml
  2. 运行以下命令以查询资源组中的 VM:

    ansible-inventory -i myazure_rm.yml --graph
    
  3. 运行此命令时,会看到类似于以下输出的结果:

    @all:
      |--@ungrouped:
      |  |--linux-vm_cdb4
      |  |--win-vm_3211
    

这两个 VM 都属于该 ungrouped 组,该组是 Ansible 清单中的组的 all 子级。

关键点

  • 默认情况下,Azure 动态清单插件返回全局唯一的名称。 因此,VM 名称可能包含额外的字符。 可以通过在动态清单中添加 plain_host_names: yes 来禁用行为。

查找 Azure 虚拟机主机变量

运行以下命令以查看所有 hostvars

ansible-inventory -i myazure_rm.yml --list
{
    "_meta": {
        "hostvars": {
            "linux-vm_cdb4": {
                "ansible_host": "52.188.118.79",
                "availability_zone": null,
                "computer_name": "linux-vm",
                "default_inventory_hostname": "linux-vm_cdb4",
                "id": "/subscriptions/<subscriptionid>/resourceGroups/ansible-inventory-test-rg/providers/Microsoft.Compute/virtualMachines/linux-vm",
                "image": {
                    "offer": "0001-com-ubuntu-server-jammy",
                    "publisher": "Canonical",
                    "sku": "22_04-lts-gen2",
                    "version": "latest"
                },
                ...,
                "tags": {
                    "applicationRole": "message-broker"
                },
                ...
            },
            "win-vm_3211": {
                "ansible_host": "52.188.112.110",
                "availability_zone": null,
                "computer_name": "win-vm",
                "default_inventory_hostname": "win-vm_3211",
                "id": "/subscriptions/<subscriptionid>/resourceGroups/ansible-inventory-test-rg/providers/Microsoft.Compute/virtualMachines/win-vm",
                "image": {
                    "offer": "WindowsServer",
                    "publisher": "MicrosoftWindowsServer",
                    "sku": "2019-Datacenter",
                    "version": "latest"
                },
                ...
                "tags": {
                    "applicationRole": "web-server"
                },
                ...
            }
        }
    },
    ...
    }
}

通过从 Azure 拉取信息,动态清单将填充 hostvars 每个 Azure VM。 然后,确定 hostvars Ansible 清单中的 VM 组成员身份。

使用“conditional_groups”分配组成员身份

每个条件组由两个部分组成。 组的名称以及将成员添加到组的条件。

使用属性 image.offerlinux-vm 创建条件组成员身份。

打开 myazure_rm.yml 动态清单并添加以下内容 conditional_group

plugin: azure_rm
include_vm_resource_groups:
  - ansible-inventory-test-rg
auth_source: auto
conditional_groups:
  linux: "'ubuntu' in image.offer"
  windows: "'WindowsServer' in image.offer"

使用--graph选项运行ansible-inventory

ansible-inventory -i myazure_rm.yml --graph
@all:
  |--@linux:
  |  |--linux-vm_cdb4
  |--@ungrouped:
  |--@windows:
  |  |--win-vm_3211

从输出中,可以看到 VM 不再与 ungrouped 组关联。 而是将每个 VM 分配给动态清单创建的新组。

关键点

  • 条件组允许你在清单中命名特定组,并使用hostvars来填充它们。

使用 keyed_groups 指定组成员资格

键组分配组成员身份的方式与条件组相同,但在使用键化组时,组名称也会动态填充。

将以下keyed_group添加到 myazure_rm.yml 动态清单:

plugin: azure_rm
include_vm_resource_groups:
  - ansible-inventory-test-rg
auth_source: auto
conditional_groups:
  linux: "'ubuntu' in image.offer"
  windows: "'WindowsServer' in image.offer"
keyed_groups:
 - key: tags.applicationRole

请使用--graph选项运行ansible-inventory

ansible-inventory -i myazure_rm.yml --graph
@all:
  |--@_message_broker:
  |  |--linux-vm_cdb4
  |--@_web_server:
  |  |--win-vm_3211
  |--@linux:
  |  |--linux-vm_cdb4
  |--@ungrouped:
  |--@windows:
  |  |--win-vm_3211

从输出中,你将看到另外两个组 _message_broker_web_server。 通过使用键控组,applicationRole 标记将填充组名称和组成员身份。

关键点

  • 默认情况下,键式组包括分隔符。 若要删除分隔符,请在键属性下添加 separator: ""

使用群组名称模式运行 playbooks

使用动态清单创建的组以锁定子组为目标。

  1. 创建一个名为win_ping.yml 的手册,内容如下:

    ---
    - hosts: windows
      gather_facts: false
    
      vars_prompt:
        - name: username
          prompt: "Enter local username"
          private: false
        - name: password
          prompt: "Enter password"
    
      vars:
        ansible_user: "{{ username }}"
        ansible_password: "{{ password }}"
        ansible_connection: winrm
        ansible_winrm_transport: ntlm
        ansible_winrm_server_cert_validation: ignore
    
      tasks:
        - name: run win_ping
          win_ping:
    
  2. 运行win_ping.yml playbook。

    ansible-playbook win_ping.yml -i myazure_rm.yml
    

    出现提示时,请为 Azure Windows VM 输入usernamepassword

    Enter local username: azureuser
    Enter password:
    
    PLAY [windows] **************************************************************************************************************************************
    
    TASK [run win_ping] *********************************************************************************************************************************
    ok: [win-vm_3211]
    
    PLAY RECAP ******************************************************************************************************************************************
    win-vm_3211                : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    

    重要

    如果收到错误 winrm or requests is not installed: No module named 'winrm',请使用以下命令安装 pywinrm: pip install "pywinrm>=0.3.0"

  3. 创建一个名为ping.yml的第二个 playbook,并包含以下内容:

    ---
    - hosts: all
      gather_facts: false
    
      vars_prompt:
        - name: username
          prompt: "Enter ssh user"
        - name: password
          prompt: "Enter password for ssh user"
    
      vars:
        ansible_user: "{{ username }}"
        ansible_password: "{{ password }}"
        ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
    
      tasks:
        - name: run ping
          ping:
    
  4. 运行ping.yml playbook。

    ansible-playbook ping.yml -i myazure_rm.yml
    

    出现提示时,输入 Azure Linux VM 的 usernamepassword

    Enter ssh username: azureuser
    Enter password for ssh user:
    
    PLAY [linux] *******************************************************************************************************
    
    TASK [run ping] ****************************************************************************************************
    ok: [linux-vm_cdb4]
    
    PLAY RECAP *********************************************************************************************************
    linux-vm_cdb4              : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
    

清理资源

  1. 运行 az group delete 以删除资源组。 将删除资源组中的所有资源。

    az group delete --name <resource_group>
    
  2. 使用 az group show 验证是否已删除资源组。

    az group show --name <resource_group>
    

后续步骤