社屋ビルの夜間計画停電に伴い、社内で運用している仮想化されたサーバ群と、それらを内包する VMware ESXi ホストを停電時間前に安全に シャットダウン させるための、 スケジュール シャットダウン についてまとめました。
vMAから仮想マシンをシャットダウン
社内の仮想サーバの載った複数台のVMware ESXiホスト(ver.6.5〜6.7で構成)は、vCenterサーバとvSphere Management Assistant (vMA)で管理運用されています。
仮想マシンの夜間のクローニングや再起動、開始や停止は全てvMAからcronにより自動運用です。もう何年も使い続けている停止スクリプトは以下のような構成で、これを複数の仮想マシン各々の役割に応じ、適切な順序と適度な間隔を開けながらシャットダウンさせることが出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#!/bin/bash ## VM POWER OFF SCRIPT FOR vCENTER ## Usage: vm_halt.sh vmStr tgtDS ## Ex: vm_halt.sh SRV09 [VD3_vm25] # PARAMETER CHECK echo "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $1] ${0##*/} Batch Raised" if [ $# -lt 2 ] then echo "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $1] Argument must be provided. Batch Aborted\n\n" exit 1 fi # VARIABLES export VI_USERNAME=##################### export VI_PASSWORD=##################### export VI_SERVER=192.168.2.23 vmStr=$1 tgtDS=$2 tgtHst=`echo $tgtDS | sed -e "s/^.VD.*_vm/192.168.2./;s/]$//"` echo "VM : $vmStr" echo "VI Host: $tgtHst" echo "Datastore: $tgtDS" # PING CHECK TO vCSA & VIhosts ping -c 1 $VI_SERVER > /dev/null 2>&1 if [ $? != 0 ] then echo -e "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $vmStr] $VI_SERVER vCenter Offline. Batch Aborted\n\n" exit 1 fi ping -c 1 $tgtHst > /dev/null 2>&1 if [ $? != 0 ] then echo -e "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $vmStr] $tgtHst VI Host Offline. Batch Aborted\n\n" exit 1 fi # GET REAL VMX PATH tgtVmxPath=`vmware-cmd -h $tgtHst -l | grep $vmStr` vmstat="Unregistered" if [ -n "$tgtVmxPath" ] then vmstat=`vmware-cmd -h $tgtHst $tgtVmxPath getstate` fi echo "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $vmStr] VM Status: $vmstat" # ABORT IF TARGET VM IS ALREADY DOWN if [[ ! -z `echo $vmstat | grep "getstate() = off"` ]] then echo -e "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $vmStr] $vmStr at $tgtHst is halted already. Batch Aborted\n\n" exit 1 fi # SEND STOP COMMAND #vmstat=`vmware-cmd -h $tgtHst $tgtVmxPath stop hard` vmstat=`vmware-cmd -h $tgtHst $tgtVmxPath stop soft` echo "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $vmStr] VM Start: $vmstat" # CONFIRM VM STATUS sleep 60s vmstat=`vmware-cmd -h $tgtHst $tgtVmxPath getstate` echo "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $vmStr] VM Status: $vmstat" # END echo -e "[`date +"%Y/%m/%d(%a) %k:%M:%S"` $vmStr] ${0##*/} Batch Completed\n\n" |
実行結果ログには次のような出力が記録されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[2021/07/29(Thu) 19:52:01 SRV12] vm_halt.sh Batch Raised VM : SRV12 VI Host: 192.168.2.26 Datastore: [VD3_vm26] [2021/07/29(Thu) 19:52:11 SRV12] VM Status: getstate() = on [2021/07/29(Thu) 19:52:19 SRV12] VM Start: stop() = 1 [2021/07/29(Thu) 19:53:27 SRV12] VM Status: [2021/07/29(Thu) 19:53:27 SRV12] vm_halt.sh Batch Completed [2021/07/29(Thu) 19:55:01 vcsa67] vm_halt.sh Batch Raised VM : vcsa67 VI Host: 192.168.2.26 Datastore: [VD3_vm26] [2021/07/29(Thu) 19:55:11 vcsa67] VM Status: getstate() = on [2021/07/29(Thu) 19:55:25 vcsa67] VM Start: stop() = 1 [2021/07/29(Thu) 19:56:26 vcsa67] VM Status: [2021/07/29(Thu) 19:56:26 vcsa67] vm_halt.sh Batch Completed |
仮想マシンのスケジュールシャットダウンは以上です。続いてvMAを含めた全ての仮想マシンがシャットダウンした後の、ESXiホスト自身のシャットダウンの仕込みに入ります。
SSHサービスの有効化
VMware ESXiホストサーバは普段、セキュリティ上の理由からSSHサービスを閉じているので、まず最初にWebUIからSSHサービスを起動にします。
SSHが有効になっている間はWebUI上にその旨アラートが表示され続けますが、ESXiホストを再起動後、SSHサービスは再び停止状態になっているので気にする必要はありません。
ESXi ホスト シャットダウンコマンド
ESXiホストをシャットダウンするコマンドは poweroff だそうで、早速有効にしたSSHを介しESXiホストへ入って確認してみると、その実体はBusyBoxでした。
1 2 |
[root@vm21:/] ls -l /sbin/poweroff lrwxrwxrwx 1 root root 35 Jul 7 2017 /sbin/poweroff -> /usr/lib/vmware/busybox/bin/busybox |
さらにESXi 6.5までのシステムは、ホストシャットダウンの前に搭載している仮想マシンやサービスを安全にシャットダウンさせるシェルスクリプトが用意されています。
1 2 |
[root@vm21:/] ls -l /sbin/shutdown.sh -r-xr-xr-x 1 root root 396 Jul 7 2017 /sbin/shutdown.sh |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#!/bin/ash log() { echo "$1" logger init "$1" } #Extract and save the random seed dd if=/dev/urandom of=/etc/random-seed count=1 2>/dev/null #Power off autostart configured VMs /sbin/vmware-autostart.sh stop #Stop running services /sbin/services.sh stop #Backup the config (including the random seed) /sbin/backup.sh 1 #Shutdown syslog daemon /usr/lib/vmware/vmsyslog/bin/shutdown.sh |
ESXi 6.7にもスクリプトファイル自体は存在するものの、中身はコメントアウトの空っぽで廃止されていることが分かります。
1 2 3 |
#!/bin/ash #The usage of shutdown.sh is deprecated! #We keep the file only for legacy reasons. Do not add any new code. |
今回、仮想マシンは全てvMAから別途スクリプトでシャットダウンさせているので、ホストシャットダウンは poweroff コマンドのみで行います。
ESXi ホストのcron
cron設定の記述されたcrontabファイルは、スティッキービット付きの読み取り専用になっているので、まずこれを編集可能な状態へ変更します。
1 2 3 4 5 6 |
[root@vm21:~] ls -l /var/spool/cron/crontabs/root -r--r--r-T 1 root root 324 Jul 7 2017 /var/spool/cron/crontabs/root [root@vm21:~] chmod 1744 /var/spool/cron/crontabs/root [root@vm21:~] ls -l /var/spool/cron/crontabs/root -rwxr--r-T 1 root root 324 Jul 7 2017 /var/spool/cron/crontabs/root |
viエディタでcrontabファイルに poweroff コマンドをフルパスで追加するのですが、この時に指定する時刻は世界時間UTCにする必要があります。下記例では、11+8=19時50分(香港時間:UTC+8)に作動するよう設定しています。
1 2 3 4 5 6 7 8 |
#min hour day mon dow command 1 1 * * * /sbin/tmpwatch.py 1 * * * * /sbin/auto-backup.sh 0 * * * * /usr/lib/vmware/vmksummary/log-heartbeat.py */5 * * * * /bin/hostd-probe.sh ++group=host/vim/vmvisor/hostd-probe/stats/sh 00 1 * * * localcli storage core device purge 50 11 * * * /sbin/poweroff |
編集を保存したら、crontabファイルを読み取り専用に戻し、
1 2 3 |
[root@vm21:~] chmod 1444 /var/spool/cron/crontabs/root [root@vm21:~] ls -l /var/spool/cron/crontabs/root -r--r--r-T 1 root root 383 Jul 29 08:26 /var/spool/cron/crontabs/root |
現在動いているcronプロセスを落として、新規プロセスとして呼び出して、追加した項目を反映させます。
1 2 |
[root@vm21:~] /bin/kill $(cat /var/run/crond.pid) [root@vm21:~] /usr/lib/vmware/busybox/bin/busybox crond |
翌朝早めに出社すると、ESXiホストは全て設定した通り、正常にシャットダウンされていました。