azure-arm Windows 使用 Ansible 配置 VM

azure-arm Windows VM provisioning with Ansible

是否可以在 Mac 上使用 Packer 在 azure-arm 上创建一个 Windows VM,并使用 Ansible 作为配置器?我正在寻找一个工作示例。

Packer documentation mentions that winrm communicator needs a connection_plugin for Packer,但是从Ansible 2.6开始就没有更新了。

ansible_playbook.sh 使用这些库和 python 3.6

运行 ansible-playbook
    #!/bin/bash
    source /usr/local/miniconda3/etc/profile.d/conda.sh && conda activate ${CONDA_ENV} && ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 /usr/local/miniconda3/envs/py36_64/bin/ansible-playbook "$@"

我的 ansible-playbook packer.yml 很简单:

    ---
    - name: setup new Azure box
      hosts: default
      gather_facts: no

      vars_files:
        - dependencies.yml

      roles:
        - {role: ansible-windows-java, tags: java}
        - {role: itigoag.chrome, tags: chrome}

我的 Azure packer.json 看起来像这样:

{
  "builders": [
    {
      "client_id": "{{user `arm_client_id`}}",
      "client_secret": "{{user `arm_client_secret`}}",
      "communicator": "winrm",
      "image_offer": "VisualStudio",
      "image_publisher": "MicrosoftVisualStudio",
      "image_sku": "VS-2017-Comm-Latest-WS2016",
      "image_version": "latest",
      "location": "{{user `arm_location`}}",
      "managed_image_name": "windows2016-vsc",
      "managed_image_resource_group_name": "{{user `arm_resource_group`}}",
      "os_type": "Windows",
      "subscription_id": "{{user `arm_subscription_id`}}",
      "tenant_id": "{{user `arm_tenant_id`}}",
      "type": "azure-arm",
      "winrm_insecure": "true",
      "winrm_timeout": "3m",
      "winrm_use_ssl": "true",
      "winrm_username": "packer",
      "vm_size": "Standard_D8_v3"
    }
  ],
  "provisioners": [
    {
      "command": "/usr/local/bin/ansible_playbook.sh",
      "extra_arguments": [
        "--connection", "packer",
        "--extra-vars", "ansible_shell_type=powershell ansible_shell_executable=None"
      ],
      "playbook_file": "packer.yml",
      "type": "ansible"
    }
  ],
  "variables": {
    "arm_client_id": "{{env `ARM_CLIENT_ID`}}",
    "arm_client_secret": "{{env `ARM_CLIENT_SECRET`}}",
    "arm_location": "{{env `ARM_LOCATION`}}",
    "arm_resource_group": "{{env `ARM_RESOURCE_GROUP`}}",
    "arm_storage_account": "{{env `ARM_STORAGE_ACCOUNT`}}",
    "arm_subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}",
    "arm_tenant_id": "{{env `ARM_TENNANT_ID`}}"
  }
}

创建了一个 VM,但进程在一段时间后停止,日志中出现以下错误,指向使用 ssh,但也提到了 winrm!不清楚这应该如何工作。

==> azure-arm: Waiting for WinRM to become available...
==> azure-arm: #< CLIXML
    azure-arm: WinRM connected.
==> azure-arm: <Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
==> azure-arm: Connected to WinRM!
==> azure-arm: Provisioning with Ansible...
==> azure-arm: Executing Ansible: /usr/local/bin/ansible_playbook.sh --extra-vars packer_build_name=azure-arm packer_builder_type=azure-arm -o IdentitiesOnly=yes -i /var/folders/hs/b03p_c310l70v6zx1byb4l0r0000gp/T/packer-provisioner-ansible072959676 /Users/bas/code/vd/azure-win2016/packer.yml -e ansible_ssh_private_key_file=/var/folders/hs/b03p_c310l70v6zx1byb4l0r0000gp/T/ansible-key860669585 --connection packer --extra-vars ansible_shell_type=powershell ansible_shell_executable=None
    azure-arm:
    azure-arm: PLAY [setup new Azure box] *****************************************************
    azure-arm:
    azure-arm: TASK [ansible-windows-java : Install Java] *************************************
    azure-arm: Saturday 29 June 2019  20:58:35 +0200 (0:00:00.155)       0:00:00.155 *********
    azure-arm: fatal: [default]: FAILED! => changed=false
    azure-arm:   module_stderr: |-
    azure-arm:     Warning: Permanently added '[127.0.0.1]:54679' (RSA) to the list of known hosts.
    azure-arm:     Parameter format not correct - ;
    azure-arm:   module_stdout: ''
    azure-arm:   msg: |-
    azure-arm:     MODULE FAILURE
    azure-arm:     See stdout/stderr for the exact error
    azure-arm:   rc: 1
    azure-arm:
    azure-arm: PLAY RECAP *********************************************************************
    azure-arm: default                    : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
    azure-arm:
    azure-arm: Saturday 29 June 2019  20:58:36 +0200 (0:00:00.726)       0:00:00.881 *********
    azure-arm: ===============================================================================
    azure-arm: ansible-windows-java : Install Java ------------------------------------- 0.73s
    azure-arm: Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
