Ansibleを使ってAzure上でリソースグループの作成~WindowsVMの諸設定までを自動化する
Pocket

Azure上に、WindowsのVMを用いた環境を構築する必要があったので、Ansibleで構築を一気にやってしまうことにした。今回は、リソースグループから作成して、VMの作成とWinRMの有効化、各VMへの接続、設定までをまとめてみる。
Playbookのサンプルはこちらに置いてあるが、Azure上にAD環境を構築する内容になっているのでそのまま流す場合は注意。また、この情報は2018年6月時点のもので、以後変わっていく可能性が高い点についても注意してもらいたい。

1.Azure-CLIの設定

まず、AnsibleをキックするマシンでAzure-CLIを利用できるようにする必要がある。
Azure-CLI 2.0ではサービスプリンシパルを利用することでmicrosoftアカウントユーザでもログイン情報を保持できるようになった(ちょっと前まではログイン情報保持できなかった)ようだ。とてもありがたい(aws-cliとかではもともとできてたので、使い勝手が同じ方がいい)。

Azure-CLI(azコマンド)はaptやbrewからインストールできるし、公式ドキュメントも充実しているのでそちらを参照のこと。また、サービスプリンシパルの設定についてもこちらに記載があるので参考になるだろう。

2.リソースグループ~仮想ネットワークの作成

まずリソースグループや仮想ネットワークなどを作成しないと始まらないので、それらを作成する。
リソースグループや仮想ネットワーク、セキュリティグループ、Subnet、ストレージアカウントを作成する場合、以下のようなPlaybookを作成する。

---
- name: Create Azure ResourceGroup.
  azure_rm_resourcegroup:
      name: "{{ azure_rg_name }}"
      location: "{{ azure_rg_location }}"

- name: Create Azure VirtualNetwork.
  azure_rm_virtualnetwork:
      resource_group: "{{ azure_rg_name }}"
      name: "{{ azure_vn_name }}"
      address_prefixes_cidr: "{{ azure_vn_cidr }}"
      dns_servers:
        - "8.8.8.8"

- name: Create Security Group.
  azure_rm_securitygroup:
    resource_group: "{{ azure_rg_name }}"
    name: "{{ azure_sg_name }}"
    purge_rules: yes
    rules:
      - name: AllowSpSSH
        protocol: Tcp
        source_address_prefix: "{{ from_global_ip }}"
        destination_port_range: 22
        access: Allow
        priority: 100
        direction: Inbound

- name: Update Security Group.
  azure_rm_securitygroup:
    resource_group: "{{ azure_rg_name }}"
    name: "{{ azure_sg_name }}"
    rules:
      - name: AllowSpRDP
        protocol: Tcp
        source_address_prefix: "{{ from_global_ip }}"
        destination_port_range: 3389
        access: Allow
        priority: 101
        direction: Inbound
      - name: AllowSpWinrm
        protocol: Tcp
        source_address_prefix: "{{ from_global_ip }}"
        destination_port_range: 5985
        access: Allow
        priority: 102
        direction: Inbound
      - name: AllowSpWinrmSSL
        protocol: Tcp
        source_address_prefix: "{{ from_global_ip }}"
        destination_port_range: 5986
        access: Allow
        priority: 103
        direction: Inbound

- name: Create Azure VirtualNetwork Subnet.
  azure_rm_subnet:
    resource_group: "{{ azure_rg_name }}"
    virtual_network_name: "{{ azure_vn_name }}"
    name: "{{ azure_vn_subnet_name }}"
    address_prefix_cidr: "{{ azure_vn_subnet_cidr }}"
    security_group_name: "{{ azure_sg_name }}"

- name: Create storage account
  azure_rm_storageaccount:
    name: "{{ azure_storage_name }}"
    account_type: "{{ azure_storage_type }}"
    resource_group: "{{ azure_rg_name }}"

 

変数で定義している箇所については、以下のような使い方になっている。
実際に使用する場合は適宜書き換えてもらいたい。

  • azure_rg_name … リソースグループ名
  • azure_rg_location … リソースグループのロケーション
  • azure_vn_name … 仮想ネットワーク名
  • azure_vn_cidr … 仮想ネットワークのCIDR
  • azure_sg_name … セキュリティグループ名
  • from_global_ip … アクセス元のグローバルIP(任意)
  • azure_vn_subnet_name … サブネット名
  • azure_vn_subnet_cidr … サブネットのCIDR
  • azure_storage_name … ストレージアカウント名
  • azure_storage_type … ストレージアカウントのタイプ
Sponsored Links

3.VMの作成(WinRM設定含む)

基盤が作成できたら、WindowsVMの作成用Playbookを定義する。
複数台作成できるようにするため、roleを用いる。roleのディレクトリ構成やらについては、ここで説明しなくてもそのへんにいっぱい情報あるので割愛(サンプルではroleになってるので、そちらを参考にしてもらえればいいかと)。

