我有一個 systemd 服務來執行由 systemd 計時器啟動的監視 bash 腳本。我用過Type=oneshot
看起來最適合的。然而,有時腳本需要呼叫另一個程序,這恰好會fork。一旦完成,腳本就會完成並退出,但是一旦腳本退出,systemd 將殺死所有剩餘的子進程。
我可以用來KillMode=process
防止這種情況,但存在這樣的風險:在腳本的其他路徑中,其他進程(不分叉)可能會在退出後繼續運行。
處理這個問題的最佳方法是什麼?
順便說一句,分叉程序是 dhcpcd,但我認為這個問題普遍適用。 dhcpcd 最初是由 ifplugd 啟動的,此腳本是一個故障保護腳本,以防系統最終處於 dhcpcd 不再運行的狀態。
答案1
進程被殺死是因為它們屬於與服務關聯的控制組(cgroup),例如這裡(對於系統服務):
/sys/fs/cgroup/systemd/system.slice/your-service.service
要將進程移出 cgroup,將其分配給另一個cgroup。 「父cgroup」似乎是對的。對於系統服務來說是這樣的:
echo <PID> > /sys/fs/cgroup/systemd/system.slice/tasks
# or even to the general systemd cgroup
echo <PID> > /sys/fs/cgroup/systemd/tasks
若要從一開始就執行此 cgroup 中的某些命令,請執行一個將自身指派給該 cgroup 的 shell,然後exec
執行實際命令:
sh -c 'echo "$$" > /sys/fs/cgroup/systemd/tasks; exec /the/forking/program'
/the/forking/program
將會取代已經在新 cgroup 中的 shell。當它分叉時,分叉的實例將發現自己位於新的 cgroup 中。當主腳本退出時,systemd 將殺死與該服務關聯的 cgroup 中的進程,但有問題的程式不會在其中。
也許有更合適的方法來解決您的問題,使用單元文件或其他東西。但我不知道。