==> azure-arm:
==> azure-arm: Cleanup requested, deleting resource group ...

Is it possible to use Packer on a Mac to create a Windows VM on azure-arm with Ansible as provisioner?

您只需使用 Ansible 供应器通过 Packer 创建 Windows VM 映像,然后从您创建的映像创建 Windows VM。

关于Packer中的Ansible provisioner,可以看看Ansible Provisioner. And for Windows VM image, you can take a look at How to use Packer to create Windows virtual machine images in Azure。创建要在 VM 中执行的 Ansible 文件并使用它。

创建 VM 映像后,您可以从该映像创建 Windows VM。

在 Microsoft 的帮助下,我找到了 packer.json:

的解决方案
{
  "builders": [
    {
      "client_id": "{{user `arm_client_id`}}",
      "client_secret": "{{user `arm_client_secret`}}",
      "communicator": "winrm",
      "image_offer": "{{user `image_offer`}}",
      "image_publisher": "{{user `image_publisher`}}",
      "image_sku": "{{user `image_sku`}}",
      "image_version": "latest",
      "location": "{{user `arm_location`}}",
      "managed_image_name": "{{user `managed_image_name`}}",
      "managed_image_resource_group_name": "{{user `arm_resource_group`}}",
      "os_type": "Windows",
      "subscription_id": "{{user `arm_subscription_id`}}",
      "tenant_id": "{{user `arm_tenant_id`}}",
      "type": "azure-arm",
      "vm_size": "Standard_D8_v3",
      "winrm_insecure": true,
      "winrm_timeout": "1h",
      "winrm_use_ssl": true,
      "winrm_username": "packer"
    }
  ],
  "provisioners": [
    {
      "type": "powershell",
      "inline": "Invoke-RestMethod -Headers @{\"Metadata\"=\"true\"} -URI 'http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/publicIpAddress?api-version=2017-08-01&format=text' | Out-File -Append -Encoding utf8 C:/Windows/Temp/ip-address"
    },
    {
      "type": "file",
      "direction": "download",
      "source": "C:/Windows/Temp/ip-address",
      "destination": "./ansible/hosts"
    },
    {
      "type": "shell-local",
      "inline": [
        "IP=`cut -b 4- ansible/hosts`",
        "echo \"[default]\n${IP}\" > ansible/hosts"
      ]
    },
    {
      "type": "shell-local",
      "environment_vars": "WINRMPASS={{.WinRMPassword}}",
      "command": "ansible-playbook -vv -i ./ansible/hosts packer.yml"
    },
    {
    "type": "powershell",
    "inline": [
      "(gcim win32_service | ? { $_.name -match 'WindowsAzureGuestAgent' }).PathName",
      "get-service WindowsAzureGuestAgent | ft -autosize"
      ]
    },
    {
      "type": "powershell",
      "inline": [
        " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.",
        "  while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
        "  while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }",
        "  while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
        "if( Test-Path $Env:SystemRoot\windows\system32\Sysprep\unattend.xml ){ rm $Env:SystemRoot\windows\system32\Sysprep\unattend.xml -Force}",
        "& $env:SystemRoot\System32\Sysprep\Sysprep.exe /oobe /generalize /quiet /quit",
        "while($true) { $imageState = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10  } else { break } }"
      ]
    }
  ],
  "variables": {
    "arm_client_id": "{{env `ARM_CLIENT_ID`}}",
    "arm_client_secret": "{{env `ARM_CLIENT_SECRET`}}",
    "arm_location": "{{env `ARM_LOCATION`}}",
    "arm_resource_group": "{{env `ARM_RESOURCE_GROUP`}}images",
    "arm_subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}",
    "arm_tenant_id": "{{env `ARM_TENNANT_ID`}}",
    "image_offer": "{{env `ARM_IMAGE_OFFER`}}",
    "image_publisher": "{{env `ARM_IMAGE_PUBLISHER`}}",
    "image_sku": "{{env `ARM_IMAGE_SKU`}}",
    "managed_image_name": "{{env `ARM_MANAGED_IMAGE_NAME`}}"
  }
}