24
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AnsibleのVmware系モジュールを使ったのでまとめ

Posted at

はじめに

タイトルのようにAnsibleでVmwareのGuestVMを作ったり色々便利に使いたい、というケースがあったのでこれを機に触ってみました。
ついでにDynamic Inventoryも使えると便利かなと思い、こちらも触ってみました。

動作検証環境

  • Vmware側
    • VMware vCenter Server Appliance, 6.7.0, 42000
    • VMware ESXi, 6.7.0, 13006603
  • クライアント(Ansible実行環境)側
    • OS: CentOS 7
      • 一応Dockerのpython:latestでも試しました
    • Python 3.8.1
      • python2系でもvmware系モジュールは動きますが、Dynamic Inventoryを使おうとするとsetuptoolsという依存パッケージがPython 3.5以上でないと対応してなかったため3.5以上のほうが幸せになれそうです
    • ansible==2.9.5
    • pyvmomi==6.7.3

使用したモジュール

Vmwareモジュール一覧

Vmware系のモジュールは歴史的には大きく分けて2種類あったようで、例えばGuestVMの作成・削除をするモジュールとしては

の二通りの書き方があったようですが、上記のようにvmware_guestに統合されたようなので、こちらを使っていきます。
(細かい歴史的経緯はよく知りません。。)

各種準備

Vmware側

vmware系モジュールの多くはvCenterサーバ経由でのAPIを利用しているようで、vCenterサーバがほぼ必須となります。
(vsphere系モジュールにはESXiに対してアクションできるものもあったとか何とか)
私が検証した環境にはvCenterサーバがなかったので仮想アプライアンスをデプロイするところから始めましたが、今回はこちらの内容は割愛します。

vCenterの各種情報をパラメータとして指定する必要があるのであらかじめ整理・取得しておきましょう。
今回は例として以下とします。

vCenter情報
ホスト名 192.168.0.1 (IPアドレスで可)
ユーザ名 administrator@vsphere.local
パスワード password
データセンター名 Datcenter

クライアント(Ansible実行環境)側

今回は簡単に検証したかったのでansibleも入っていない状況からバージョン指定せずにインストールしていきます。

$ pip install ansible pyvmomi

実際にPlaybook等を書いていく

ここからPlaybookなどを書いていきますが、その前に以降のPlaybookで使い回しするであろうvCenterの情報をあらかじめ変数としてファイルに書いておきましょう。

vars_vmware.yml
vcenter_hostname: 192.168.0.1
vcenter_username: administrator@vsphere.local
vcenter_password: password
vcenter_datacenter: Datacenter

Vmwareへの接続確認

細かい操作・変更を始める前にちゃんとVmwareに接続できているか確認してみましょう。
とりあえずシンプルそうなvmware_about_infoモジュールを使ってました。
tasksの中身はリンクにあるサンプルほぼそのままです。
一般的なモジュールはssh接続したリモートサーバで実行するものが多いですが、
vmware系のモジュールは大抵delegate_to: localhostと書かれているようにpyvmomiパッケージを持つansible実行ホストで実行します。

test.yml
- hosts: local
  gather_facts: false
  vars_files:
  - vars_vmware.yml
  tasks:
  - name: Provide information about vCenter
    vmware_about_info:
      hostname: "{{ vcenter_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      validate_certs: false
    delegate_to: localhost
    register: cluster_info

  - debug:
      var: cluster_info

インベントリも今回はlocalhostを設定しました。

local.ini
[local]
localhost

Playbookを実行してみます。

$ ansible-playbook -i local.ini test.yml 

PLAY [local] ***********************************************************************************************************************************************************************************************

TASK [Provide information about vCenter] *******************************************************************************************************************************************************************
ok: [localhost -> localhost]

