ラベル VMware の投稿を表示しています。 すべての投稿を表示
ラベル VMware の投稿を表示しています。 すべての投稿を表示

2024年12月31日火曜日

vmtoolsd がちゃんと起動しているか確認する方法

vmtoolsd がちゃんと起動しているか確認する方法

概要

Ubuntu で稼働している vmtoolsd が systemctl で見ると active なのにうまく動作していないことがあります
そのときに起動しているか確認する方法を紹介します

環境

  • Ubuntu 24.04
  • vmtoolsd 12.4.5

コマンド

おそらく以下が一番カンタンです

vmtoolsd --cmd "info-get guestinfo.ip"

もしくは

vmware-rpctool "info-get guestinfo.ip"

vmtoolsd が正常に起動している場合は IP アドレスが返りますが動作していない場合は unknown が返ってきます

2020年2月12日水曜日

VMware PowerCLI で nfs のマウント操作をしてみた

概要

VMware.PowerCLI で nfs のデータストアをマウントする操作をしてみました
サンプルのコマンドレットを紹介します

環境

  • CentOS 7.7.1908
  • .NET SDK 3.1
  • PowerShell 6.2.3
  • VMware.PowerCLI 11.5.0.14912921

データストアを追加する (マウント)

  • Connect-VIServer -Server 192.168.100.10 -User administrator@vsphere.local -Password xxxxxxxx
  • $host1 = Get-VMhost -Name 192.168.100.11
  • New-Datastore -Name nfs_test -Nfs -NfsHost 192.168.100.20 -Path /opt/nfs -VMHost $host1

データストアを削除する (アンマウント)

  • Remove-Datastore -Datastore nfs_test -VMHost $host1 -Confirm:$false

データストアの一覧を表示する

  • Get-Datastore

参考サイト

2020年2月11日火曜日

CentOS7 に VMware vCLI をインストールする方法

環境

  • CentOS 7.7.1908
  • VMware vSphere Command Line Interface 6.7

ダウンロード

VMware の公式から gz 形式のファイルをダウンロードしましょう

インストール

  • tar zvxf VMware-vSphere-CLI-6.7.0-8156551.x86_64.tar.gz
  • cd vmware-vsphere-cli-distrib/
  • ./vmware-install.pl

cpan から必要なモジュールのダウンロードとインストールが開始されます
必要なモジュールが揃えば vCLI をインストールするパスを聞いてくるのでパスを指定して完了です

cpan から特定のモジュールがインストールできなかった場合

自分は UUID がインストールできませんでした
以下のようなメッセージが表示されます

CPAN not able to install following Perl modules on the system. These must be
installed manually for use by vSphere CLI:

UUID 0.27 or newer

cpan コマンドで直接インストールしてみると状況がわかると思います

  • cpan install UUID

これで出てきたエラーに対して対処すれば OK です
自分の場合は libuuid-devel がなかったのでインストールしました

  • yum -y install libuuid-devel
  • cpan install UUID

このあとで再度 ./vmware-install.pl を実行すれば OK です

動作確認

  • esxcfg-vswitch --server 192.168.100.10 --list
  • esxcli --version
  • esxcli --thumbprint 45:D3:5E:D1:1A:E7:CB:2C:E5:A5:79:4B:F3:C1:29:DD:C4:39:9C:9E --server
    192.168i.100.10 network vswitch standard list

esxcfg-hoge コマンドは非推奨なので esxcli コマンドを使いましょう
実際に実行すると警告が表示されるのが確認できると思います

2020年2月10日月曜日

VMware PowerCLI でポートグループを操作するサンプル

概要

VMware.PowerCLI でポートグループを操作してみました
サンプルのコマンドレットを紹介します

環境

  • CentOS 7.7.1908
  • .NET SDK 3.1
  • PowerShell 6.2.3
  • VMware.PowerCLI 11.5.0.14912921

指定の vDS 配下にポートグループを作成する

  • New-VDPortgroup -VDSwitch vds -name pg -NumPorts 123 -VlanId 456

ポートグループを削除する

  • Get-VDPortGroup -Name pg | Remove-VDPortGroup

ポートグループのセキュリティポリシーを変更する

  • $pg = New-VDPortgroup -VDSwitch vds -name pg -NumPorts 123 -VlanId 456
  • $pg | Get-VDSecurityPolicy | Set-VDSecurityPolicy -AllowPromiscuous $true -MacChanges $true -ForgedTransmits $true

その他関連操作

  • Set-VDPortgroup
  • Export-VDPortgroup
  • Set-VDSecurityPolicy

参考サイト

2020年2月4日火曜日

VMware.PowerCLI でロールや権限周りの操作をしてみる

環境

  • CentOS 7.7.1908
  • .NET SDK 3.1
  • PowerShell 6.2.3
  • VMware.PowerCLI 11.5.0.14912921

Powershell の起動

以下は Powershell を起動したプロンプト内で実行します

証明書のエラーを抑制する

  • Set-PowerCLIConfiguration -InvalidCertificateAction:Ignore

一度のみ実行すれば OK です

vCenter or ESXi への接続 (basic 認証)

  • Connect-VIServer -Server 192.168.100.10 -User administrator@vsphere.local -Password xxxxxxxxxxx

vCenter or ESXi への接続解除

  • Disconnect-VIServer

ユーザの取得

  • Get-VMHostAccount
  • Get-VMHostAccount -Name hoge

ユーザの追加

  • New-VMHostAccount -Id hoge -Password "fuga12345!" -Description "for test"

ユーザの削除

  • Get-VMHostAccount -Id hoge | Remove-VMHostAccount

ロールの取得

  • Get-VIRole
  • Get-VIRole -Name NewRole_20200204

ロールの追加

  • New-VIRole -Name NewRole_20200204 -Privilege (Get-VIPrivilege -PrivilegeGroup)

ロールの削除

  • Get-VIRole -Name NewRole_20200204 | Remove-VIRole

権限の取得

  • Get-VIPermission
  • Get-VIPermission -Entity (Get-Datacenter) -Principal VSPHERE.LOCAL\vsphere-webclient-0c0e11a5-d914-4030-976c-04e51aa67b00

