はじめに
タイトルのように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
- OS: CentOS 7
使用したモジュール
Vmware系のモジュールは歴史的には大きく分けて2種類あったようで、例えばGuestVMの作成・削除をするモジュールとしては
-
vmware_guestモジュール
- pythonのPyVmomiパッケージを利用
- 推奨
-
vsphere_guestモジュール
- pythonのPysphereパッケージを利用
- 長らく
DEPRECATED
だったが、ansible 2.9でついに削除された
の二通りの書き方があったようですが、上記のように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の情報をあらかじめ変数としてファイルに書いておきましょう。
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実行ホストで実行します。
- 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]
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モジュールで取得するのが手っ取り早かったです。
- 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
を指定してください。
その他パラメータはドキュメントを確認してください。
- 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に必要なプラグインを有効化します。
[inventory]
enable_plugins = vmware_vm_inventory
続いて、インベントリですが、vCenterの情報を記載します。またファイル名の末尾が.vmware.yml
or .vmware.yaml
である必要があります。
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
やグループ名にすれば複数台に対して実行されるはずです。
- 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