TASK [debug] ***********************************************************************************************************************************************************************************************
ok: [localhost] => {
    "cluster_info": {
        "about_info": {
            "api_type": "VirtualCenter", 
            "api_version": "6.7.3", 
            "build": "15129973", 
            "instance_uuid": "*****-******", 
            "license_product_name": "VMware VirtualCenter Server", 
            "license_product_version": "6.0", 
            "locale_build": "000", 
            "locale_version": "INTL", 
            "os_type": "linux-x64", 
            "product_full_name": "VMware vCenter Server 6.7.0 build-15129973", 
            "product_line_id": "vpx", 
            "product_name": "VMware vCenter Server", 
            "vendor": "VMware, Inc.", 
            "version": "6.7.0"
        }, 
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": false, 
        "failed": false
    }
}

PLAY RECAP *************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

エラーなく接続して値が取得できてますね!

GuestVMの作成(From Template)

今度はvmware_guestモジュールを使ってGuestVMを作成します。
おそらく一番使われていそうなモジュールだと思いますが、実際に動かす前に諸々準備をする必要があります。

VMテンプレートの作成

vmware_guestモジュールで最小限のパラメータでゲストVMを作成した場合はOSがインストールされる前の空っぽの状態になります。
せっかくAnsibleでゲストVMを作成したのにそのままパッケージインストールやアプリのデプロイができないのは片手落ち感がありました。
KickStart用のISOイメージを作成・マウントして...みたいな方法もできそうですが、
ここはスマートに(?)VMテンプレートの作成してクローンとしてGuestVMを作成しようと思います。

VMテンプレートとしてはお好きなものを作ってもらえればいいので詳細は省きますが、
私の例ではCentOS7を最小構成インストールしたものを使用しました。
また、その状態のテンプレートを使用した場合、VMNICが有効にならないなどの事象があったため、
追加でopen-vm-toolsパッケージをインストールする必要があるようなので、これとopen-vm-toolsを動かすperlだけははインストールしておきましょう。

$ sudo yum install -y open-vm-tools perl

※ Debian系の場合でも同名のパッケージがあるようなのでapt等でインストールしましょう。

今回はTemplate_CentOSという名前の仮想マシンを作成し、テンプレートに変換しました。
※ ここではテンプレートに変換していますが、起動中のVMを指定しても特に問題なくクローン作成されるようです。

folderの確認

またvmware_guestモジュールでGuestVMの作成をする場合にはfolderというパラメータを入れる必要があるので、このfolderの値を確認します。
Vmware側のドキュメントやvSphereWebClient上から確認する方法が分かりませんでしたが(ご指摘いただけると幸いです)、
vmware_folder_infoモジュールで取得するのが手っ取り早かったです。

get_folders.yml
- hosts: local
  gather_facts: false
  vars_files:
  - vars_vmware.yml
  tasks:
  - name: Provide information about vCenter folders
    vmware_folder_info:
      hostname: "{{ vcenter_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      datacenter: "{{ vcenter_datacenter }}"
      validate_certs: false
    delegate_to: localhost
    register: folder_info
  - debug:
      var: folder_info
$ ansible-playbook -i local.ini get_folders.yml 

PLAY [local] ***********************************************************************************************************************************************************************************************

TASK [Provide information about vCenter folders] ***********************************************************************************************************************************************************
ok: [localhost -> localhost]

TASK [debug] ***********************************************************************************************************************************************************************************************
ok: [localhost] => {
    "folder_info": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": false, 
        "failed": false, 
        "folder_info": {
            "datastoreFolders": {
                "path": "/Datacenter/datastore", 
                "subfolders": {}
            }, 
            "hostFolders": {
                "path": "/Datacenter/host", 
                "subfolders": {}
            }, 
            "networkFolders": {
                "path": "/Datacenter/network", 
                "subfolders": {}
            }, 
            "vmFolders": {
                "path": "/Datacenter/vm", 
                "subfolders": {}
            }
        }
    }
}

PLAY RECAP *************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

この中のvmFoldersに記載された/Datacenter/vmが仮想マシン用のfolderのようです。

やっとGuestVMの作成

これらのパラメータを使って、ようやくvmware_guestモジュールを使用できます。