権限の追加 (ロール or ユーザへの権限割り当て)

  • New-VIPermission -Role NewRole_20200204 -Entity (Get-Datacenter) -Principal VSPHERE.LOCAL\vsphere-webclient-0c0e11a5-d914-4030-976c-04e51aa67
  • New-VIPermission -Entity (Get-VMHost) -Principal hoge -Role Admin -Propagate:$true

権限の削除

  • $permission = Get-VIPermission -Entity (Get-VMHost) -Principal hoge
  • Remove-VIPermission -Permission $permission

Tips

Get-View の使い方

  • $dc = Get-Datacenter | Get-View
  • Write-Host $dc.Name

Get-Datacenter で取得した結果から Datacenter オブジェクトを取得して編集に格納します
オブジェクトにすることでドットつなぎでフィールドなどを参照することができます

Select-Object -ExpandProperty

  • Get-VIPrivilege -Name System | Select-Object -ExpandProperty Id

デフォルトで表示されない Id フィールドを表示することができます
フィールドの一覧は Get-Member あたりで確認できます

  • Get-VIPrivilege | Get-Member

WhatIf (ドライラン)

  • Get-VIRole -Name NewRole_20200204 -WhatIf

どういう挙動になるのか確認することができます

Format-List で短縮形を表示する

  • Get-VIPermission | Format-List

長くて表示されない項目がある場合はフォーマットを指定することで表示できます

各コマンドのヘルプの表示

  • Get-Help Get-VIPermission
  • Get-Help Get-VIPermission -examples
  • Get-Help Get-VIPermission -full

最後に

VMware.PowerCLI でユーザ/ロール/権限周り操作をしてみました
Powershell に用意されているコマンドレットと組み合わせることで更に便利に扱うことができるようになります

2019年9月27日金曜日

vSphere REST API を curl でサクっと実行する方法

概要

タイトルの通りです
SOAP ではなく JSON ベースの REST API になります

環境

  • CentOS 7.7.1908
  • vSpehre vCenter 6.7.0.30000

認証

まずは SessionID を取得します
vSphere Client でログインしているユーザとパスワードが必要になります
以下は user001/pass001 として SessionID を取得する例です

  • curl -k -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'vmware-use-header-authn: test' --header 'vmware-api-session-id: null' -u 'user001' 'https://192.168.100.10/rest/com/vmware/cis/session'

実行するとパスワードの入力が求められるので user001 のパスワードを入力します
vmware-use-header-authn は「test」のままで OK です

成功すると {"value":"1aa17f25fbe29ca15de233dd82d1fda8"} のような SessionID が返ってきます

API をコールする

例えばタグの一覧を取得する場合は以下のようにコールします

  • curl -k -X GET --header 'Accept: application/json' --header 'vmware-api-session-id: 1aa17f25fbe29ca15de233dd82d1fda8' 'https://192.168.100.10/rest/com/vmware/cis/tagging/tag'

これで JSON 情報が返ってきます
取得した SessionID は vmware-api-session-id に設定しましょう

最後に

コール可能な API の一覧は https://192.168.100.10/apiexplorer/ にアクセスすると確認できます

2019年5月23日木曜日

vcsim を使ってみた

概要

環境

  • macOS 10.14.4
  • golang 1.11.5
  • Ruby 2.6.2p47

vcsim インストール

  • go get -u github.com/vmware/govmomi/vcsim

govc がない場合は動作確認で使うのでインストールしておきましょう

  • go get -u github.com/vmware/govmomi/govc

vcsim 起動

$GOPATH/bin には PATH を通しているものとします

  • vcsim

これで localhost:8989 で起動します

環境変数

govc を使って動作確認してみます
vcsim を起動すると環境変数を設定するように言われるので素直に設定します

  • export GOVC_URL=https://user:pass@127.0.0.1:8989/sdk GOVC_SIM_PID=62667 GOVC_INSECURE=1

GOVC_INSECURE=1 を忘れずに入れましょう

動作確認

まずは govc を使って確認してみます

リソースの一覧を表示

  • govc find

vCenter の情報を表示

  • govc about

VM の一覧を取得

  • govc find vm
  • govc find . -type m

VM の詳細を取得

  • govc vm.info DC0_H0_VM0

VM のシャットダウン

  • govc vm.power -off DC0_H0_VM0

ちなみに -on で VM を起動できます

VM の設定変更

  • govc vm.change -vm DC0_H0_VM0 -name=DC0_H0_VM2

ホストの一覧を取得

  • govc find . -type h

その他 govc の使い方はこちらを参照してください

rbvmomi で動作確認

せっかくなので Ruby からも動作確認してみました

  • bundle init
  • vim Gemfile
gem "rbvmomi"
  • bundle install --path vendor
  • vim app.rb
require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: 'localhost',
  port: '8989',
  user: 'user',
  password: 'pass',
  insecure: 'true'
)

# List vms
dc = vim.serviceInstance.find_datacenter('DC0') || fail('datacenter not found')
dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine).find do |x| 
  puts x.name
end

# Search a vm
vm = dc.find_vm('DC0_H0_VM0') || fail('VM not found')

# ReconfigVM_Task
# pp vm.config
spec = {}
spec['name'] = 'DC0_H0_VM2'
ret = vm.ReconfigVM_Task(spec: spec).wait_for_completion
  • bundle exec ruby app.rb

という感じで使えます

Tips 使える関数の一覧

  • curl -sk https://user:pass@127.0.0.1:8989/about

vcsim で使える SOAP API の一覧が確認できます
さすがにすべての API をサポートしているわけではなさそうです

最後に

vcsim を使ってみました
vCenter 環境を簡単に構築できない場合に便利かなと思います
govmomi のレポジトリで管理されているので p-r などは govmomi 自体に送ることになります

参考サイト

2019年2月18日月曜日

Linked Clone を Ruby で試してみた

概要

Linked Clone は差分クローンでフルクローンに比べて高速に VM をクローンすることができます
API 的に CloneVM_Task を使いますがある条件下で CloneVM_Task をコールすることで Linked Clone になります
今回は rbvmomi を使って Linked Clone API をコールしてみました