./site.yml(抜粋)

- name: Create VMs
  hosts: localhost
  connection: local
  vars_files:
    - vars/vars.yml
    - vars/azure_vms.yml
  roles:
    - azure_vms

 

./roles/azure_vms/tasks/main.yml

---
- name: Create public IP
  azure_rm_publicipaddress:
    name: "{{ item.name }}-IP"
    allocation_method: Static
    resource_group: "{{ azure_rg_name }}"
  with_items: "{{ azure_vms }}"

- name: Create NIC
  azure_rm_networkinterface:
    name: "{{ item.name }}-NIC"
    subnet: "{{ item.subnet_name }}"
    public_ip_name: "{{ item.name }}-IP"
    private_ip_address: "{{ item.private_ip_address }}"
    private_ip_allocation_method: "{{ item.private_ip_allocation_method }}"
    virtual_network: "{{ azure_vn_name }}"
    resource_group: "{{ azure_rg_name }}"
    security_group_name: "{{ azure_sg_name }}"
  with_items: "{{ azure_vms }}"

- name: Create VM
  azure_rm_virtualmachine:
    name: "{{ item.name }}"
    vm_size: "{{ item.vm_size }}"
    storage_blob: "{{ item.name }}-OS.vhd"
    admin_username: "{{ item.username }}"
    admin_password: "{{ item.password }}"
    os_type: "{{ item.os_type }}"
    os_disk_caching: "{{ item.os_disk_caching }}"
    network_interfaces: "{{ item.name }}-NIC"
    image:
      offer: "{{ item.image_offer }}"
      publisher: "{{ item.image_publisher }}"
      sku: "{{ item.image_sku }}"
      version: "{{ item.image_version }}"
    storage_account: "{{ azure_storage_name }}"
    resource_group: "{{ azure_rg_name }}"
  with_items: "{{ azure_vms }}"

- name: Add VM Extension
  azure_rm_virtualmachine_extension:
    name: "{{ item.name }}-extension"
    location: "{{ azure_rg_location }}"
    resource_group: "{{ azure_rg_name }}"
    virtual_machine_name: "{{ item.name }}"
    publisher: Microsoft.Compute
    virtual_machine_extension_type: CustomScriptExtension
    type_handler_version: 1.8
    settings:  {
      "fileUris": ["https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"],
      "commandToExecute": "powershell.exe -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"
    }
    auto_upgrade_minor_version: true
  with_items: "{{ azure_vms }}"

with_items(指定した要素の内容をループしてitem.XXXで参照できる)で各VMの情報を取得しているので、ちょっとわかりにくいかもしれない。
各item.XXXの内容については、サンプルのこちらのファイルを見てもらったほうがイメージがつくかも。

ここでのポイントは、ラストにあるazure_vm_virtualmachine_extensionで、これが無いとWinRMを有効にできないので注意(後処理で対象のVMにAnsibleから接続できなくなる)。

4.各VMへの接続チェック

最後に、ちゃんとVMにAnsibleから接続できることを確認するためのPlaybookについて抜粋。

./site.yml(抜粋)

- name: Add hosts type
  hosts: localhost
  connection: local
  vars_files:
    - vars/vars.yml
    - vars/azure_vms.yml
  tasks:
    - include: tasks/add_hosts.yml
      with_items: "{{ azure_vms }}"
      loop_control:
        loop_var: user

- name: Ping
  hosts: server
  vars:
    ansible_user: "{{ azure_server_user }}"
    ansible_password: "{{ azure_server_pass }}"
    ansible_port: 5986
    ansible_connection: winrm
    ansible_winrm_server_cert_validation: ignore
  winping:

 

./tasks/add_hosts.yml

---
- name: Get public ip list.
  azure_rm_publicipaddress_facts:
    resource_group: '{{ azure_rg_name }}'
    name: '{{ user.name }}-IP'
  register: azure_ip

- name: Add new instance to host group
  add_host:
    hostname: "{{ item.name | regex_replace('-IP','') }}"
    ansible_host: "{{ item.properties.ipAddress }}"
    groups: "server"
  with_items: "{{ azure_ip.ansible_facts.azure_publicipaddresses }}"

 

add_hostで作成したVMのPublic IPをhostに追加して、それを対象としてwinpingを実行している(Ansibleでログインできるかどうかをチェックしているので、WinRMが動いてないとここで失敗する)。
各VMへの接続チェックまでは行ったので、あとは個別に設定を流してあげればいいかなと(今回はそこまでやらないので、win_pingで疎通確認までにした)。

かなりやっつけだけど、細かい内容についてはSampleで上げてあるPlaybookを参考にしてもらえればと思う。

 

Pocket

Written by blacknon

インフラエンジニア(…のつもり)。 仕事で使うならクライアントはWindowsよりはUNIXの方が好き。 大体いつも眠い。

Leave a Comment

メールアドレスが公開されることはありません。

*