雑木林

頭の中の整理と忘れないための確認メモ

ESXi Hypervisor上のVM自動バックアップ

タイトル通り、無償版のESXiにて仮想マシンのバックアップを取得しようというものです。
特に目新しいこともなく、ghettoVCBを使って行います。
詳しい内容は下記のサイトで良く纏められてますので、そちらを参照ください。

VMware オンラインバックアップ

VMware ESXiでコマンドやスクリプトを定期実行させる方法&オンラインバックアップ - Qiita

今回はghettoVCBを使って以下を実現したかったのでその備忘録を残します。

作業の流れ

特に上記のサイトとやっていることは変わりません。

  1. ghettoVCB本体の取得、展開
  2. ghettoVCBの編集
  3. 作成したスクリプトの格納
  4. 手動実行確認
  5. cron登録

フォルダ構成

バックアップ用のNFSデータストア上に以下のようなフォルダ構成で作成しています。
ESXiが複数あるので、フォルダを分けました。

/vmfs/volumes/nfs_ds01/backup/
 ├ esxi01
 │ ├ files/         イメージ保存フォルダ
 │ └ script/        スクリプトフォルダ
 │  ├ ghettoVCB-master/  ghettoVCB本体
 │  └ backupVM/      ghettoVCBを呼び出すスクリプト
 ├ esxi02
  ...

1. ghettoVCB本体の取得、展開

githubよりダウンロードしてunzipし、所定のフォルダに展開してください。
wgetでいけるかなと思ったのですが、esxiのwgethttps対応してない?ようで先に進めませんでした。

[root@xh61v:~] wget https://github.com/lamw/ghettoVCB/archive/master.zip
Connecting to github.com (192.30.255.113:443)
wget: error getting response

[root@xh61v: ~] wget --help
BusyBox v1.29.3 (2018-11-02 15:37:50 PDT) multi-call binary.

Usage: wget [-c|--continue] [--spider] [-q|--quiet] [-O|--output-document FILE]
        [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]
        [-S|--server-response] [-U|--user-agent AGENT] URL...

Retrieve files via HTTP or FTP

        --spider        Only check URL existence: $? is 0 if exists
        -c              Continue retrieval of aborted transfer
        -q              Quiet
        -P DIR          Save to DIR (default .)
        -S              Show server response
        -O FILE         Save to FILE ('-' for stdout)
        -U STR          Use STR for User-Agent header
        -Y on/off       Use proxy
[root@xh61v:/vmfs/volumes/56992690-54522fc5/backup] unzip ghettoVCB-master.zip
Archive:  ghettoVCB-master.zip
   creating: ghettoVCB-master/
  inflating: ghettoVCB-master/README.md
  inflating: ghettoVCB-master/ghettoVCB-restore.sh
  inflating: ghettoVCB-master/ghettoVCB-restore_vm_restore_configuration_template
  inflating: ghettoVCB-master/ghettoVCB-vm_backup_configuration_template
  inflating: ghettoVCB-master/ghettoVCB.conf
  inflating: ghettoVCB-master/ghettoVCB.sh
  inflating: ghettoVCB-master/vghetto-ghettoVCB-offline-bundle.zip
  inflating: ghettoVCB-master/vghetto-ghettoVCB.vib

2. ghettoVCBの編集

作成したスクリプトで上書き処理をしてもよかったのですが、こちらでバックアップの設定を行います。
エラー時の通知とかを設定したほうが良さそうですが、今回は割愛。

[root@xh61v: ~] vi /vmfs/volumes/nfs_ds01/backup/esxi01/script/ghettoVCB-master/ghettoVCB.sh
バックアップ先の変更
# directory that all VM backups should go (e.g. /vmfs/volumes/SAN_LUN1/mybackupdir)
VM_BACKUP_VOLUME=/vmfs/volumes/nfs_ds01/backup/esxi01/files/

保存世代数の変更
# Number of backups for a given VM before deleting
VM_BACKUP_ROTATION_COUNT=2

3. 作成したスクリプトの格納

