Wie fahre ich meine virtuellen KVM-Maschinen beim Herunterfahren des Hosts ordnungsgemäß herunter?

Wie fahre ich meine virtuellen KVM-Maschinen beim Herunterfahren des Hosts ordnungsgemäß herunter?

Diese Frage klarstellenvon hier.

Ich verwende Archlinux und habe neben dem System oft auch eine VM darauf laufen. Eigentlich die meiste Zeit.

Mein Ziel ist es, folgendes Verhalten zu erzeugen:

  • Ein Shutdown- / Poweroff- / Reboot- / Halt-Signal wird an das System gesendet
  • Keine Aktion außer dem Versuch, die virtuellen Maschinen ordnungsgemäß herunterzufahren.
  • Wenn die VMs nach X Sekunden ordnungsgemäß heruntergefahren werden, wird auch mit dem Herunterfahren des Hostsystems fortgefahren.
  • Wenn nicht, führen Sie einen anderen Befehl aus

Geben Sie mir einfach eine gute Idee, woran ich arbeiten soll, denn ich weiß nicht einmal, wo ich anfangen soll. Ich vermute, es gibt einen Aufruf an den Kernel, der angeschaut werden kann.

Lass es mich wissen.


Mein aktueller Code

Im Moment verwende ich diese Skripte, um meine virtuellen KVM-Maschinen ordnungsgemäß herunterzufahren, und es funktioniert! Aber nur, solange mein Benutzer einenabschaltenoder einNeustartmit seiner Shell. In jedem anderen Fall würde es nicht funktionieren.

Dieser Alias:

alias sudocheck="/bin/bash /home/damiano/.script/sudocheck"
alias sudo="sudocheck "

Lösen diese Funktion aus:

#!/bin/bash

# This script checks for what is being passed to sudo.
# If the command passed is poweroff or reboot, it
# launches a custom script instead, that also looks
# fur currently running virtual machines and shuts them.

sudocheck() {
    if [ $1 == "poweroff" ] || [ $1 == "reboot" ]; then
        eval "sudo /home/damiano/.script/graceful $@"
    else
        eval "sudo $@"
    fi
}
sudocheck $@

Dadurch wird bei Bedarf dieses Skript gestartet:

#!/bin/bash
i=0
e=0
## if virsh finds VMs running
virsh -c qemu:///system list | awk '{ print $3}' | \
if grep running > /dev/null ; then
    virsh -c qemu:///system list --all | grep running | awk '{print "-c qemu:///system shutdown "$2}' | \
## shuts them dow gracefully
    xargs -L1 virsh
## wait 30 seconds for them to go down
    until (( i >= 30 || e == 1 )) ; do
## check every second for their status
        virsh -c qemu:///system list --all | awk '{ print $3}' | \
        if grep -E '(running|shutdown)' > /dev/null ; then
## keep waiting if still running
            if (( i <= 30 )) ; then
                sleep 1 && let i++ && echo $i
            else
                e=1 && notify-send 'Shutdown has been canceled' 'Please check the status of your virtual machines: seems like even though a stop signal has been sent, some are still running.' --urgency=critical
            fi
        else
## if no machine is running anymore, original power command can be executed
            e=1 && eval $@
        fi
    done
fi

Systemd-Einheit

Um die Ausführung meiner VM zu verwalten, habe ich außerdem den folgenden Entwurf erstellt:

[email geschützt]

[Unit]
Description=This service manages the execution of the %i virtual machine
Documentation=https://libvirt.org/manpages/virsh.html

[Service]
ExecStartPre=virsh -c qemu:///system
ExecStart=virsh start %i
ExecStop=virsh -c qemu:///system
ExecStop=virsh shutdown %i 
TimeoutStopSec=30
KillMode=none

[Install]
WantedBy=multi-user.target

Aber wie kann ich dem System sagen, dass es die Desktop-Umgebung nicht herunterfahren soll, sondern so bleiben soll, wie sie ist?BISdie VM wurde erfolgreich heruntergefahren? Denn wenn das System die VM nicht herunterfahren kann, möchte ich dies tun, während ich mich noch in meiner DE befinde. Ich möchte nicht, dass der Computer beginnt, alle Dienste zu stoppen und hängen bleibt, bis er einfach das Herunterfahren erzwingt.

Antwort1

Seltsame Methode zur Steuerung einer VM. Gute Methode: Verwenden Sie systemd zum automatischen Starten und Stoppen einer VM. Beispiel:

/etc/systemd/system/[email geschützt]

[Unit]
Description=QEMU virtual machine

[Service]
Environment="type=system-x86_64" "haltcmd=kill -INT $MAINPID"
EnvironmentFile=/etc/conf.d/qemu.d/%i
ExecStart=/usr/bin/qemu-${type} -name %i -nographic $args
ExecStop=/bin/sh -c ${haltcmd}
TimeoutStopSec=30
KillMode=none

[Install]
WantedBy=multi-user.target

... Und natürlich Konfiguration(en) zum Ausführen von VMs:

/etc/conf.d/qemu.d/eins

type="system-x86_64"

args="-enable-kvm -m 512 -hda /dev/vg0/vm1 -net nic,macaddr=DE:AD:BE:EF:E0:00 \
 -net tap,ifname=tap0 -serial telnet:localhost:7000,server,nowait,nodelay \
 -monitor telnet:localhost:7100,server,nowait,nodelay -vnc :0"

haltcmd="echo 'system_powerdown' | nc localhost 7100" # or netcat/ncat

# You can use other ways to shut down your VM correctly
#haltcmd="ssh powermanager@vm1 sudo poweroff"

... und eine andere VM-Konfiguration:

/etc/conf.d/qemu.d/zwei

args="-enable-kvm -m 512 -hda /srv/kvm/vm2.img -net nic,macaddr=DE:AD:BE:EF:E0:01 \
 -net tap,ifname=tap1 -serial telnet:localhost:7001,server,nowait,nodelay \
 -monitor telnet:localhost:7101,server,nowait,nodelay -vnc :1"

haltcmd="echo 'system_powerdown' | nc localhost 7101"

Und so weiter. Danke an die ArchWiki-Mitwirkendenfür diesen Artikel.

Antwort2

Der Entwurf des Originalbeitrags und die Antwort von @Oxyd sind nützlich, wenn Sie jede virtuelle Maschine einzeln steuern müssen.

Wenn jedoch das Herunterfahren/Starten gewünscht wirdalle VMsman könnte die libvirt-Gäste verwenden, wie erwähnt aufLibvirt-Dokumente.

  • Bearbeiten Sie die Datei /etc/conf.d/libvirt-guestsoder /etc/sysconfig/libvirt-guestsfür CentOS, dann setzen ON_SHUTDOWN=shutdownundSHUTDOWN_TIMEOUT=0
  • Ich denke, man muss den Dienst auch aktivieren libvirt-guests, zum Beispiel systemctl enable libvirt-guestsundsystemctl start libvirt-guests

verwandte Informationen