環境

  • CentOS 7.5.1804
  • Ruby 2.5.0p0
  • rbvmomi 2.0.1

Linked Clone with rbvmomi

とりあえず素の状態の VM から Linked Clone な VM を作成するスクリプトです

  • vim clone_vm.rb
require 'rbvmomi'

src = 'src'
dest = 'dest'
dc = 'dc'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.10',
  user: 'vcenter-user',
  password: 'vcenter-pass',
  insecure: 'true'
)
dc = vim.serviceInstance.find_datacenter(dc)
vm = dc.find_vm(src)
disks = vm.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
disks.select { |x| x.backing.parent == nil }.each do |disk|
  spec = {
    :deviceChange => [
      {
        :operation => :remove,
        :device => disk
      },
      {
        :operation => :add,
        :fileOperation => :create,
        :device => disk.dup.tap { |x|
          x.backing = x.backing.dup
          x.backing.fileName = "[#{disk.backing.datastore.name}]"
          x.backing.parent = disk.backing
        },
      }
    ]
  }
  vm.ReconfigVM_Task(:spec => spec).wait_for_completion
end
relocateSpec = RbVmomi::VIM.VirtualMachineRelocateSpec(:diskMoveType => :moveChildMostDiskBacking)
spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => relocateSpec,
                                   :powerOn => false,
                                   :template => false)
vm.CloneVM_Task(:folder => vm.parent, :name => dest, :spec => spec).wait_for_completion

ポイントは一度、素の VM に対して ReconfigVM_Task を実行している点です
「素」の VM というのは差分ディスクを持たない VM のことをいいます
この素の VM に対して CloneVM_Task を実行してもフルクローンになってしまいます
VirtualDisk のデバイスを新規に追加し追加したディスクの親ディスクを指定することで差分ディスクを作成することができます

実行結果

下の図は素の VM に対して ReconfigVM_Task を実行して差分ディスクを追加した状態のデータストアの状況です


ReconfigVM_Task 実行後

下は src_1.vmdk という差分ディスクが増えていることがわかります
また mob で「src」VM の VirtualDisk の backing の情報を見ると parent がリンク状態になり存在していることがわかります

「dest」VM のデータストアを見てみると極小の vmdk ファイルのみが作成されています

vCenter Web クライアントから見えるタスク的には再設定後に通常のクローンのタスクが実行されているように見えます
なのでタスクだけ見ても Linked Clone かどうかはわかりません

スナップショットでもいいのか

差分ディスクと言えばスナップショットです
先程のサンプルでは差分ディスクをコード上で追加しました
スナップショットを事前に作成しておくことで同じことができないかも試してみました
まず再度「素」の VM を用意しましょう
そして API でも Web クライアントでも何でもいいのでスナップショットを作成します

差分ディスクは 000001 という名前が自動で振られます

この状態で Linked Clone を実行してみましょう
今度は新規でディスクを追加するロジックをごっそり削除しています

  • vim clone_vm2.rb
require 'rbvmomi'

src = 'src'
dest = 'dest'
dc = 'dc'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.10',
  user: 'vcenter-user',
  password: 'vcenter-pass',
  insecure: 'true'
)
dc = vim.serviceInstance.find_datacenter(dc)
vm = dc.find_vm(src)
relocateSpec = RbVmomi::VIM.VirtualMachineRelocateSpec(:diskMoveType => :moveChildMostDiskBacking)
spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => relocateSpec,
                                   :powerOn => false,
                                   :template => false)
vm.CloneVM_Task(:folder => vm.parent, :name => dest, :spec => spec).wait_for_completion

これで実行しても Linked Clone になりました
ということでスナップショットを事前に作成しておくだけでも Linked Clone にすることができます
要するに元の VirtualDisk を親ディスクとして差分ディスクを追加すれば何でも良いようです

その他

bVmomi::VIM.VirtualMachineRelocateSpec:diskMoveType => :moveChildMostDiskBacking は地味に必須です
これがないと Linked Clone になりません
どういうパラメータかというとクローンする際に使用するディスクを親ディスクから共有するというパラメータになります
つまり、子ディスク (差分ディスク) だけ移動して VM をクローンすることを意味するのでこれで Linked Clone な VM を作成することができます
これを指定しないとフルクローンになるので注意が必要です

また Linked Clone VM がある状態で差分ディスクを削除することはできませんでした
ただ Web Client から試しにスナップショットを削除してみたところスナップショット自体は削除できたのですがデータストアにはまだ src-000001.vmdk が残っていました
要するに親子関係が残った状態の差分ディスクだけは削除されないということになります
スナップショットは削除できるので差分ディスクもないかなと思いきや差分ディスクはあったので気付きとしてメモしておきます

最後に

Linked Clone を rbvmomi で試してみました
最大のポイントを親ディスクを参照する差分ディスクを事前に作成しておく点かなと思います
Linked Clone は差分ディスクだけを使って VM をクローンする手法なので差分ディスクの作成自体はスナップショットなどの方法でも OK です

2019年2月6日水曜日

InstantClone した VM に PromoteDisks を実行し元の VM と同じ状態にする方法

概要

前回 InstantClone を実行し高速に VM をクローンする方法を紹介しました
InstantClone は内部的には大元の VM の vmdk の差分分だけを管理しており元の VM の変更の影響を受けます

もし InstantClone した VM を大元とは別で管理したい場合には PromoteDisks という API をコールすることでクローン VM を昇格させることができます

今回は PromoteDisks API を InstantClone した VM に適用してみました

環境

  • VCSA 6.7.0.20000 build 10244745
  • ESXi 6.7.0 Update 1 (Build 10302608)
  • Ubuntu 18.04 LTS (クローン元)

事前準備

前回の記事を参考に 1 台 InstantClone VM を作成しておいてください
またファイルストアを確認すると vmdk が元の VM に比べて差分しか存在しないことを確認します

また重要なポイントとして InstantClone VM は事前に停止しておいてください
起動した状態だと PromoteDisks API がエラーを返してしまいます

mob からコールする