メイン部分ですね。VM一覧の生成と除外リストとの比較を行うスクリプトを格納します。
処理の流れはこんな感じです。(変数は適宜変更してください)

  1. スクリプトのフォルダに仮想マシンの一覧を出力(getallvms.txt)
  2. 仮想マシンの一覧と無視リスト(IGNORE_VMLIST_FILE)を比較して対象を出力(VMLIST_FILE)
  3. バックアップ取得処理の実施
  4. 仮想マシン一覧に無いデータを保存期間経過後(RETENTION_PERIOD_OPTION)に削除する
[root@xh61v:~] vi /vmfs/volumes/nfs_ds01/backup/esxi01/script/backupVM/backupVM.sh
# Backup Volume(Full Path)
VM_BACKUP_VOLUME=/vmfs/volumes/nfs_ds01/backup/esxi01/files/

# Path To ghettoVCB-master Directory(Full Path)
SCRIPT_DIR=/vmfs/volumes/nfs_ds01/backup/esxi01/script/ghettoVCB-master/

# VMList File Name
VMLIST_FILE=vmlist.txt

# Ignore VM List File
IGNORE_VMLIST_FILE=ignore.txt

# Current Directory(ABS Path)
CURRENT_DIR=$(cd $(dirname $0); pwd)

# Retention Period Option
RETENTION_PERIOD_OPTION="-mtime +7"

# Loggin Option
LOG_TO_STDOUT=1
LOG_TO_SYSLOG=1


logging() {
    priority=$1
    message=$2
    time=$(date +%F" "%H:%M:%S)

    if [ ${LOG_TO_STDOUT} -eq 1 ]
    then
        echo -e "${time} -- ${priority}: ${message}"
    fi

    if [ ${LOG_TO_SYSLOG} -eq 1 ]
    then
        logger -p ${priority} "${message}"
    fi
}


logging "user.info" "backup script started."

if [ -d ${SCRIPT_DIR} ]
then
    # Modify Parameter
    sed -i "/^VM_BACKUP_VOLUME=/c VM_BACKUP_VOLUME=${VM_BACKUP_VOLUME}" ${SCRIPT_DIR}/ghettoVCB.sh

    # All VM List
    logging "info" "vim-cmd vmsvc/getallvms | grep vmx | awk '{print $2}' > ${CURRENT_DIR}/getallvms.txt"
    vim-cmd vmsvc/getallvms | grep vmx | awk '{print $2}' > ${CURRENT_DIR}/getallvms.txt

    # Export VM List
    if [ -f ${CURRENT_DIR}/${IGNORE_VMLIST_FILE} ]
    then
        # VM List
        sort ${CURRENT_DIR}/getallvms.txt ${CURRENT_DIR}/${IGNORE_VMLIST_FILE} | uniq -u > ${SCRIPT_DIR}/${VMLIST_FILE}
    else
        # VM List
        cat ${CURRENT_DIR}/getallvms.txt > ${SCRIPT_DIR}/${VMLIST_FILE}
    fi

    # Begin Backup
    logging "info" "begin backup : ${SCRIPT_DIR}/ghettoVCB.sh -f ${SCRIPT_DIR}/${VMLIST_FILE}"
    ${SCRIPT_DIR}/ghettoVCB.sh -f ${SCRIPT_DIR}/${VMLIST_FILE}

    # Add Registered VM To The Exclusion List
    ignore_path=""
    num=`wc -l ${CURRENT_DIR}/getallvms.txt | awk '{print $1}'`
    i=0
    while read line
    do
        if [ $i -eq 0 ]
        then
            ignore_path="-type d ( -name $line "
        elif [ $i -eq `expr $num - 1` ]
        then
            ignore_path="${ignore_path} -o -name $line ) -prune -o "
        else
            ignore_path="${ignore_path} -o -name $line "
        fi
        i=`expr $i + 1`
    done < ${CURRENT_DIR}/getallvms.txt

    # Delete Unregistered VM
    logging "user.info" "delete unregisted vm folder : find ${VM_BACKUP_VOLUME} ${ignore_path} -type d -maxdepth 1 -mindepth 1 ${RETENTION_PERIOD_OPTION} -print | xargs rm -rf"
    find ${VM_BACKUP_VOLUME} ${ignore_path} -type d -maxdepth 1 -mindepth 1 ${RETENTION_PERIOD_OPTION} -print | xargs rm -rf

else
    logging "user.info" "No Such Directory : ${SCRIPT_DIR}"
fi

logging "user.info" "backup script terminated."

スクリプトの実行権限を付与することを忘れずに

