web-dev-qa-db-ja.com

systemdはどのようにしてVirtualBoxゲストを自動起動および制御できますか?

私の特定のケースでは、Ubuntu 18.04 BionicとVirtualBox-5.2.20の新しいサーバーインストールにより、ゲストを自動起動する古い方法が利用できなくなったようです。それはそれほど素晴らしいことではありませんでしたが、機能しました。これを実行するためのクリーンな方法はないようです-systemdとVirtualBoxはどのように機能しますかtogetherインテリジェントな起動、制御、およびシャットダウンのために?

2
Daniel Miller

ええと...私は答えを思いついたと思います。

これが私の解決策です。それは確かに完璧ではありません-そして私が共有している理由の一部は改善を招待することです。ただし、systemdを介して自動起動、監視、シャットダウンを行うことができます。そして、私は考えるこれは少なくともこれら2つの製品にとって正しい方向に進んでいます。

注意点の1つ-以下は、systemdとVirtualBoxの両方に少し慣れていることを前提としています。また、ゲストでACPIシャットダウン機能を有効にする必要があります。これはWindowsに組み込まれている可能性があり、Linuxにacpidをインストールするのと同じくらい簡単ですが、私は想定していません。また、一部のゲスト(Windowsバージョンxxxx)は、ACPIシャットダウンがすぐに実行されるように「調整」を必要とする場合があります- https://ethertubes.com/unattended-acpi-shutdown-of-windows-serverで素晴らしいリソースを見つけました/

まず、もちろんsystemdユニットを作成する必要があります。 テンプレートの可用性を活用しています。

systemctl edit --full [email protected]を実行すると、エディターが配置されます。[Unit] Description = VirtualBox%I Virtual Server After = network.target vboxdrv.service

[Service]
Type=forking
Restart=no
TimeoutSec=5min
KillMode=process
RuntimeDirectory=vbox
RuntimeDirectoryPreserve=yes
PIDFile=/run/vbox/%I.pid

Environment='RUNDIR=/run'
Environment='PIDDIR=/vbox'
Environment='VM=%I'
ExecStart=/etc/init.d/vbox-systemd start
ExecStop=/etc/init.d/vbox-systemd stop

[Install]
WantedBy=multi-user.target

上記は基礎を提供します:

- Allows for up to 5 minutes for startup/shutdown per guest
- The pid files will be stored as /run/vbox/<guest>.pid
- And the guests will be started as part of the normal boot process

これは好みに合わせて調整できますが、サーバー全体のデフォルトは別として、そのままにしておきます。個々のゲストは後で調整されます。今-ヘルパースクリプトを提供する必要があります。私は、BASHの複雑さ、睡眠不足、およびBASHのアクティブな経験の深刻な欠如と戦うために長期間過ごしました。したがって、次の作品では、スタイルの混合があり、単純なBASH関数での私の試みがそれほど惨めに失敗した理由を本当に知りたいと思います。しかし、私はベッドの準備ができているので、それは私の最高の仕事ではありませんが...それはうまくいきます!:

#! /bin/bash
# /etc/init.d/vbox-systemd: Helper script to startup & shutdown VirtualBox
# headless machines via systemd
#
# written by Daniel L. Miller <[email protected]>

# This should not be called directly (though possible with the
# proper environment variables set). This is used by the
# [email protected] template to start & stop virtual machines - 
# with supervision.

# Environment variables to be defined for us by systemd unit
# RUNDIR=/run
# PIDDIR=/vbox
# VM=<vmname>

# This was setup to use environment variables - maybe support cmd line as well.
if [ ! -z "$2" ]; then
    VM=$2
fi

# So...I suppose might as well set sane defaults
if [ -z "$RUNDIR" ]; then
    RUNDIR='/run'
fi
if [ -z "$PIDDIR" ]; then
    PIDDIR='/vbox'
fi

#
# Overprotective but trying to be good...
# These utilities should be fairly standard...
#
VB=/usr/bin/VBoxManage
GREP=/bin/grep
CUT=/usr/bin/cut
TR=/usr/bin/tr
SLEEP=/bin/sleep
WAITEXIT=300

# Make sure the utilities are available
test -x $VB || exit 3
test -x $GREP || exit 3
test -x $CUT || exit 3
test -x $TR || exit 3

# Verify the pid folder tree is defined and usable
test -d "${RUNDIR:?run directory top-level must be set}" || exit 3
test -d "$RUNDIR${PIDDIR:?pid directory must be set}" || mkdir -p "$RUNDIR$PIDDIR"
# This test is a little different - this validates the name but we don't
# care if the file exists or not. At least the moment.
test -f "$RUNDIR$PIDDIR/${VM:?Virtual Machine name must be set}.pid"

PIDFILE=$RUNDIR$PIDDIR/$VM.pid