PromoteDisks API を一番てっとり早くコールできるのは mob なので今回は mob を使います
作成した InstantClone VM を探しアクセスしましょう

そしてメソッドの一覧から PrometeDisks_Task を探します
クリックすると API をコールするために別ウィンドウが開きます

パラメータは以下のように入力します

  • unlink・・・true
  • disks・・・
<disks>
   <key>2000</key>
   <capacityInKB>31457280</capacityInKB>
</disks>

ポイントは unlink を true にする点です
こうすることで大元のディスクとの紐付きを解消し VM が独立することができます
keycapacityInKB は大元の VM に接続されている VirtualDisk の数分用意、引用してください
今回はディスクは 1 つしかないので 1 つ分のディスク情報を記載します

結果を確認する

API を実行するとタスクにディスクの昇格の進捗ステータスが表示されます

完了後に再度 InstantClone VM のディスクストアを確認しましょう
先程よりも大幅に vmdk のサイズが大きくなっていると思います
このサイズはクローン元の VM の vmdk サイズと同じサイズになっているはずです

最後に

InstantClone した VM に対して PromoteDisks を実行することで VM を昇格させる方法を紹介しました
ポイントは昇格対象のクローン VM が停止していなければいけない点かなと思います
また昇格するディスク分パラメータを付与する点もポイントかなと思います

本文内では触れなかったのですがクローン元の VM にスナップショットが存在する場合も PromoteDisks できない可能性があります
試している最中に API が失敗するケースがあり調べてみるとクローン元の VM にスナップショットのゴミデータ (xxx-0001.vmdk や xxx-0002.vmdk) がありこれを削除してみたところうまく PromoteDisks できるケースがありました
なので失敗する場合はスナップショットデータを削除してみると良いかもしれません

参考サイト

2018年12月30日日曜日

同一分散仮想スイッチ上の同一分散ポートグループにいる VM 間で通信ができない場合の対処方法

概要

同一ホストであれば通信できるけど異なるホストに移動すると通信できない場合は分散仮想スイッチのアップリンクを確認してみましょう

環境

  • VCSA 6.7.0.20000 build 10244745
  • ESXi 6.7.0 Update 1 (Build 10302608)

分散スイッチにアップリンクを追加する

vds_uplink2.png

アップリンクの部分が 1 以上になっていることを確認しましょう
またこれが各ホストで設定されていることを確認しましょう

VDS にホストを追加するときにアップリンク選択するところがあるのでそこで追加対象のホストが持つそれぞれのアップリンク選択してあげましょう

また大抵の場合は VMkernel で 1 つ使っているので VDS 用にもう 1 つ作成しておきましょう
vds_uplink1.png

VLAN の設定確認

それでもダメな場合は VLAN の設定確認しましょう
「VLAN なし」もしくは「VLAN トランク」にすれば疎通できるようになると思います
vds_uplink3.png

vds_uplink4.png

VLAN ID を設定しちゃダメなのか

自分の場合 VLAN ID を設定すると異なるホスト間で通信できませんでした
が、普通に考えればできるんじゃないかなと思います

物理のネットワーク側で対象の VLAN ID が振られている通信を許可する必要があります
Nested を使っている場合はとりあえずトランクなり VLAN ID なしにしておけば良いかなと思います
物理側は使用している機器や環境に応じてかなり変わってくるので自身の環境に合わせて適切に設定してください

参考サイト

2018年12月24日月曜日

VMKernel ネットワークで vMotion を有効にしないと vMotion できない

概要

vMotion できない場合は確認してみてください

環境

  • VCSA 6.7.0.20000 build 10244745
  • ESXi 6.7.0 Update 1 (Build 10302608)

VMKernel の設定を確認

こんなエラーが出て vMotion できない場合は
vmkernel_vmotion_check1.png

対象のホストの VMKernel アダプタの設定を選択して「vMotion」の欄が有効になっているか確認してください
vmkernel_vmotion_check2.png

もしここが有効になっていない場合は設定から有効にしましょう

あとは他のホストに vMotion できない原因としては VM が配置されているストレージが ESXi のローカルストレージ (datastore1 など) になっている場合があります
ホスト同士が共有ストレージ (例えば nfs など) を使っている必要があり要するに異なるホスト間から対象の VM の vmdk や vmx ファイルを参照できる必要があるということです

2018年12月23日日曜日

VCSA6.7u1 で「サービス vpxd-svcs の開始中にエラーが発生しました」でセットアップに失敗する

概要

VCSA 6.7u1 をセットアップ中にタイトルのエラーが出て先に進めなくなりました
その場合の対処方法を紹介します

環境

  • VCSA 6.7.0.20000 build 10244745
  • ESXi 6.7.0 Update 1 (Build 10302608)

背景

今回は VCSA に FQDN ではなく IP アドレスを振ることを想定しています
FQDN の場合 DNS サーバが必要になりそれが面倒なので IP で管理します
ただその場合に該当のエラーが発生しました

対処方法

IP アドレスの割り当てを static で振るようにしましょう
DHCP を使っている場合、該当のエラーが発生します
インストール時だと以下の画面での設定です
vpxd_svcs_not_working1.png

またセットアップ時にも気をつける点があります
同じようにネットワークを設定する項目がありその中の「マシン名」という項目にも同じ IP アドレスを設定しましょう
確かデフォルトだと「photon-machine」になっていると思いますがそれだと名前解決できずにエラーとなります

参考サイト

2018年12月22日土曜日

InstantClone_Task 時に IP がバッティングしないようにする方法

概要

過去に紹介した記事に InstantClone 時に IP がバッティングしてしまうという問題があることを紹介しました
vmware-tools を使った解決方法がわかったので紹介します

環境

  • VCSA 6.7.0.20000 build 10244745
  • ESXi 6.7.0 Update 1 (Build 10302608)
  • Ubuntu 18.04 LTS (クローン元)

クローン元の VM で準備

事前に作業が必要です
スクリプトを配置するだけです

ネットワーク情報を更新するスクリプトを準備

配置する場所はどこでも OK です
まだ実行しないでください

  • vim my_customize.sh
#!/bin/bash
vmware-rpctool "instantclone.freeze"