仮想マシン名はtest1としています。
仮想マシン名は(厳密には一意ではないようですが)一意の名前を指定しましょう。
既存の仮想マシン名を指定した場合はGuestVMの作成は起こらず、既存の仮想マシンのstateで指定した電源状態に変化するだけのようです。(いわゆる冪等性ってやつだと思います)

なお今回はClusterという名前のvSphereクラスタを作成し、その配下にGuestVMを作成しましたが、
クラスタがない場合や作成するESXiホストを指定したい場合はclusterの代わりにesxi_hostnameを指定してください。

その他パラメータはドキュメントを確認してください。

create_guestvm.yml
- hosts: local
  gather_facts: false
  vars_files:
  - vars_vmware.yml
  tasks:
  - name: Create a virtual machine on given ESXi hostname
    vmware_guest:
      name: test1                  # VM名
      hostname: "{{ vcenter_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      datacenter: "{{ vcenter_datacenter }}"
      folder: /Datacenter/vm    # vmware_folder_infoで取得したfolder名
      validate_certs: false
      template: Template_CentOS   # 準備で作成したテンプレート名
      state: poweredon             # 起動状態にする
      # guest_id: centos7_64Guest  # 仮想マシンの作成時には必須であり、テンプレートからの作成時には不要
      cluster: Cluster
      # esxi_hostname: 192.168.*.* # clusterないしesxi_hostnameのいずれかを指定する
      disk:
      - size_gb: 16
        type: thin
        datastore: datastore
      hardware:
        memory_mb: 1024
        num_cpus: 1
        scsi: paravirtual
      networks:
      - name: VM Network
        start_connected: true
      wait_for_ip_address: yes
      customization:
        hostname: test1
    delegate_to: localhost
    register: vm_info

  - debug:
      var: vm_info
$ ansible-playbook -i local.ini create_guestvm.yml 

PLAY [local] ***********************************************************************************************************************************************************************************************

TASK [Create a virtual machine on given ESXi hostname] *****************************************************************************************************************************************************
changed: [localhost -> localhost]

