本記事は「エーピーコミュニケーションズ Advent Calendar 2020」の4日目のエントリとなります。
今年入社しまして自動化とコンテナをいろいろ頑張りたいです。よろしくお願いします。
2020.12.16追記: コレクション作成と公開の記事へのリンク追加 (こちら)
概要
ESXiのSSH機能を使ってVM作成などの操作を行うAnsibleコレクションを作ってみました。
無償ライセンスのESXiでも使えます。
Ansible Galaxy / esxissh - VM operation on ESXi with enabled SSH
Python3で動作し、Ansible 2.9以上、ESXiは6.5と6.7で動作確認しています。
また、SSH接続用にParmikoを使用するのでAnsible実行ノードにpip
で別途インストールしてください。
※ まだ「とりあえず最低限VMができる」くらいなので、利用の際ははあくまで検証用でお願いします。
ソースはGitHubにあります。
Ansible Collection - zaki_lknr.esxissh
モジュール作成の練習をしてたらいい感じになってきたのでコレクションとして公開してみました。
本記事ではこのコレクションの使い方と仕組みについて記載します。
作った自作モジュールをコレクション構成にしてGalaxyに公開する内容については、以下にまとめました。
[Ansible] 自作のコレクションを作ってGalaxyで公開するまで - Qiita
使い方
(準備)ESXi設定
ESXiのSSHを有効にします。
このコレクションで使うモジュールは、ESXiにSSH接続してから処理を行います。
(準備)Paramikoインストール
pip install paramiko
コレクションインストール
ansible-galaxy collection install zaki_lknr.esxissh
デフォルトで$HOME/.ansible
以下にインストールされるので、venv環境の場合は、他の環境と混ざらないようにcollections_path
を使ってコレクションパスをvenv環境内に設定しておくと良いです。
playbook例
以下のようなplaybookでVM作ったり出来ます。
(基本的にvmware_guestで使うplaybookベースに、ESXiだと不要なdatacenter
やfolder
などを省略しています)
esxiaddr
やesxiuser
などは、環境に合わせてinventory変数などを参照するようにしてください。
VMの削除はstate: absent
で可能です。
- hosts: localhost
gather_facts: no
tasks:
- name: create vm
zaki_lknr.esxissh.esxissh_guest:
esxiaddress: '{{ esxiaddr }}'
esxiusername: '{{ esxiuser }}'
esxipassword: '{{ esxipass }}'
name: example
guest_id: centos7_64Guest
datastore: datastore1
hardware:
memory_mb: 4096
num_cpus: 2
networks:
- name: VM Network
device_type: vmxnet3
- name: private-network-1
device_type: vmxnet3
disk:
- size_gb: 40
type: thin
- size_gb: 20
type: eagerzeroedthick
cdrom:
- type: iso
iso_path: cheddar-share/disk2/archive/iso/CentOS-7-x86_64-Minimal-1908.iso
- type: iso
iso_path: cheddar-share/disk2/archive/iso/CentOS-8.2.2004-x86_64-minimal.iso
state: present
現時点で、電源on/off・VM作成/削除に対応しています。サンプルのplaybookを参考にしてください。
実行するとこんな感じになります。
(eagerzeroedthick
で20GBプロビジョニングすると時間がかかるので↑からは除きました)
(2.10) [zaki@cloud-dev sample-playbook (main)]$ ansible-playbook -i inventory.ini create_vm.yml -v
Using /home/zaki/src/esxi-ansible/sample-playbook/ansible.cfg as config file
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'
PLAY [localhost] ***************************************************************
TASK [create vm] ***************************************************************
changed: [localhost] => changed=true
cdrom:
- iso_path: cheddar-share/disk2/archive/iso/CentOS-7-x86_64-Minimal-1908.iso
type: iso
- iso_path: cheddar-share/disk2/archive/iso/CentOS-8.2.2004-x86_64-minimal.iso
type: iso
datastore: WDS100T2B0A
disk:
- size_gb: 10
type: thin
guest_id: centos7_64Guest
hardware:
memory_mb: 4096
num_cpus: 2
name: vm-example
networks:
- device_type: vmxnet3
name: VM Network
- device_type: vmxnet3
name: private-network-1
PLAY RECAP *********************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
(2.10) [zaki@cloud-dev sample-playbook (main)]$
作成されたVM
基本的に以上なのですが、簡単に趣旨と仕組みを解説します。
ESXiの無償ライセンス
無償でも利用できるESXi、個人の検証環境用などに使用されている方は多いのではないでしょうか。
ただし無償ライセンスの制限として、write系のAPIが使用できないという縛りがあります。
これはつまり、govc
やvmware_guest
などのツールを使って「VMを作ったり」「VMの設定を変更したり」「VMの電源on/offを制御したり」することができません。(VMの情報を参照するくらいはできます。スクリーンショット取得も実は可能)
ちなみに無償ライセンスを適用する前であれば、期間限定の評価ライセンス状態となり、60日間はwrite系のAPIも使用できます。
以前はvsphere_guestというAnsibleモジュールを使えば無償ライセンスでもゲストOS操作が出来ましたが、現在はメンテナンスされておらず、deprecatedのためAnsible 2.9で削除され、Python3でも動作しません。
ESXiのCLIツール
普段ESXi使ってる方は、webの画面からぽちぽちと操作してVM管理をするか、無償ライセンスでなければpyVmomiやPowerCLIなどを使った自動化ツールを使用しているかと思いますが、実はESXiの内蔵SSHを有効にしてログインすると、vim-cmd
というCLIツールを使って__ある程度の__VM操作が可能です。
引数無しで実行すると、サブコマンド(末尾に/
が付いていてディレクトリ名に見えるけどサブコマンド)一覧が出力されます。
[root@localhost:~] vim-cmd
Commands available under /:
hbrsvc/ internalsvc/ solo/ vmsvc/
hostsvc/ proxysvc/ vimsvc/ help
作成済みVMの定義ファイル関連は/vmfs/volumes/<datastore>
以下にあります。
このディレクトリ配下に「VM名のサブディレクトリ」があり、そのサブディレクトリ内にVMの定義ファイル類があります。
VM定義ファイル: <vmname>.vmx
ディスクイメージ: <任意のファイル名>.vmdk
今回作成したAnsibleコレクションは、このvim-cmd
コマンドを使ってVM操作を行っています。
vim-cmd
コマンドは情報が少ないので、使っているコマンドを一通り説明します。
なお、文中のWDS100T2B0A
は私の手元の環境のデータストア名です。
VM作成
VM作成というより、名前の通りダミーのVMを作成します。
[root@localhost:~] vim-cmd vmsvc/createdummyvm
Insufficient arguments.
Usage: createdummyvm vm_name datastore_path [hw_version]
Create a pre-configured dummy vm.
このコマンドでvmxファイルが生成されESXi上にもVMが登録されます。
が、ほぼほぼ設定無しの以下のスペックのskelton状態なので、いろいろと定義追加してあげる必要があります。
- 1 vCPU
- RAM 32 MB
- HDD 1 MB
- OS種別はother
ダミーVMの作成に成功すると、VMIDという一意の番号が出力されます。
[root@localhost:~] vim-cmd vmsvc/createdummyvm example /vmfs/volumes/WDS100T2B0A/
253
VMに対する操作をコマンドで実行する際は、このVMIDが必要になります。
1点注意点があり、webの画面だと出来ない「同じ名前のVMの作成ができてしまう」点があります。
同じ名前のVMを作成すると<vmname>_1/<vmname>_1.vmx
というファイル構成になり、webの画面だと見分けがつきづらいので、使わない方が良いでしょう。
VMIDの一覧取得
ESXi上の全VMのID・ファイルパス、ゲストOS種別などの一覧を取得するコマンドです。
[root@localhost:~] vim-cmd vmsvc/getallvms
Vmid Name File Guest OS Version Annotation
:
:
250 vm-example [WDS100T2B0A] vm-example/vm-example.vmx centos7_64Guest vmx-14
253 example [WDS100T2B0A] example/example.vmx otherGuest vmx-14
254 example [WDS100T2B0A] example_1/example_1.vmx otherGuest vmx-14
:
:
単純にスペースで区切って取り出そうとすると、VM名にスペースが入っていると分断されてしまうので注意。
vmxファイル状態のリロード
vim-cmd
を使ってVM定義を更新した場合は即時ESXi上に反映されますが、VMの定義ファイルであるvmxファイルを直接編集した場合は、手動で変更内容を反映させる必要があります。
[root@localhost:~] vim-cmd vmsvc/reload 253
実行すると、対象VMのvmxファイルの内容がESXiに反映され、webの画面でも変更内容を確認できるようになります。
CPU/メモリ設定
あいにく設定用のコマンドを見つけられませんでした。
よって、vmxファイルを直接編集して設定します。
といっても、既存の作成済みvmxファイルを参考に、CPUとメモリの設定行を真似すれば問題ないです。
numvcpus = "2"
memSize = "4096"
ただし、vmxファイルを手動編集しただけだとESXiが変更内容を認識しないため「リロード」してESXiに認識させる必要があります。
また、vmxファイルを手動編集したあとにリロードをせずに、後述の「NIC追加のコマンド」などを実行すると、ESXiが認識している状態の編集前の内容で上書きされます。
ゲストOS設定
OS種別の設定もコマンドが見つかりませんでした。
ので、これもvmxファイルを直接編集します。
例えば「CentOS 7 (64 ビット)」を指定した場合のvmxファイルは以下の通り。
guestOS = "centos7-64"
ただし、ゲストOSを表す文字列はちょっと注意が必要で、APIを使う場合のゲストOSのID文字列と、実際にvmxファイルに出力される文字列が異なります。
例えば、前述同様にCentOS 7 (x64)であれば、centos7_64Guest
になります。
VirtualMachineGuestOsIden.. - vSphere Web Services API - VMware {code}
例えばこんな感じです。
guestOS | API | description |
---|---|---|
centos | centosGuest | CentOS 4/5 x32 |
centos-64 | centos64Guest | CentOS 4/5 x64 |
centos7-64 | centos7_64Guest | CentOS 7 x64 |
coreos-64 | coreos64Guest | CoreOS Linux |
other-64 | otherGuest64 | Other x64 |
other | otherGuest | Other x32 |
rhel2 | rhel2Guest | RHEL 2.1 |
rhel3 | rhel3Guest | RHEL 3 |
rhel3-64 | rhel3_64Guest | RHEL 3 x64 |
rhel7-64 | rhel7_64Guest | RHEL 7 x64 |
ubuntu | ubuntuGuest | Ubuntu x32 |
ubuntu-64 | ubuntu64Guest | Ubuntu x64 |
windows9-64 | windows9_64Guest | Windows 10 x64 |
windows8-64 | windows8_64Guest | Windows 8 x64 |
windows7srv-64 | windows7Server64Guest | Microsoft Windows Server 2008 R2 (64 ビット) |
windows8srv-64 | windows8Server64Guest | Microsoft Windows Server 2012 (64 ビット) |
windows9srv-64 | windows9Server64Guest | Microsoft Windows Server 2016 以降 (64 ビット) |
vmkernel65 | vmkernel65Guest | VMware ESX 6.5 |
guest_idに指定するGuestOSのidが内部ファイルで使用するものになっている · Issue #3 · zaki-lknr/esxissh-ansible
NIC追加
NICの追加はvmsvc/devices.createnic
で出来ます。
[root@localhost:~] vim-cmd vmsvc/devices.createnic
Insufficient arguments.
Usage: devices.createnic vmid adapter-type network-id [network-type]
Add a NIC to this virtual machine.
ESXiをインストールしたときにデフォルトで作成されるVM Network
をVMに追加するには以下の通り。
[root@localhost:~] vim-cmd vmsvc/devices.createnic 253 "vmxnet3" "VM Network"
これでvmxファイルに以下の定義が追加されます。
ethernet0.virtualDev = "vmxnet3"
ethernet0.networkName = "VM Network"
ethernet0.uptCompatibility = "TRUE"
ethernet0.present = "TRUE"
別のNICを追加する場合は続けて実行すればよく、アダプタ番号は追加順に自動で割り当てられます。
[root@localhost:~] vim-cmd vmsvc/devices.createnic 253 "vmxnet3" "restricted-network-1"
ethernet1.virtualDev = "vmxnet3"
ethernet1.networkName = "restricted-network-1"
ethernet1.uptCompatibility = "TRUE"
ethernet1.present = "TRUE"
ポートグループ自体の作成までは調べてないので機会があれば…(あるのかな?)
ディスク管理
ディスク自体(vmdkファイル)の操作と、VMの定義のvmxファイル内におけるディスク定義の操作の2種類があります。
vmdkファイル
vmdkファイルを作ったり削除するにはvmkfstools
コマンドを使います。
VM用のファイル操作は主に「OPTIONS FOR VIRTUAL DISKS」の部分です。
[root@localhost:~] vmkfstools
No valid command specified
:
:
OPTIONS FOR VIRTUAL DISKS:
vmkfstools -c --createvirtualdisk #[bBsSkKmMgGtT]
-d --diskformat [zeroedthick
|thin
|eagerzeroedthick
]
-a --adaptertype [deprecated]
-W --objecttype [file|vsan|vvol|pmem|upit]
--policyFile <fileName>
-w --writezeros
-j --inflatedisk
-k --eagerzero
-K --punchzero
-U --deletevirtualdisk
-E --renamevirtualdisk srcDisk
-i --clonevirtualdisk srcDisk
-d --diskformat [zeroedthick
|thin
|eagerzeroedthick
|rdm:<device>|rdmp:<device>
|2gbsparse]
-W --object [file|vsan|vvol]:
:
vmdkファイル削除
vim-cmd vmsvc/createdummyvm
でVMと一緒に作成された(平たく言うと使い道のない)32MBのvmdkファイルを削除するには、フルパスでvmdkファイル(-flat
ではない方)を指定します。
[root@localhost:~] ls -l /vmfs/volumes/WDS100T2B0A/example/*vmdk
-rw------- 1 root root 1048576 Dec 1 00:00 /vmfs/volumes/WDS100T2B0A/example/example-flat.vmdk
-rw------- 1 root root 439 Dec 1 00:00 /vmfs/volumes/WDS100T2B0A/example/example.vmdk
[root@localhost:~] ls -1 /vmfs/volumes/WDS100T2B0A/example/
example-flat.vmdk
example.vmdk
example.vmsd
example.vmx
[root@localhost:~] vmkfstools --deletevirtualdisk /vmfs/volumes/WDS100T2B0A/example/example.vmdk
[root@localhost:~] ls -1 /vmfs/volumes/WDS100T2B0A/example/
example.vmsd
example.vmx
vmdkファイル作成
新しくディスクを作成するにはvmkfstools --createvirtualdisk
を使用します。
5GBのthin
プロビジョニングであれば以下の通り。
作成先のフルパスも必要です。
[root@localhost:~] vmkfstools --createvirtualdisk 5GB --diskformat thin /vmfs/volumes/WDS100T2B0A/example/example_0.vmdk
Create: 100% done.
[root@localhost:~] ls -1l /vmfs/volumes/WDS100T2B0A/example/
total 0
-rw-r--r-- 1 root root 0 Dec 1 00:00 example.vmsd
-rwxr-xr-x 1 root root 1278 Dec 1 00:07 example.vmx
-rw------- 1 root root 5368709120 Dec 1 00:33 example_0-flat.vmdk
-rw------- 1 root root 474 Dec 1 00:33 example_0.vmdk
ちなみにディスク(vmdkファイル)の作成も削除も、ディスク自体のファイル操作になり、VMの設定(vmxファイル内定義)には影響しないので、別途更新する必要があります。
ディスク定義
vmxファイルの下記定義を操作します。
scsi0:0.deviceType = "scsi-hardDisk"
scsi0:0.fileName = "example.vmdk"
scsi0:0.present = "TRUE"
定義の削除
vim-cmd vmsvc/device.diskremove
を使用します。
[root@localhost:~] vim-cmd vmsvc/device.diskremove
Insufficient arguments.
Usage: device.diskremove vmid controller_number unit_number delete_file [controller_type]
Remove a disk from this virtual machine. If controller type is not set, the command will look for a SCSI disk.
実行にはコントローラ番号とユニット番号の指定に加えて、ファイル名も指定する必要があります。
scsiX:Y
の場合、コントローラ番号がX
でユニット番号はY
です。
[root@localhost:~] vim-cmd vmsvc/device.diskremove 253 0 0 example.vmdk
これでscsi0:0
の定義が削除されます。
定義の追加(既存ディスク設定)
作成済みvmdkをVMに追加するにはvim-cmd vmsvc/device.diskaddexisting
を使用します。
[root@localhost:~] vim-cmd vmsvc/device.diskaddexisting
Insufficient arguments.
Usage: device.diskaddexisting vmid disk_file controller_number unit_number [ctlr_type]
Add an existing disk to this virtual machine. If controller type is not set, the command will create a SCSI disk.
削除と同様、コントローラ番号とユニット番号を指定します。
NICのように「追加した順番に番号が自動で割り振られる」ことはないので、手動で採番が必要です。
[root@localhost:~] vim-cmd vmsvc/device.diskaddexisting 253 /vmfs/volumes/WDS100T2B0A/example/example_0.vmdk 0 0
[root@localhost:~]
scsi0:0.deviceType = "scsi-hardDisk"
scsi0:0.fileName = "example_0.vmdk"
scsi0:0.present = "TRUE"
2台目のディスクはunit_number
を増やしていけばOK
[root@localhost:~] vim-cmd vmsvc/device.diskaddexisting 253 /vmfs/volumes/WDS100T2B0A/example/example_1.vmdk 0 1
scsi0:1.deviceType = "scsi-hardDisk"
scsi0:1.fileName = "example_1.vmdk"
scsi0:1.present = "TRUE"
CD/DVD追加
たとえばデータストア上にあるisoファイルのマウント設定はvmxファイルでは、設定済みのVMの定義を見ると以下の通り。
ide1:0.deviceType = "cdrom-image"
ide1:0.fileName = "/vmfs/volumes/6d9f7290-6ab63077-0000-000000000000/disk2/archive/iso/CentOS-7-x86_64-Minimal-1908.iso"
ide1:0.present = "TRUE"
残念ながらdeviceType: cdrom-iamge
として設定を追加するコマンドは見つけられなかった。
(vim-cmd vmsvc/device.diskaddexisting
もオプションの引数にide
を指定すればide1:0
の部分は設定できるけど、deviceType
の設定がわからなかった)
よってここは手動で編集してリロード。
なお、設定済みVMを見るとデータストアのパスがUUIDのようになってますが、普通に/vmfs/volumes/<datastore>/path/to/foobar-image.iso
で認識します。
VM削除
VMの削除はvim-cmd vmsvc/destroy
で出来ます。
[root@localhost:~] vim-cmd vmsvc/destroy
Insufficient arguments.
Usage: destroy vmid
Deletes the vm.
VMIDを指定して実行すれば特に何も出力されず、シュッと消えます。
(echo $0
すれば0
を確認できます)
[root@localhost:~] vim-cmd vmsvc/destroy 254
電源操作
電源on
vim-cmd vmsvc/power.on
を使用します。
[root@localhost:~] vim-cmd vmsvc/power.on 253
Powering on VM:
電源off
vim-cmd vmsvc/power.off
を使用します。
ESXiのwebの画面での「パワーオフ」操作なので、いわゆる強制電源オフです。
[root@localhost:~] vim-cmd vmsvc/power.off 253
Powering off VM:
シャットダウン
vim-cmd vmsvc/power.shutdown
を使用します。
OSのシャットダウンを行うので、VM上にVMware Toolsが必要です。
無い場合はエラーになります。
[root@localhost:~] vim-cmd vmsvc/power.shutdown 253
(vim.fault.ToolsUnavailable) {
faultCause = (vmodl.MethodFault) null,
faultMessage = <unset>
msg = "Received SOAP response fault from [<cs p:0000002122005370, TCP:localhost:8307>]: shutdownGuest
Cannot complete operation because VMware Tools is not running in this virtual machine."
}
電源状態の取得
vim-cmd vmsvc/power.getstate
を使用します。
[root@localhost:~] vim-cmd vmsvc/power.getstate 253
Retrieved runtime info
Powered off
[root@localhost:~] vim-cmd vmsvc/power.getstate 106
Retrieved runtime info
Powered on
コレクション化について
以下の記事にまとめました。
[Ansible] 自作のコレクションを作ってGalaxyで公開するまで - Qiita
まとめ
ESXiのSSHを有効にするという「穴あけ」は必要ですが、SSH接続して直接ファイルを操作することで大抵のことは操作可能なので、良い感じにパッケージングできるという例でした。
今回はCLIツールを内部で操作するAnsibleコレクションを使うことで、無償ライセンスでは難しくなってしまったVM作成や操作の自動化ができるようになりました。
作成したVMはOSは入っていませんが、そちらはkickstartインストールなどで自動化しましょう。
参考情報
- community.vmware.vmware_guest – Manages virtual machines in vCenter — Ansible Documentation
- VMware ESXiをSSHでがんばるぞい(コマンドライン操作色々) - Qiita
- [ESXi / Ansible] ssh接続してvmi-cmdを使ったVM操作が可能かお試し - zaki work log
- [VMware / Ansible] 評価版ライセンスのESXiにvmware_guestモジュールを使ってVMを作成する - zaki work log
- [Ansible] deprecatedになってるvsphere_guestを使ってESXi上でVMを自動生成する - zaki work log
- vsphere_guest – Create/delete/manage a guest VM through VMware vSphere — Ansible Documentation