[root@xh61v:~] chmod +x /vmfs/volumes/nfs_ds01/backup/esxi01/script/backupVM/backupVM.sh

4. 手動実行確認

スクリプトを手動で叩いて正常に動作するか確認します。

[root@xh61v:~] /vmfs/volumes/nfs_ds01/backup/esxi01/script/backupVM/backupVM.sh
2019-05-06 13:01:53 -- user.info: backup script started.
2019-05-06 13:01:53 -- info: vim-cmd vmsvc/getallvms | grep vmx | awk '{print }' > /vmfs/volumes/nfs_ds01/backup/esxi01/script/backupVM/getallvms.txt
2019-05-06 13:01:54 -- info: begin backup : /vmfs/volumes/nfs_ds01/backup/esxi01/script/ghettoVCB-master//ghettoVCB.sh -f /vmfs/volumes/nfs_ds01/backup/esxi01/script/ghettoVCB-master//vmlist.txt
Logging output to "/tmp/ghettoVCB-2019-05-06_13-01-54-2133818.log" ...
2019-05-06 13:01:54 -- info: ============================== ghettoVCB LOG START ==============================

2019-05-06 13:01:54 -- info: CONFIG - VERSION = 2019_01_06_4
2019-05-06 13:01:54 -- info: CONFIG - GHETTOVCB_PID = 2133818
2019-05-06 13:01:54 -- info: CONFIG - VM_BACKUP_VOLUME = /vmfs/volumes/nfs_ds01/backup/esxi01/files/
2019-05-06 13:01:54 -- info: CONFIG - ENABLE_NON_PERSISTENT_NFS = 0
2019-05-06 13:01:54 -- info: CONFIG - VM_BACKUP_ROTATION_COUNT = 2
2019-05-06 13:01:54 -- info: CONFIG - VM_BACKUP_DIR_NAMING_CONVENTION = 2019-05-06_13-01-54
2019-05-06 13:01:54 -- info: CONFIG - DISK_BACKUP_FORMAT = thin
2019-05-06 13:01:54 -- info: CONFIG - POWER_VM_DOWN_BEFORE_BACKUP = 0
2019-05-06 13:01:54 -- info: CONFIG - ENABLE_HARD_POWER_OFF = 0
2019-05-06 13:01:54 -- info: CONFIG - ITER_TO_WAIT_SHUTDOWN = 3
2019-05-06 13:01:54 -- info: CONFIG - POWER_DOWN_TIMEOUT = 5
2019-05-06 13:01:54 -- info: CONFIG - SNAPSHOT_TIMEOUT = 15
2019-05-06 13:01:54 -- info: CONFIG - LOG_LEVEL = info
2019-05-06 13:01:54 -- info: CONFIG - BACKUP_LOG_OUTPUT = /tmp/ghettoVCB-2019-05-06_13-01-54-2133818.log
2019-05-06 13:01:54 -- info: CONFIG - ENABLE_COMPRESSION = 0
2019-05-06 13:01:54 -- info: CONFIG - VM_SNAPSHOT_MEMORY = 0
2019-05-06 13:01:54 -- info: CONFIG - VM_SNAPSHOT_QUIESCE = 0
2019-05-06 13:01:54 -- info: CONFIG - ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP = 0
2019-05-06 13:01:54 -- info: CONFIG - VMDK_FILES_TO_BACKUP = all
2019-05-06 13:01:54 -- info: CONFIG - VM_SHUTDOWN_ORDER =
2019-05-06 13:01:54 -- info: CONFIG - VM_STARTUP_ORDER =
2019-05-06 13:01:54 -- info: CONFIG - RSYNC_LINK = 0
2019-05-06 13:01:54 -- info: CONFIG - BACKUP_FILES_CHMOD =
2019-05-06 13:01:54 -- info: CONFIG - EMAIL_LOG = 0
2019-05-06 13:01:54 -- info: CONFIG - ENABLE NFS IO HACK = 0