TASK [debug] ***********************************************************************************************************************************************************************************************
ok: [localhost] => {
    "vm_info": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": true, 
        "failed": false, 
        "instance": {
            "annotation": "", 
            "current_snapshot": null, 
            "customvalues": {}, 
            "guest_consolidation_needed": false, 
            "guest_question": null, 
            "guest_tools_status": "guestToolsRunning", 
            "guest_tools_version": "10336", 
            "hw_cluster": "Cluster", 
            "hw_cores_per_socket": 1, 
            "hw_datastores": [
                "datastore"
            ], 
            "hw_esxi_host": "192.168.*.*", 
            "hw_eth0": {
                "addresstype": "assigned", 
                "ipaddresses": [
                    "192.168.*.*", 
~~~~ 中略 ~~~~
            "instance_uuid": "****^****", 
            "ipv4": "192.168.*.*", 
            "ipv6": null, 
            "module_hw": true, 
            "moid": "vm-***", 
            "snapshots": [], 
            "vimref": "vim.VirtualMachine:vm-***", 
            "vnc": {}
        }
    }
}

PLAY RECAP *************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

スペックによってはそれなりの時間がかかると思いますが、これでGuestVMが作成されましたね!
.instance.ipv4にIPアドレスの情報もあるので、add_hostモジュールで追加してその後のタスクを実行!なんてことも可能です。

オマケ:VmwareのDynamic Inventoryを使ってみる

AnsibleはVmwareについてDynamic Inventoryを使用することができます。
Dynamic Inventory自体については以下を参考してもらえるのがよいですが、簡単にいうと
タスクを実行したい対象が数台ぐらいであればVMのホスト名(IP)をインベントリに書けばいいのですが、対象が3桁・4桁と増えていくとそれも大変になります。
そこでホスト情報を直接記載するのではなく、API等からホスト情報を取得することで動的にインベントリに必要な情報を取ってこよう、というものです。
https://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html

こちらのページを参考に、ついでにDynamic Inventoryを使ってみました。
https://docs.ansible.com/ansible/latest/scenario_guides/vmware_scenarios/vmware_inventory.html

準備として、先にインストールしたpyvmomiモジュールに加えて、vSphere Automation SDKが必要なようです。
こちらの手順にしたがってインストールします。
なお、動作検証環境で記載したようにsetuptoolsパッケージがpython3.5未満ではインストールできなかったため、python3系で実行しています。
(setuptoolsはバージョン指定をすればインストールできたのですが、その後のsdkのインストールには失敗したのでそれ以降は追いかけてません。回避方法等があればご指摘ください)

$ pip install --upgrade pip setuptools
$ pip install --upgrade git+https://github.com/vmware/vsphere-automation-sdk-python.git

まずansible.cfgでVmwareのDynamic Inventoryに必要なプラグインを有効化します。

ansible.cfg
[inventory]
enable_plugins = vmware_vm_inventory

続いて、インベントリですが、vCenterの情報を記載します。またファイル名の末尾が.vmware.yml or .vmware.yamlである必要があります。

inventory.vmware.yml
plugin: vmware_vm_inventory
strict: False
hostname: 192.168.0.1
username: administrator@vsphere.local
password: password
validate_certs: False
with_tags: True

ここで確認でansible-inventoryコマンドを実行するとJSON形式のインベントリ情報が出力されます。

$ ansible-inventory -i inventory.vmware.yml --list
{
    "_meta": {
        "hostvars": {
            "test1_****-****": {
                "ansible_host": "192.168.*.*",
                "config.cpuHotAddEnabled": false,
                "config.cpuHotRemoveEnabled": false,
                "config.hardware.numCPU": 1,
                "config.instanceUuid": "****-****",
                "config.name": "test1",
                "config.template": false,
                "guest.guestId": "centos7_64Guest",
                "guest.guestState": "running",
                "guest.hostName": "localhost.localdomain",
                "guest.ipAddress": "192.168.*.*",
                "name": "test1",
                "runtime.maxMemoryUsage": 1024
            },
~~~ 中略 ~~~
        }
    },
    "all": {
        "children": [
            "centos7_64Guest",
            "other3xLinux64Guest",
            "poweredOff",
            "poweredOn",
            "ungrouped"
        ]
    },
    "centos7_64Guest": {
        "hosts": [
            "test1_****-****",
            "",
~~~ 中略 ~~~
        ]
    },

~~~ 中略 ~~~
}

allグループのchildrenとしてguest_idや電源状態のグループがあり、hostsの中に配列でホスト名が記載されており、ホスト毎の詳細な情報はhost_varsとして記載されているようです。
なお、ホスト名はVM名にhw_product_uuidというUUIDをつけた形式のようです。

最後に例としてvmware_guest_tools_upgradeモジュールを使ってVmwareToolのアップグレードをやってみたいと思います。
今回は他のVMに影響を与えたくなかったのでtest1のみに対してアップグレードを実行しますが、
hostsをallやグループ名にすれば複数台に対して実行されるはずです。

vmtool_upgrade.yml
- hosts: test1_***-****
  gather_facts: false
  vars_files:
  - vars_vmware.yml
  tasks:
  - name: Upgrade VMware Tools using VM name
    vmware_guest_tools_upgrade:
      hostname: "{{ vcenter_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      datacenter: "{{ vcenter_datacenter }}"
      name: "{{ name }}"
      validate_certs: false
    delegate_to: localhost

実行した結果、作成したばかりのVMだったためVmwareToolも最新版だったようで変化はありませんでしたが、
ある程度の期間と台数を運用している環境で実行すれば中々強力な作業自動化に繋がると思います。

$ ansible-playbook -i inventory.vmware.yml play.yml -v
Using /work/ansible.cfg as config file

PLAY [test1_***-***] **********************************************************************************************************************************************************

TASK [Upgrade VMware Tools using VM name] ******************************************************************************************************************************************************************
ok: [test1_***-*** -> localhost] => {"changed": false, "msg": "VMware tools is already up to date"}

PLAY RECAP *************************************************************************************************************************************************************************************************
test1_***-*** : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
24
32
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?