echo "Updating MAC Address ..."
for NETDEV in /sys/class/net/e*
do
        DEVICE_LABEL=$(basename $(readlink -f "$NETDEV/device"))
        DEVICE_DRIVER=$(basename $(readlink -f "$NETDEV/device/driver"))
        echo $DEVICE_LABEL > /sys/bus/pci/drivers/$DEVICE_DRIVER/unbind
        echo $DEVICE_LABEL > /sys/bus/pci/drivers/$DEVICE_DRIVER/bind
done

echo "Updating Hostname ..."
hostnamectl set-hostname ic01
  • chmod 755 my_customize.sh

やっていることは Mac アドレスの unbind/bind です
これを実行することでクローン元で使っていたイーサネットカードの Mac アドレスをリフレッシュして本来あるべき Mac アドレスを割り当てます

  • echo "0000:03:00.0" > /sys/bus/pci/drivers/vmxnet3/unbind
  • echo "0000:03:00.0" > /sys/bus/pci/drivers/vmxnet3/bind

ちなみに今回の環境は DHCP なのでこれを行うだけで dhclient が動作して DHCP サーバから IP の取得も行ってくれます

スナップショットを取得しておこう (optional)

この後で先程配置したスクリプトを実行します
スクリプトは一度実行すると VM が何も受け付けない状態になってしまいます
再起動すれば直りますが毎回再起動するのは面倒なのでスナップショットを取得しておきましょう

スクリプトを実行しておく

準備ができたらクローン元の VM でスクリプトを実行しておきましょう

  • ./my_customize.sh

という感じでスクリプトを実行すると VM が何も受け付けない状態 (フリーズ) になります
スクリプト内に記述した vmware-rpctool "instantclone.freeze" が実行されフリーズ状態になります

IP などもなくなるので SSH している場合には通信が切れます
ちなみにこうなると復帰させる方法はスナップショットから元に戻すか VM を再起動するしかありません

InstantClone を実行

フリーズ状態になったクローン元の VM を使って InstantClone を実行しましょう
API からのみ実行できるのできるので mob や rbvmomi を使いましょう (参考)

動作確認

InstantClone した VM で以下を確認しましょう

  • IP アドレスがクローン元の VM と別のものが振られている
  • ホスト名が設定されている

特に IP アドレスに関しては VM が起動してすぐに別の IP が振られていることを確認してみましょう
(Web Client から見るとクローン元の VM が振られているように見えますが実際は別の IP になっていると思います)

おまけ: guestinfo を組み合わせる

例えばホスト名などは動的に決めたい場合があります
そんな場合は InstantClone 時に guestinfo を設定することで実現することができます
またスクリプトも guestinfo から値を取得するように変更します

  • vim my_customize.sh
#!/bin/bash
vmware-rpctool "instantclone.freeze"

echo "Updating MAC Address ..."
for NETDEV in /sys/class/net/e*
do
        DEVICE_LABEL=$(basename $(readlink -f "$NETDEV/device"))
        DEVICE_DRIVER=$(basename $(readlink -f "$NETDEV/device/driver"))
        echo $DEVICE_LABEL > /sys/bus/pci/drivers/$DEVICE_DRIVER/unbind
        echo $DEVICE_LABEL > /sys/bus/pci/drivers/$DEVICE_DRIVER/bind
done

echo "Updating Hostname ..."
HOSTNAME=$(vmware-rpctool "info-get guestinfo.ic.hostname")
hostnamectl set-hostname ${HOSTNAME}

そして InstantClone を guestinfo 付きで実行します

  • vim instant_clone.rb
require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.30',
  user: 'administrator@vsphere.local',
  password: 'xxxxxxxxxxx',
  insecure: 'true',
  rev: '6.7.1'
)

dc = vim.serviceInstance.find_datacenter('Datacenter') || fail('datacenter not found')
vm = dc.find_vm('u18_01') || fail('VM not found')

spec = {
  name: "ic01", location: "",
  config: [
    {key: "guestinfo.ic.hostname", value: "ic01"}
  ]
}
ret = vm.InstantClone_Task(spec: spec).wait_for_completion
puts ret

こんな感じでホスト名を設定できます

ちなみに今回は DHCP 環境だったので Mac アドレスの更新だけで良かったのですが IP を static で振る場合には guestinfo を使って実現することもできます
static IP を振る場合はこちらのスクリプトが参考になると思います

最後に

InstantClone_Task でクローン先の VM に同じ IP が振られてしまう現象に対応してみました
今回は Ubuntu18.04 に対するスクリプトなので別のディストリビューションや GuestOS であればそれ用のスクリプトを作成する必要があります

ちなみに InstantClone はクローン元の VM のコンソール情報もクローンします
なので InstantClone 前にコンソールでログインした状態にしてしまうとクローン後の VM もすでにコンソールでログインしている状態になってしまうので注意しましょう

参考サイト

2018年12月21日金曜日

InstantClone_Task 時に guestinfo を渡す方法

概要

前回 InstantClone をサクっと試してみました
実は InstantClone_Task 実行時に作成されたインスタントクローン VM に guestinfo を渡すことができます
gusetinfo は簡単に言えば GuestOS (例えば Ubuntu など) 上で参照することができる変数です

環境

  • VCSA 6.7.0.20000 build 10244745
  • ESXi 6.7.0 Update 1 (Build 10302608)
  • Ruby 2.5.0p0
  • rbvmomi (2.0.0)

guestinfo を指定する方法

spec に config を key/value 形式で並べるだけです

<spec>
   <name>ic01</name>
   <location></location>
   <!-- ok -->
   <config>
      <key>guestinfo.ic.hoge</key>
      <value xsi:type="xsd:string">guestinfo.ic.hoge</value>
   </config>
   <config>
      <key>guestinfo.ic.fuga</key>
      <value xsi:type="xsd:string">guestinfo.ic.fuga</value>
   </config>
   <config>
      <key>guestinfo.iic.fuga</key>
      <value xsi:type="xsd:string">guestinfo.iic.fuga</value>
   </config>
   <config>
      <key>guestinfo.fuga</key>
      <value xsi:type="xsd:string">guestinfo.fuga</value>
   </config>
   <!-- ng -->
   <config>
      <key>ic.fuga</key>
      <value xsi:type="xsd:string">ic.fuga</value>
   </config>
   <config>
      <key>fuga</key>
      <value xsi:type="xsd:string">fuga</value>
   </config>