2019-05-06 13:01:56 -- info: Initiate backup for WinClient
2019-05-06 13:01:56 -- info: Creating Snapshot "ghettoVCB-snapshot-2019-05-06" for WinClient
Option --adaptertype is deprecated and hence will be ignored
Destination disk format: VMFS thin-provisioned
Cloning disk '/vmfs/volumes/xh61v_ds01/WinClient/WinClient-000003.vmdk'...
Clone: 17% done.
2019-05-06 13:05:26 -- info: Removing snapshot from WinClient ...
2019-05-06 13:05:27 -- info: Slept 1 seconds to work around NFS I/O error
2019-05-06 13:05:27 -- info: Backup Duration: 3.52 Minutes
2019-05-06 13:05:27 -- info: Successfully completed backup for WinClient!

2019-05-06 13:05:31 -- info: Initiate backup for foreman01
2019-05-06 13:05:31 -- info: Creating Snapshot "ghettoVCB-snapshot-2019-05-06" for foreman01
Option --adaptertype is deprecated and hence will be ignored
Destination disk format: VMFS thin-provisioned
Cloning disk '/vmfs/volumes/xh61v_ds01/foreman01/foreman01-000001.vmdk'...
Clone: 1% done.
2019-05-06 13:05:56 -- info: Removing snapshot from foreman01 ...
2019-05-06 13:05:57 -- info: Slept 1 seconds to work around NFS I/O error
2019-05-06 13:05:57 -- info: Backup Duration: 26 Seconds
2019-05-06 13:05:57 -- info: Successfully completed backup for foreman01!

2019-05-06 13:06:01 -- info: Initiate backup for ns01
Option --adaptertype is deprecated and hence will be ignored
Destination disk format: VMFS thin-provisioned
Cloning disk '/vmfs/volumes/xh61v_ds01/ns01/ns01.vmdk'...
Clone: 92% done.
2019-05-06 13:06:27 -- info: Slept 1 seconds to work around NFS I/O error
2019-05-06 13:06:27 -- info: Backup Duration: 26 Seconds
2019-05-06 13:06:27 -- info: Successfully completed backup for ns01!

2019-05-06 13:06:29 -- info: ###### Final status: All VMs backed up OK! ######

2019-05-06 13:06:29 -- info: ============================== ghettoVCB LOG END ================================

2019-05-06 13:06:29 -- user.info: delete unregisted vm folder : find /vmfs/volumes/nfs_ds01/backup/esxi01/files/ -type d ( -name foreman01  -o -name WinClient  -o -name ns01 ) -prune -o  -type d -maxdepth 1 -mindepth 1 -mtime +7 -print | xargs rm -rf
2019-05-06 13:06:29 -- user.info: backup script terminated.
[root@xh61v:~]

上記の例では3つのVMのバックアップを行いました。
バックアップ先のフォルダに仮想マシン名のフォルダができており、vmdk等が格納されていれば成功。

5. cron登録

cron設定は再起動すると消えるようなので、rc.local.dに書き込んで起動時に設定するようにします。
ちなみにUTCなので、日本の場合実行される時間は記入した時間の+9時間です。
私の場合は日中は仕事でいないので、日中帯にバックアップしています。

余談
cronの再起動処理っているんでしょうか?
VMWareのKBに従ってるようなので付けてますが、なくても動作するような。。。
 ⇒2019/06/25追記 cronを再起動しないと、変更が反映されませんでした。

[root@xh61v:~] vi /etc/rc.local.d/local.sh
#!/bin/sh

# local configuration options

# Note: modify at your own risk!  If you do/use anything in this
# script that is not part of a stable API (relying on files to be in
# specific places, specific tools, specific output, etc) there is a
# possibility you will end up with a broken system after patching or
# upgrading.  Changes are not supported unless under direction of
# VMware support.

# Note: This script will not be run when UEFI secure boot is enabled.

/bin/echo "* 3 * * * /bin/sh /vmfs/volumes/nfs_ds01/backup/esxi01/script/backupVM/backupVM.sh"  >> /var/spool/cron/crontabs/root
/bin/kill $(cat /var/run/crond.pid)
/bin/crond

exit 0

再起動すれば反映されますが、そのまま反映したい場合は、スクリプトを実行してください。
設定がうまくできていれば、/var/spool/cron/crontabs/rootにcron設定が反映されています。  ⇒2019/11/20追記 cronの時刻設定が誤ってましたので修正

[root@xh61v:~] cat /var/spool/cron/crontabs/root
#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
0 3 * * * /bin/sh /vmfs/volumes/nfs_ds01/backup/esxi01/script/backupVM/backupVM.sh