How to I gracefully shutdown my kvm virtual machines when shutting down the host?
Solution 1
Strange way for controlling VM. Good way -- use systemd for automatic start and stop VM. For example:
/etc/systemd/system/[email protected]
[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
... And, of course config(s) for run VM's:
/etc/conf.d/qemu.d/one
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"
...and another VM config:
/etc/conf.d/qemu.d/two
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"
Et cetera. Thanks ArchWiki contributors for this article.
Solution 2
The draft by the original post and @Oxyd's answer are useful when you need to control each Virtual Machines individually.
However if it's desired to shutdown/start all the VMs one could use the libvirt guests as mentioned on Libvirt docs.
- Edit the file
/etc/conf.d/libvirt-guests
, or/etc/sysconfig/libvirt-guests
for CentOS, then setON_SHUTDOWN=shutdown
andSHUTDOWN_TIMEOUT=0
- I think one also needs to activate the
libvirt-guests
service, for examplesystemctl enable libvirt-guests
andsystemctl start libvirt-guests
Related videos on Youtube
Domenico Onorato Datteri
Updated on September 18, 2022Comments
-
Domenico Onorato Datteri over 1 year
Bringing this question straight from here.
I am running archlinux and I have a VM running often on it along with the system. Most of the time actually.
My goal is to produce the following behaviour:
- A shutdown / poweroff / reboot / halt signal is sent to the system
- No action other then trying to shut down the virtual machines gracefully
- If the VMs are shut down gracefully after X seconds, proceeds with shutting down the host system too.
- If not, execute a different command
Just give me a good idea on what to work on, because I don't even know from where to begin. I guess there is a call to the kernel that can be looked at.
Let me know.
My current code
At the moment I am using these scripts to gracefully shutdown my kvm virtual machines, and it works! But only as long as my user launches a shutdown or a reboot using his shell. Any other case wouldn't work.
These alias:
alias sudocheck="/bin/bash /home/damiano/.script/sudocheck" alias sudo="sudocheck "
Are triggering this function:
#!/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 $@
That launches this script if needed:
#!/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 Unit
I also made the following draft, to manage the execution of my VM:
[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
But how can I tell the system to don't shut down the desktop environment, to stay as it is UNTIL the VM has been successfully shut down? Because if the system can't shut down the vm, I want to do it while still in my DE. I don't want the computer to begin stopping all the services and remain hung until it just forces the shut down.
-
ajgringo619 about 4 yearsDoes running
virsh shutdown domainname
from the host do what you need? -
Domenico Onorato Datteri about 4 yearsNo, it just shuts down my virtual machine. I want to script a graceful shutdown for the entire system. So that all the vm's get shut down along with the host.
-
MUY Belgium over 3 yearsMay be using the full path of
virsh
is more secure.
-
Stefan Skoglund about 4 yearsThe virtual machine ? do you use something cfengine, puppet or chef to manage it ? Could you have something in policy which if something is true for the host propagates a shutdown action to the virtual machines ? In the case of cfengine : the hub can initiate a policy check with special variables set -> special variable set ? create a marker file and at end of policy shutdown the VM.
-
Domenico Onorato Datteri about 4 yearsHello Stefan, thanks for your comment. No I just use virt-manager and virsh