Linux

ExecStart 中的腳本退出時執行 ExecStop

  • May 17, 2021

我對 systemd 服務的行為有點困惑。我有上述系統服務。

[Unit]
After=libvirtd.service

[Service]
Type=simple
Environment=VM_XML=xxxxxxx
ExecStartPre=/usr/bin/bash /usr/local/lib/common/createQcowImage.sh ${VM_XML}
ExecStart=/usr/bin/bash /usr/local/lib/common/createVM.sh ${VM_XML}
ExecStop=/usr/bin/bash /usr/local/lib/common/destroyVM.sh ${VM_XML}
Restart=always

[Install]
WantedBy=multi-user.target

當這個單元在 createVM.sh 腳本中啟動時,它會創建一個 VM 並監控它的狀態。如果 VM 的 PID 不再存在,則腳本以返回碼 1 退出。我注意到,當發生這種情況時,ExecStop 被執行(我正在管理 /var/log/messages,當我手動銷毀 VM 時)使用 virsh destroy 我在從 ExecStop 執行的腳本中播下用於調試的迴聲,以列印在 /var/log/messages 中)。這是 systemd 的預設行為嗎?在單元退出時執行 ExecStop(我也嘗試使用程式碼 0 退出,這是相同的行為)。這不是我真正想做的,因為在我銷毀 VM 後,ExecStop 會嘗試銷毀導致 systemd 單元故障的同一 VM。有沒有辦法避免這種情況?

如果您想創建一個按預期執行的 systemd 服務配置,您需要充分了解所有選項的含義。

我建議您開始閱讀man systemd.service有關Type=, ExecStart=, ExecStop=. 也許Type=exec,或者Type=oneshot更適合您的腳本?

您描述的行為在我看來確實符合預期。

要處理您的 VM 已被其使用者停止的情況,您需要測試它是否仍在執行,如果沒有則避免​​破壞它。也不要忘記 ExecStop 必須等待機器停止,而不僅僅是要求它停止。

我附上了我用來啟動 VirtualBox VM 的使用者服務,也許你可以在那裡找到一些靈感。

[Unit]
Description=Virtual Machine as a headless service.
After=network.target virtualbox.target
Before=runlevel2.target shutdown.target

[Service]
Type=simple
Restart=no
Environment=VMNAME=my-vbox-vm
Environment=TIMEOUT=60
#ExecStartPre=VBoxManage snapshot $VMNAME take "before service start"
ExecStart=VBoxHeadless --startvm $VMNAME
# Sleep might be needed if there is some ExecStartPost later, to make sure that the VM was really powered up
#ExecStartPost=sleep 1
# sometimes it happens that the machine is paused from some reason
#ExecStartPost=bash -c "VBoxManage showvminfo $VMNAME | grep -E ^State:\\\\s+paused && VBoxManage controlvm $VMNAME resume || exit 0"
# If the VM uses the VirtualBox hdd encryption, so a line like below is needed to unlock the drive
#ExecStartPost=VBoxManage controlvm $VMNAME addencpassword $VMNAME "/home/user/VirtualBox VMs/my-vbxo-vm/my-vbox-vm.vmdk.pass"
# The 'savestate' is the only reliable way to turn off the machine.
# Optionally sending acpishutdown, can be considered, but better that needs to use the savestate as a fallback anyway,
# because the acpishutdown can be from various reasons ignored by the VM or delayed significantly.
#
# Alternatives for ExecStop
# - save state
#   (should be reliable but not really turning off the VM;
#    exit 0 necessary to handle the situation that VM was turned off already,
#    from inside)
#   ExecStop=bash -c "VBoxManage controlvm $VMNAME savestate || exit 0"
# - stop vm using acpi, with active waiting
#   (not reliable - if acpi signal ignored by VM, or shutdown takes too long,
#    systemd will just kill it after some timeout, (normally 90s);
#    note that the active waiting is necessary,
#    otherwise systemd might kill the process before shutdown is finished)
#   ExecStop=bash -c "VBoxManage controlvm $VMNAME acpipowerbutton && while (VBoxManage list runningvms | grep $VMNAME); do sleep 1; done"
# - stop vm using acpi or, after a timeout, with save state
#   (timeout let's say max 60s, to keep 30s for possible savestate;
#    exit 0 necessary in order not to have the service in error state when stopped already by acpi, or maybe even by user from inside of VM)
ExecStop=bash -c "VBoxManage controlvm $VMNAME acpipowerbutton && (let timeout=$TIMEOUT; while VBoxManage list runningvms | grep --silent $VMNAME && test $timeout -gt 0; do sleep 1; let timeout=$timeout-1; done) && VBoxManage list runningvms | grep --silent $VMNAME && VBoxManage controlvm $VMNAME savestate || exit 0"

[Install]
WantedBy=default.target

引用自:https://serverfault.com/questions/1061283