</spec>

少しポイントがあります
渡せる key に制約があるようで必ず guestinfo で始まっている必要がありました
もし制約違反していると値が GuestOS 側に渡りません
参照しても Invalid key name supplied になります
また、存在しない key を指定すると No value found になります

どうやって参照するの

vmware-tools の機能を使います
vmware-tools がインストールされていると vmware-rpctool コマンドが使えます
実際にインスタントクローンされた VM にログインして以下のコマンドを叩いてみましょう

  • vmware-rpctool "info-get guestinfo.ic.hoge"

すると設定した value 側の値が取得できると思います

おまけ: rbvmomi でやってみた

require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.30',
  user: 'administrator@vsphere.local',
  password: 'xxxxxxxxxxx',
  insecure: 'true',
  rev: '6.7.1'
)

dc = vim.serviceInstance.find_datacenter('Datacenter') || fail('datacenter not found')
vm = dc.find_vm('u18_01') || fail('VM not found')

spec = {
  name: "ic01", location: "",
  config: [
    {key: "guestinfo.ic.hoge", value: "hoge"},
    {key: "guestinfo.ic.fuga", value: "fuga"}
  ]
}
ret = vm.InstantClone_Task(spec: spec).wait_for_completion
puts ret

spec の指定を mob で実行する spec に合わせるだけです

最後に

InstantClone_Task 時に gusetinfo を渡す方法を紹介しました
実はこれを応用すると前回紹介した InstantClone 時に IP アドレスがバッティングしてしまう問題を解決することができます

要するにネットワーク情報を guestinfo で渡してインスタントクローン VM が作成されたときにネットワークを設定するスクリプトを実行することでバッティングを解消するという流れになります

ちょっと力技感も強いですがこちらで紹介されていたのでほぼオフィシャルなのかなと思います
具体的なやり方も分かったら紹介したいと思います

参考サイト

2018年12月20日木曜日

vSphere 6.7 で InstantClone_Task を試してみた

概要

vSphere 6.7 から正式に InstantClone が使えるようになったので試してみました
Web Client からは使えないので mob と SOAP API (rbvmomi) から実行してみました

環境

  • VCSA 6.7.0.20000 build 10244745
  • ESXi 6.7.0 Update 1 (Build 10302608)
  • Ruby 2.5.0p0
  • rbvmomi (2.0.0)

mob から実行する

対象の VM に移動して methods 内から InstantClone_Task を選択すれば OK です
条件としては対象の VM が起動している必要があります (停止中の VM に対して実行したところエラーになりました)
instant_clone1.png

最低限必要な spec は以下の通りです

<spec>
   <name>ic01</name>
   <location>
   </location>
</spec>

instant_clone2.png

これで Invoke すれば InstantClone で VM が作られます
location を指定すれあ別のホストに作成することもできます

rbvmomi から実行する

プログラムからも実行してみました

  • bundle init
  • vim Gemfile
gem "rbvmomi"
  • bundle install --path vendor
  • vim main.rb
require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.30',
  user: 'administrator@vsphere.local',
  password: 'xxxxxxxxxxx',
  insecure: 'true',
  rev: '6.7.1'
)

dc = vim.serviceInstance.find_datacenter('Datacenter') || fail('datacenter not found')
vm = dc.find_vm('vm01') || fail('VM not found')

spec = {name: "ic01", location: ""}
ret = vm.InstantClone_Task(spec: spec).wait_for_completion
puts ret
  • bundle exec ruby main.rb

これだけです
rbvmomi で実施する場合は VIM.connect する際に rev: '6.7.1' の指定が必要です
WSDL から InstantClone_Task を探すのですが rev: を明示的に指定しないと探すことができずエラーになってしまいます
またパワーオンになっていないと以下のエラーが発生します
InvalidPowerState: The attempted operation cannot be performed in the current state (Powered off). (RbVmomi::Fault) (edited)

ちなみに WSDL の URL は https://192.168.100.30/sdk/vim.wsdl という感じの URL で確認できます

最後に

InstanceClone_Task を試してみました
いろいろ経緯とかを調べてみるとコンテナの需要が高まったのと CI/CD で使えないかという要望があったららしいです
なのであくまでも用途としては使い捨て VM という感じで使うのだと思います

一つ気になったのはインスタンスクローン後にクローン元の VM と同じ IP が振られる現象が多々ありました
ネットワークのインタフェースの MAC アドレスクローン直後は同一に見えてしまうため DHCP も同じ IP を払い出しているんだと思います
再起動したり一定時間経過すると異なる IP が振られたのですが、直後はどう対処すれば良いか不明でした

P.S どうやら GuestInfo の仕組みを使って VM ないで IP のリフレッシュ作業を行う必要があるようです
https://www.virtuallyghetto.com/2018/04/new-instant-clone-architecture-in-vsphere-6-7-part-2.html
おそらくこの方法が確実だと思われます

参考サイト

2018年12月18日火曜日

VDDK API 学習コンテンツ

これまで VDDK API 絡みでいろいろと記事を投稿してきました
一通り基本から応用まで学べるコンテンツになったので記事をまとめておきます

基本概念

VDDK API を使ったバックアップ処理を実装する際の基本概念や簡単な仕組みを紹介しています
図も載せているので導入としては理解しやすいと思います

VDDK のインストールおよびサンプルのビルドと実行方法を紹介しています

VDDK API 入門

VDDK API を C++ から操作する基本的な方法を紹介しています
Init -> Connect -> Open までの基本的な操作を学べます

vmdk から実際にセクタ情報を取得/書き込みするサンプルです
とりあえず Read/Write の動かし方を学ぶことができます

セクタの書き込み、読み込みとは別の API も試しました
PrepareForAccess と EndAccess は対象の VM の vMotion を禁止することができます