vmactive=$($VB list runningvms | grep $VM | cut -d ' ' -f 1 | tr -d '"')

case "${1:-''}" in
  'start')
    # Start the machine
    $VB startvm $VM --type headless
    # Give it at least a change to get started...
    $SLEEP 2
    # Now perform first trick and save pid
    vmactive=`$VB list runningvms | grep $VM | cut -d ' ' -f 1 | tr -d '"'`
    if [ "x$vmactive" == "x$VM" ]; then
        vmpid=$($VB showvminfo $VM --log 0 | $GREP -m 1 'Process ID' | $CUT -d ':' -f4 | $TR -d ' ')
        echo $vmpid > $PIDFILE
    else
        exit 1;
    fi
    ;;
  'stop')
    waited=0
    while [ "$waited" -lt $WAITEXIT ]; do
        # Test first so VB doesn't object to shutting off a non-running VM
        vmactive=`$VB list runningvms | grep $VM | cut -d ' ' -f 1 | tr -d '"'`
        if [ "x$vmactive" != "x$VM" ]; then
            echo "Proper ACPI Shutdown of $VM - or it wasn't running!"
            break
        fi
        # Try to turn it off - repeatedly
        $VB controlvm $VM acpipowerbutton
        # Give it a chance to take.
        $SLEEP 5
        waited=$((waited+5))
    done

    # Time to clean up - force terminate if necessary and delete the pid file
    [ "$waited" -ge $WAITEXIT ] && [ -f $PIDFILE ] && kill -s 9 $PIDFILE
    [ -f $PIDFILE ] && rm $PIDFILE
    ;;
  'status')
    vmactive=`$VB list runningvms | grep $VM | cut -d ' ' -f 1 | tr -d '"'`
    if [ "x$vmactive" == "x$VM" ]; then
        vmpid=$($VB showvminfo $VM --log 0 | $GREP -m 1 'Process ID' | $CUT -d ':' -f4 | $TR -d ' ')
        echo "$VM is running as PID $vmpid"
    else
        echo "$VM is not running"
    fi
    ;;
  *)
    echo "Usage: vbox-systemd [start|stop|status]" >&2
    exit 3;
    ;;
esac

したがって、仮想マシンを起動するために必要なのは、systemctl start vbox@<your-guest-name>だけです。さらにエキサイティング-systemctl status vbox@<your-guest-name>はVMのsystemdステータスを提供します!また、systemctl stop vbox@<your-guest-name>を実行してオフにすることもできます。

自動起動を有効にするには、systemctl enable vbox@<your-guest-name>を実行します。

ここで、ゲストが起動するorderを指定するなどの追加の制御が必要な場合は、トリッキーなsystemctl edit vbox@<your-guest-name>を使用します。今回は--full引数を使用していないことに注意してください。これにより、ベースユニットを複製せずに、このゲスト用のオーバーライドフォルダーが作成されます。多分このゲストはホストからのSQLサービスを必要とします:

[Unit]
After=mysql.service
Wants=mysql.service

これで、このゲストはmysqlサーバーが起動するまで開始されません。または、このゲストが重要なサービスを提供する場合は、追加できます:

[Services]
Restart=yes

追加またはオーバーライドする必要があるsystemd引数を入力するだけです。残りはテンプレートから取得します。

これが他の誰かの助けになることを願っています-そして他の人が貢献できるなら、ぜひしてください!

1
Daniel Miller

あなたの解決策に似ていますが、少し簡単です:

  1. systemctl edit [email protected] --full --forceを実行し、次のコンテンツを貼り付けて、ユーザーとグループをユーザー名に更新します。
Description=Virtual Box Guest %I
After=network.target vboxdrv.service
Before=runlevel2.target shutdown.target

[Service]
User=USERNAME
Group=GROUPNAME
Type=forking
Restart=no
TimeoutSec=5min
IgnoreSIGPIPE=no
KillMode=process
GuessMainPID=no
RemainAfterExit=yes

ExecStart=/usr/bin/VBoxManage startvm %i --type headless
ExecStop=/usr/bin/VBoxManage controlvm %i acpipowerbutton

[Install]
WantedBy=multi-user.target
  1. Systemdを再読み込みします:systemctl daemon-reload

  2. VMのリストを取得するVBoxManage list vms

$ VBoxManage list vms
"Ubuntu" {1ba32309-d4c4-420a-a9c8-a38177f00bc4}
"Windows" {573df054-0e33-4389-896a-1245e09d15ad}
  1. 手順3で返された名前を使用して、systemdでVMを管理します。たとえば、「Ubuntu」を管理するにはVMを実行します。
Sudo systemctl start vbox@Ubuntu     # Start the VM
Sudo systemctl enable vbox@Ubuntu    # Start the VM on boot
0
HeWhoWas