LoginSignup
33
23

More than 3 years have passed since last update.

ESXi上でvim-cmdを使ってVM操作するAnsibleコレクション (無償ライセンス利用可)

Last updated at Posted at 2020-12-03

本記事は「エーピーコミュニケーションズ 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接続してから処理を行います。

20200910214002.png

(準備)Paramikoインストール

pip install paramiko

コレクションインストール

ansible-galaxy collection install zaki_lknr.esxissh

デフォルトで$HOME/.ansible以下にインストールされるので、venv環境の場合は、他の環境と混ざらないようにcollections_pathを使ってコレクションパスをvenv環境内に設定しておくと良いです。

playbook例

以下のようなplaybookでVM作ったり出来ます。
(基本的にvmware_guestで使うplaybookベースに、ESXiだと不要なdatacenterfolderなどを省略しています)

esxiaddresxiuserなどは、環境に合わせてinventory変数などを参照するようにしてください。
VMの削除はstate: absentで可能です。

playbook.yml
- 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

image.png

基本的に以上なのですが、簡単に趣旨と仕組みを解説します。

ESXiの無償ライセンス

無償でも利用できるESXi、個人の検証環境用などに使用されている方は多いのではないでしょうか。
ただし無償ライセンスの制限として、write系のAPIが使用できないという縛りがあります。
これはつまり、govcvmware_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の画面だと見分けがつきづらいので、使わない方が良いでしょう。

2020-12-01_09h04_12.png

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とメモリの設定行を真似すれば問題ないです。

vmxファイル設定例
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ファイルに以下の定義が追加されます。

vmxファイル内NIC設定
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"
vmxファイル内NIC設定
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ファイルの下記定義を操作します。

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:~]
vmxファイル内ディスク設定
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
vmxファイル内ディスク設定
scsi0:1.deviceType = "scsi-hardDisk"
scsi0:1.fileName = "example_1.vmdk"
scsi0:1.present = "TRUE"

CD/DVD追加

たとえばデータストア上にあるisoファイルのマウント設定はvmxファイルでは、設定済みのVMの定義を見ると以下の通り。

vmxファイル内CD/DVD設定
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インストールなどで自動化しましょう。

参考情報

33
23
0

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
33
23