VDDK API 側のログを出力する方法を紹介しています
Init する際に設定ファイルを指定する方法も紹介しています

VixDiskLib_QueryAllocatedBlocks は 6.7 を使った際にフルバックアップを実装するために使います
応用では他の API と組み合わせて実際にフルバックアップを実装しています

CBT 入門

コーディングの前に ManagedObjectBrowser を使ってディスクの増分領域を取得する方法を紹介しています

mob を使って実行した操作を govmomi を使ってコードに落とし込んでいます
govmomi を使った初期化の部分から学べます

応用

フルバックアップを実装してみました
対象の VM と全く同じ VM を作ることができます
VDDK API の基本操作と vSphere API の QueryChangedDiskAreas の使い方および CBT の使い方を理解している必要があります

こちらは増分バックアップのサンプル実装になります
vSphere API と組み合わせた実装になっているのでより難しくなっています

2018年12月16日日曜日

QueryChangedDiskAreas と VixDiskLib_Read/Write を組み合わせて増分バックアップをしてみた

概要

CBT を有効にした VM に対して QueryChangedDiskAreas を実行することでディスクの変更箇所を確認することができます (参考)
今回は govmomi で変更箇所を取得し VDDK API の VixDiskLib_ReadVixDiskLib_Write を使ってディスクの変更箇所 (増分) だけをディスクに追記してみました

環境

  • CentOS 7
  • VCSA 6.5.0 9451637
  • VDDK API 6.7.1
  • golang 1.11.2

事前作業

全く同じ状態のサーバを 2 台用意しましょう
そして 1 台 (src) を変更してその変更をもう 1 台 (dest) に反映する処理をします
同じサーバは VixDiskLib_QueryAllocatedBlocks を使ってコピーを作成しても OK ですしクローンでも OK です

src での作業

CBT を有効にする

src (vm-10) の VM に対して CBT を有効にしましょう
こちらの記事を参考に mob を使ってやるのが簡単だと思います

CBT を有効化したらスナップショットを作成し ChangeID を取得しておきます (52 54 eb 64 13 82 bc 71-41 42 a2 b3 ba f4 96 2e/102)
ここで取得した ChangeID は src の大元の ChangeID になります
この ChangeID とこの後新たに作成するスナップショットを使って QueryChangedDiskAreas を実行し増分情報を取得します

ChangeID を取得したらスナップショットは削除して OK です

増分を取得する

サーバは起動するだけでもまだ増分が出るので起動するだけでも良いですがそれだとつまらないので適当にファイルでも作成しましょう
一旦 src サーバを起動して以下のファイルを作成しましょう

  • date > src_file.txt

ファイルを作成したら VM を一旦停止しスナップショットを新たに作成しましょう (snapshot-20)
そしてそのスナップショットと先ほどメモしておいた ChangeID を使って増分情報を取得します

package main

import (
    "context"
    "flag"
    "fmt"
    "net/url"
    "os"

    "github.com/vmware/govmomi"
    "github.com/vmware/govmomi/find"
    "github.com/vmware/govmomi/vim25/methods"
    "github.com/vmware/govmomi/vim25/types"
)

var envURL = "https://192.168.100.20/sdk"
var user = "administrator@vsphere.local"
var pass = "xxxxxxxxxxxx"
var vmname = "src"
var diskNum int32 = 2000
var changeID = "52 54 eb 64 13 82 bc 71-41 42 a2 b3 ba f4 96 2e/102"
var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", envURL, urlDescription)

var envInsecure = true
var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", envInsecure, insecureDescription)

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    flag.Parse()
    u, err := url.Parse(*urlFlag)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    u.User = url.UserPassword(user, pass)
    c, err := govmomi.NewClient(ctx, u, *insecureFlag)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    f := find.NewFinder(c.Client, true)
    dc, err := f.DefaultDatacenter(ctx)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    f.SetDatacenter(dc)
    ss := &types.ManagedObjectReference{Type: "VirtualMachineSnapshot", Value: "snapshot-20"}
    // change disk areas
    query := new(types.QueryChangedDiskAreas)
    query.ChangeId = changeID
    query.DeviceKey = diskNum
    query.Snapshot = ss
    query.StartOffset = 0
    query.This.Type = "VirtualMachine"
    query.This.Value = "vm-10"
    res, err := methods.QueryChangedDiskAreas(ctx, c.RoundTripper, query)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    for _, area := range res.Returnval.ChangedArea {
        fmt.Printf("%d,%d\n", area.Start, area.Length)
    }
}

QueryChangedDiskAreas は vSphere API なので golang からコールします
しかし VDDK API は c++ から呼ぶので連携するために CSV ファイルを作成します

  • go build github.com/hawksnowlog/j
  • go install github.com/hawksnowlog/j
  • $GOPATH/bin/j > changed_areas.csv

この CSV 増分の offset と length が羅列されています

1048576,65536
135266304,131072
143654912,65536
155189248,65536
155713536,65536
511705088,1703936
...

dest での作業

dest VM は念の為停止しておきましょう

増分を書き込む

先程の CSV を使って VDDK API で増分のセクタ情報を書き込みます
まずコードは以下の通りです

#include <iostream>
#include <cstring>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include "vixDiskLib.h"
using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::ifstream;
using std::istringstream;

#define VIXDISKLIB_VERSION_MAJOR 6
#define VIXDISKLIB_VERSION_MINOR 7

static struct {
  VixDiskLibConnection connection;
  char *libdir;
  char *cfgFile;
} params, wparams;

static void LogFunc(const char *fmt, va_list args) {
  printf("Log: ");
  vprintf(fmt, args);
}

static void WarnFunc(const char *fmt, va_list args) {
  printf("Warning: ");
  vprintf(fmt, args);
}

static void PanicFunc(const char *fmt, va_list args) {
  printf("Panic: ");
  vprintf(fmt, args);
  exit(10);
}

static vector<string> split(string& input, char delimiter) {
  istringstream stream(input);
  string field;
  vector<string> result;
  while (getline(stream, field, delimiter)) {
    result.push_back(field);
  }
  return result;
}

