共用方式為


使用 Ansible 在 Azure 中建立 Windows 虛擬機器

本文說明如何使用 Ansible 在 Azure 中部署 Windows Server 2019 VM。

在本文中,您將學會如何:

  • 建立資源群組
  • 建立虛擬網路、公用 IP、網路安全性群組和網路介面
  • 部署 Windows Server 虛擬機器
  • 透過 WinRM 連線到虛擬機器
  • 執行 Ansible 教戰手冊以設定 Windows IIS

先決條件

  • Azure 訂用帳戶:如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶
  • Azure 服務主體建立服務主體,並記下下列值:appIddisplayName密碼租戶

將 WinRM 支援新增至 Ansible

若要透過 WinRM 進行通訊,Ansible 控制伺服器需要 python 套件 pywinrm

在 Ansible 伺服器上執行下列命令進行安裝 pywinrm

pip install "pywinrm>=0.3.0"

如需詳細資訊,請參閱 適用於 Ansible 的 Windows 遠端管理

建立資源群組

建立名為的 azure_windows_vm.yml Ansible 教戰手冊、並將下列內容複製到教戰手冊中:

---
- name: Create Azure VM
  hosts: localhost
  connection: local
  tasks:

  - name: Create resource group
    azure_rm_resourcegroup:
      name: myResourceGroup
      location: eastus

關鍵點:

  • 設定 hostslocalhostconnection 作為 _local_,將在 Ansible 伺服器上本機執行劇本。

建立虛擬網路與子網路

將下列任務新增至 azure_windows_vm.yml Ansible 教戰手冊,以建立虛擬網路:

  - 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 流程手冊,以建立公共 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 模組可用來將虛擬機器的公用 IP 位址輸出至主控台。

建立網路安全性群組和 NIC

網路安全性群組會定義允許和不允許到達 VM 的流量。

若要開啟 WinRM 和 HTTP 連接埠,請將下列任務新增至 Ansible 劇本:

  - 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 網路安全性群組,以使 Ansible 伺服器能夠透過允許通過連接埠 59855986 的方式,將 WinRM 資料流發送到遠端主機。

建立虛擬機

接下來,建立一個虛擬機器,以使用您在本文先前各節中建立的所有資源。

將以下任務新增至 azure_windows_vm.yml Ansible 播放簿:

  - 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

admin_password{{ password }}值是包含 Windows VM 密碼的 Ansible 變數。 若要安全地填入該變數,請在教戰手冊的開頭新增 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。

將下列工作加入至操作手冊中,以等待 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 腳本。 執行 PowerShell 指令碼 ConfigureRemotingForAnsible.ps1 會先建立自我簽署憑證,並開啟 Ansible 連線所需的連接埠來設定 WinRM。
  • 模組 azure_rm_publicipaddress_info 會從 Azure 查詢公用 IP 位址,然後 set_fact 將輸出儲存在變數中,以供 wait_for 模組使用。

完整範例 Ansible 腳本

本節列出您在本篇文章中建立的整個 Ansible 範例指令手冊。

---
- 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 虛擬機器

建立名為的新 connect_azure_windows_vm.yml Ansible 教戰手冊,並將下列內容複製到教戰手冊中:

---
- 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 的清單剖析器。 此技術可讓您在沒有清單檔案的情況下執行劇本。

清理資源

  1. 將下列程式碼儲存為 delete_rg.yml

    ---
    - hosts: localhost
      tasks:
        - name: Deleting resource group - "{{ name }}"
          azure_rm_resourcegroup:
            name: "{{ name }}"
            state: absent
          register: rg
        - debug:
            var: rg
    
  2. 使用 ansible-playbook 命令執行教戰手冊。 將佔位符取代為要刪除的資源組名稱。 資源群組內的所有資源都會被刪除。

    ansible-playbook delete_rg.yml --extra-vars "name=<resource_group>"
    

    重點

    • 由於教戰手冊中的register變數和debug區段,當命令完成時,結果會顯示。

後續步驟