使用 Ansible 在 Azure 中创建 Windows 虚拟机
本文介绍如何使用 Ansible 在 Azure 中部署 Windows Server 2019 VM。
在本文中,学习如何:
- 创建资源组
- 创建虚拟网络、公共 IP、网络安全组和网络接口
- 部署 Windows Server 虚拟机
- 通过 WinRM 连接到虚拟机
- 运行 Ansible playbook 配置 Windows IIS
先决条件
- Azure 订阅:如果没有 Azure 订阅,请在开始之前创建一个免费帐户。
- Azure 服务主体:创建服务主体,记下以下值:appId、displayName、密码和租户 。
安装 Ansible - 执行以下任一选项:
- 在 Linux 虚拟机上安装和配置 Ansible
- 配置 Azure Cloud Shell
向 Ansible 添加 WinRM 支持
要通过 WinRM 进行通信,Ansible 控制服务器需要 python 包 pywinrm
。
在 Ansible 服务器上运行以下命令以安装 pywinrm
:
pip install "pywinrm>=0.3.0"
有关详细信息,请参阅 Ansible 的 Windows 远程管理。
创建资源组
创建名为的 azure_windows_vm.yml
Ansible playbook,并将以下内容复制到 playbook:
---
- name: Create Azure VM
hosts: localhost
connection: local
tasks:
- name: Create resource group
azure_rm_resourcegroup:
name: myResourceGroup
location: eastus
要点:
- 设置为
hosts
localhost ,并在connection
_local_
Ansible 服务器上本地运行 playbook。
创建虚拟网络和子网
将以下任务添加到 azure_windows_vm.yml
Ansible playbook 以创建虚拟网络:
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: myResourceGroup
name: vNet
address_prefixes: "10.0.0.0/16"
- name: Add subnet
azure_rm_subnet:
resource_group: myResourceGroup
name: subnet
address_prefix: "10.0.1.0/24"
virtual_network: vNet
创建公共 IP 地址
将以下任务添加到 azure_windows_vm.yml
playbook 以创建公共 IP 地址:
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: myResourceGroup
allocation_method: Static
name: pip
register: output_ip_address
- name: Output public IP
debug:
msg: "The public IP is {{ output_ip_address.state.ip_address }}"
要点:
- Ansible
register
模块用于将azure_rm_publicipaddress
中的输出存储在名为output_ip_address
的变量中。 - 该
debug
模块用于将 VM 的公共 IP 地址输出到控制台。
创建网络安全组和 NIC
网络安全组定义哪些流量可以进入 VM,哪些不可以。
要打开 WinRM 和 HTTP 端口,请将以下任务添加到 azure_windows_vm.yml
Ansible playbook:
- name: Create Network Security Group
azure_rm_securitygroup:
resource_group: myResourceGroup
name: networkSecurityGroup
rules:
- name: 'allow_rdp'
protocol: Tcp
destination_port_range: 3389
access: Allow
priority: 1001
direction: Inbound
- name: 'allow_web_traffic'
protocol: Tcp
destination_port_range:
- 80
- 443
access: Allow
priority: 1002
direction: Inbound
- name: 'allow_powershell_remoting'
protocol: Tcp
destination_port_range:
- 5985
- 5986
access: Allow
priority: 1003
direction: Inbound
- name: Create a network interface
azure_rm_networkinterface:
name: nic
resource_group: myResourceGroup
virtual_network: vNet
subnet_name: subnet
security_group: networkSecurityGroup
ip_configurations:
- name: default
public_ip_address_name: pip
primary: True
要点:
- 虚拟网络接口卡将 VM 连接到其虚拟网络、公共 IP 地址和安全组。
azure_rm_securitygroup
创建 Azure 网络安全组,通过允许端口5985
和5986
,允许 WinRM 流量从 Ansible 服务器到远程主机。
创建虚拟机
下一步是创建虚拟机,该虚拟机使用在本文的前述部分创建的所有资源。
将以下任务添加到 azure_windows_vm.yml
Ansible playbook:
- name: Create VM
azure_rm_virtualmachine:
resource_group: myResourceGroup
name: win-vm
vm_size: Standard_DS1_v2
admin_username: azureuser
admin_password: "{{ password }}"
network_interfaces: nic
os_type: Windows
image:
offer: WindowsServer
publisher: MicrosoftWindowsServer
sku: 2019-Datacenter
version: latest
no_log: true
{{ password }}
的 admin_password
值是一个 Ansible 变量,其中包含 Windows VM 密码。 要安全填充该变量,请在 playbook 的开头添加一个 var_prompts
条目。
- name: Create Azure VM
hosts: localhost
connection: local
vars_prompt:
- name: password
prompt: "Enter local administrator password"
tasks:
要点:
- 避免以纯文本形式存储敏感数据。 使用
var_prompts
在运行时填充变量。 添加no_log: true
以防止密码被记录。
配置 WinRM 侦听器
Ansible 使用 PowerShell 通过 WinRM 连接和配置 Windows 远程主机。
要配置 WinRM,请添加以下 ext azure_rm_virtualmachineextension
:
- name: Create VM script extension to enable HTTPS WinRM listener
azure_rm_virtualmachineextension:
name: winrm-extension
resource_group: myResourceGroup
virtual_machine_name: win-vm
publisher: Microsoft.Compute
virtual_machine_extension_type: CustomScriptExtension
type_handler_version: '1.9'
settings: '{"fileUris": ["https://raw.githubusercontent.com/ansible/ansible-documentation/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"],"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"}'
auto_upgrade_minor_version: true
WinRM 在完全配置之前,Ansible 无法连接到 VM。
将以下任务添加到 playbook 以等待 WinRM 连接:
- name: Get facts for one Public IP
azure_rm_publicipaddress_info:
resource_group: myResourceGroup
name: pip
register: publicipaddresses
- name: set public ip address fact
set_fact: publicipaddress="{{ publicipaddresses | json_query('publicipaddresses[0].ip_address')}}"
- name: wait for the WinRM port to come online
wait_for:
port: 5986
host: '{{ publicipaddress }}'
timeout: 600
要点:
- 使用
azure_rm_virtualmachineextension
模块可在 Azure Windows 本地运行 PowerShell 脚本。 运行ConfigureRemotingForAnsible.ps1
PowerShell 脚本可通过创建自签名证书并打开所需的端口来配置 WinRM 以连接 Ansible。 azure_rm_publicipaddress_info
模块从 Azure 查询公共 IP 地址,然后set_fact
将输出存储在变量中供wait_for
模块使用。
完整的示例 Ansible playbook
此部分列出在本文中从头至尾生成的整个示例 Ansible playbook。
---
- name: Create Azure VM
hosts: localhost
connection: local
vars_prompt:
- name: password
prompt: "Enter local administrator password"
tasks:
- name: Create resource group
azure_rm_resourcegroup:
name: myResourceGroup
location: eastus
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: myResourceGroup
name: vNet
address_prefixes: "10.0.0.0/16"
- name: Add subnet
azure_rm_subnet:
resource_group: myResourceGroup
name: subnet
address_prefix: "10.0.1.0/24"
virtual_network: vNet
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: myResourceGroup
allocation_method: Static
name: pip
register: output_ip_address
- name: Output public IP
debug:
msg: "The public IP is {{ output_ip_address.state.ip_address }}"
- name: Create Network Security Group
azure_rm_securitygroup:
resource_group: myResourceGroup
name: networkSecurityGroup
rules:
- name: 'allow_rdp'
protocol: Tcp
destination_port_range: 3389
access: Allow
priority: 1001
direction: Inbound
- name: 'allow_web_traffic'
protocol: Tcp
destination_port_range:
- 80
- 443
access: Allow
priority: 1002
direction: Inbound
- name: 'allow_powershell_remoting'
protocol: Tcp
destination_port_range:
- 5985
- 5986
access: Allow
priority: 1003
direction: Inbound
- name: Create a network interface
azure_rm_networkinterface:
name: nic
resource_group: myResourceGroup
virtual_network: vNet
subnet_name: subnet
security_group: networkSecurityGroup
ip_configurations:
- name: default
public_ip_address_name: pip
primary: True
- name: Create VM
azure_rm_virtualmachine:
resource_group: myResourceGroup
name: win-vm
vm_size: Standard_DS1_v2
admin_username: azureuser
admin_password: "{{ password }}"
network_interfaces: nic
os_type: Windows
image:
offer: WindowsServer
publisher: MicrosoftWindowsServer
sku: 2019-Datacenter
version: latest
no_log: true
- name: Create VM script extension to enable HTTPS WinRM listener
azure_rm_virtualmachineextension:
name: winrm-extension
resource_group: myResourceGroup
virtual_machine_name: win-vm
publisher: Microsoft.Compute
virtual_machine_extension_type: CustomScriptExtension
type_handler_version: '1.9'
settings: '{"fileUris": ["https://raw.githubusercontent.com/ansible/ansible-documentation/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"],"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"}'
auto_upgrade_minor_version: true
- name: Get facts for one Public IP
azure_rm_publicipaddress_info:
resource_group: myResourceGroup
name: pip
register: publicipaddresses
- name: set public ip address fact
set_fact: publicipaddress="{{ publicipaddresses | json_query('publicipaddresses[0].ip_address')}}"
- name: wait for the WinRM port to come online
wait_for:
port: 5986
host: '{{ publicipaddress }}'
timeout: 600
连接到 Windows 虚拟机
创建新的 Ansible playbook,并将 connect_azure_windows_vm.yml
以下内容复制到 playbook 中:
---
- hosts: all
vars_prompt:
- name: ansible_password
prompt: "Enter local administrator password"
vars:
ansible_user: azureuser
ansible_connection: winrm
ansible_winrm_transport: ntlm
ansible_winrm_server_cert_validation: ignore
tasks:
- name: Test connection
win_ping:
运行 Ansible playbook。
ansible-playbook connect_azure_windows_vm.yml -i <publicIPaddress>,
将 <publicIPaddress>
替换为你的虚拟机地址。
要点:
- Ansible 的配置确定了 Ansible 如何连接到远程主机并向其进行身份验证。 需要定义以连接到 Windows 主机的变量取决于你所选择的 WinRM 连接类型和身份验证选项。 有关详细信息,请参阅连接到 Windows 主机和Windows 身份验证选项。
- 在公共 IP 地址后面添加逗号会绕过 Ansible 的清单分析程序。 通过此方法,无需清单文件即可运行 playbook。
清理资源
将以下代码另存为
delete_rg.yml
。--- - hosts: localhost tasks: - name: Deleting resource group - "{{ name }}" azure_rm_resourcegroup: name: "{{ name }}" state: absent register: rg - debug: var: rg
使用 ansible-playbook 命令运行 playbook。 将占位符替换为要删除的资源组的名称。 将删除资源组内的所有资源。
ansible-playbook delete_rg.yml --extra-vars "name=<resource_group>"
要点:
- 由于 playbook 的
register
变量和debug
部分,因此在命令完成时,将显示结果。
- 由于 playbook 的