int main(int argc, char* argv[]) {
  VixDiskLibHandle _handle = NULL;
  VixDiskLibHandle _whandle = NULL;
  try {
    VixError err;

    err = VixDiskLib_InitEx(VIXDISKLIB_VERSION_MAJOR, VIXDISKLIB_VERSION_MINOR, &LogFunc, &WarnFunc, &PanicFunc, params.libdir, "init.cfg");
    printf("%lu\n", err);
    err = VixDiskLib_InitEx(VIXDISKLIB_VERSION_MAJOR, VIXDISKLIB_VERSION_MINOR, &LogFunc, &WarnFunc, &PanicFunc, wparams.libdir, "init.cfg");
    printf("%lu\n", err);

    VixDiskLibConnectParams cnxParams = {0};
    cnxParams.vmxSpec = {(char*)"moref=vm-10"};
    cnxParams.specType = VIXDISKLIB_SPEC_VMX;
    cnxParams.serverName = {(char*)"192.168.100.20"};
    cnxParams.credType = VIXDISKLIB_CRED_UID;
    cnxParams.creds.uid.userName = {(char*)"administrator@vsphere.local"};
    cnxParams.creds.uid.password = {(char*)"xxxxxxxxxxxx"};
    cnxParams.thumbPrint = {(char*)"96:09:d6:5b:e0:83:58:1b:ba:2b:cc:78:22:88:33:36:64:50:32:eb"};
    err = VixDiskLib_ConnectEx(&cnxParams, 1, NULL, NULL, &params.connection);
    printf("%lu\n", err);
    VixDiskLibConnectParams wcnxParams = {0};
    wcnxParams.vmxSpec = {(char*)"moref=vm-20"};
    wcnxParams.specType = VIXDISKLIB_SPEC_VMX;
    wcnxParams.serverName = {(char*)"192.168.100.20"};
    wcnxParams.credType = VIXDISKLIB_CRED_UID;
    wcnxParams.creds.uid.userName = {(char*)"administrator@vsphere.local"};
    wcnxParams.creds.uid.password = {(char*)"xxxxxxxxxxxx"};
    wcnxParams.thumbPrint = {(char*)"96:09:d6:5b:e0:83:58:1b:ba:2b:cc:78:22:88:33:36:64:50:32:eb"};
    err = VixDiskLib_ConnectEx(&wcnxParams, 1, NULL, NULL, &wparams.connection);
    printf("%lu\n", err);

    err = VixDiskLib_Open(params.connection, "[datastore2] src/src.vmdk", VIXDISKLIB_FLAG_OPEN_SINGLE_LINK, &_handle);
    printf("%lu\n", err);
    err = VixDiskLib_Open(wparams.connection, "[datastore2] dest/dest.vmdk", VIXDISKLIB_FLAG_OPEN_SINGLE_LINK, &_whandle);
    printf("%lu\n", err);

    ifstream ifs("changed_areas.csv");
    string line;
    while (getline(ifs, line)) {
      vector<string> strvec = split(line, ',');
      VixDiskLibSectorType offset = stoul(strvec.at(0)) / VIXDISKLIB_SECTOR_SIZE;
      VixDiskLibSectorType length = stoul(strvec.at(1)) / VIXDISKLIB_SECTOR_SIZE;
      printf("offset: %lu\n", offset);
      printf("length: %lu\n", length);
      VixDiskLibSectorType start = offset;
      VixDiskLibSectorType bufSize = 128;
      VixDiskLibSectorType count = length / bufSize;
      for (VixDiskLibSectorType j = 0; j < count; j++) {
        uint8 *buf = new uint8[bufSize * VIXDISKLIB_SECTOR_SIZE];
        // read
        err = VixDiskLib_Read(_handle, start + (j * bufSize), bufSize, buf);
        if (err != VIX_OK) {
          throw std::exception();
        }
        // write
        err = VixDiskLib_Write(_whandle, start + (j * bufSize), bufSize, buf);
        if (err != VIX_OK) {
          throw std::exception();
        }
        delete[] buf;
      }
    }
    VixDiskLib_Close(_whandle);
    VixDiskLib_Close(_handle);
    VixDiskLib_Disconnect(params.connection);
  } catch (...) {
    VixDiskLib_Close(_whandle);
    VixDiskLib_Close(_handle);
    VixDiskLib_Disconnect(params.connection);
  }
  return 0;
}

解説

CSV の読み込みは ifstream を使います
必要になるヘッダファイルがあるので冒頭で追加しています
読み込んだ CSV の行数分ループさせます

実は CSV の offset と length の値はそのままでは使えません
VDDK API の世界で使える単位にしなければいけないので VIXDISKLIB_SECTOR_SIZE (512) で割る必要があります
(どこにもこの情報がなく初めはそのまま使っていたのですがうまく行かずいろいろ試してたどり着きました、、)

VixDiskLibSectorType offset = stoul(strvec.at(0)) / VIXDISKLIB_SECTOR_SIZE;
VixDiskLibSectorType length = stoul(strvec.at(1)) / VIXDISKLIB_SECTOR_SIZE;

あとは基本的には[フルバックアップ時[()に行ったように書き込めば OK です
bufSize を上げれば Read/Write の速度が上昇します
増分はそこまで多くないのであれば 128 で十分だと思います

動作確認

実際に VDDK API 側のコードを動かして dest VM を起動すると src VM 側に作成した src_file.txt があるのが確認できると思います

この方法だと確かに増分のファイルだけ送ることができるようになります
ですが src 側の kernel ログなども書き込んでしまいます
dest があくまでも src 側のバックアップサーバなのであれば問題ないですが、そうでない場合は src と dest のログが混在するケースが発生するので注意が必要です

最後に

QueryChangedDiskAreas を使って増分バックアップを実装してみました

後で調べてみたのですが QueryChangedDiskAreas にバグのような挙動があるらしく vmdk のサイズを後から拡大するとおかしな offset と length を返すようです (参考1, 参考2)
今回使用した vSphere 6.5 環境でその現象になるかまでは試していません
最新版は 6.7 なので最新版では解決している可能性もあります
そもそもこのバグらしく挙動をどうやって再現するのかから考えないとダメそうですが、、