小さなバックアップスクリプト(btrfsスナップショット+ USBに転送)システムがシャットダウンしたとき。
次のサービスは終了時に完全に機能しますが、再起動すると期待どおりに機能しません。
[Unit]
Description=Backup on poweroff to external encrypted USB disk.
DefaultDependencies=no
Before=shutdown.target
[Service]
Type=oneshot
ExecStart=/usr/bin/sleep 30
TimeoutSec=infinity
RemainAfterExit=yes
[Install]
WantedBy=poweroff.target
サービスが期待どおりに機能すると、/usr/bin/sleep 30
実際のバックアップスクリプトに置き換えられます。
ただし、バックアップスクリプトが機能するには、起動する前にcryptsetupを使用して外部USBディスクの復号化が必要です。これらの操作はすべて、/etc/crypttab
systemd()とsystemd()noauto
の組み合わせを介してバックグラウンドで処理されます。これは、上記のユニットで参照できるsystemd-cryptsetup-generator
systemdユニットファイルを自動的に生成します。systemd-cryptsetup@<name>.service
しかし、一度[unit]セクションに次の要件を追加したら:
[email protected]
[email protected]
システムのシャットダウン/停電中にサービスは開始されなくなりました。
サービスを手動で起動しても問題はないので、systemctl start poweroff-backup.service
サービスファイル自体に問題はありません... :-/
私考える問題は、poweroff.target
viaがすべてのデバイス(cryptsetupを含む)を順番に削除するsystemd-poweroff.service
必要があることです。umount.target
山')を組み合わせて紛争=そして以降 =systemd マウントおよび cryptsetup デバイスの説明です。ただし、他の要件を追加しても、umount.target
次の内容は変更されません。
Before=umount.target
umount.target
追加の要件がなくても、サービスが常に到着するとすぐに開始されることを確認できます。
答え1
さて、私はまだsystemdワークフローに従う適切に動作するソリューションを構築することができるこの質問を見つけました。ほとんどの場合)。
質問
次のサービスは一見すると正確ですが、実行されません。
# poweroff-backup.service
[Unit]
Description=Backup on poweroff to external encrypted USB disk.
DefaultDependencies=no
Before=shutdown.target
# This causes the service to be discarded/skipped due to
# a dependency cycle conflict. See below...
[email protected]
[email protected]
Before=umount.target
[Service]
Type=oneshot
# Note: The script executed here needs access to '/', '/tmp'
# (or Systemd's PrivateTemp) and '/dev/mapper/ext' which is the
# decrypted USB partition managed by /etc/crypttab and
# systemd-cryptsetup-generator (as [email protected])
ExecStart=/usr/bin/sleep 30
TimeoutSec=infinity
# Note: This does not make any difference
RemainAfterExit=yes
[Install]
WantedBy=poweroff.target
サービスが開始されないのは、シャットダウン(電源オフ/再起動)と電源オフ - バックアップの前に暗号化されたすべてのディスクが切断されるようにするために、shutdown.targetとcryptsetup.targetの間に依存ループの問題/衝突があるためです。 poweroff.target経由。poweroff.target -[require]-> shutdown.target -[conflicts]-> cryptsetup.target <-[require]- [email protected] <-[require]- poweroff-backup.service <-[wants]- poweroff.target
解決策
これを知ると、明らかな問題はsystemdがpoweroff-backup.serviceが」ワンタイムストライク"poweroff-backup.serviceが有効になって非アクティブ/完了に切り替えられると、システムは通常のシャットダウン切り替えを続行しながらサービスを最初に解決できます。
以下は、ExecStart=の代わりにExecStop=を使用するサービスです。これにより、依存関係のサイクルを回避できますが、いくつかのマイナーな注意があります。
# poweroff-backup.service
[Unit]
Description=Backup external encrypted USB disk on poweroff.
[email protected]
After=multi-user.target
[email protected]
[Service]
Type=oneshot
ExecStart=/usr/bin/echo "Waiting for poweroff..."
# Note: We need this, since there is no other way to detect poweroff vs reboot now.
ExecStop=/usr/bin/systemctl list-jobs | /usr/bin/egrep -q 'poweroff.target.*start'
# Note: This should be replaced with your script
ExecStart=/usr/bin/sleep 30
TimeoutSec=infinity
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
これは次の理由で機能します。
- shutdown.target、cryptsetup.target、およびpoweroff-backup.serviceによる依存関係サイクルの問題の回避
- systemdは終了順序が開始順序と反対であることを保証するため、正しい作業順序は維持されます(After =およびBefore =で提供されています)。
このソリューションには2つのマイナーな苦情があります。
サービスはログイン時に開始されるため、ログイン時に外部USBディスクのパスワードも復号されます。私は通常のシステムのAfter =とRequire =の順序付けと依存関係のメカニズムを使い続けながら、実際のバックアップスクリプトが実行されたときにのみこれが起こりたいと思います。これは以下を追加して処理できますが、これはUSBディスクを復号化/分離するためにcryptsetupサービスを使用しないことを意味します。
ExecStop=/usr/lib/systemd/systemd-cryptsetup attach ext [...] ExecStop=/usr/lib/systemd/systemd-cryptsetup detach ext
shutdown.targetを参照して、終了時にのみExecStop =を条件付きで実行する方法はなく、使用されているいくつかのヘルパーコマンドに依存する必要があります
systemctl list-jobs
。
質問:これらの点を改善する方法を知っている人はいますか?
完全なサービス文書
これは現在のサービスファイルです。 USBディスクをマウントした後にのみ、multi-user.targetの代わりにUSBデバイス(UUID経由)に接続(WantedBy =)してサービスを開始します。
# poweroff-backup.service
[Unit]
Description=Backup external encrypted USB disk on poweroff.
[email protected]
Requires=-.mount
Requires=tmp.mount
After=dev-disk-by\<uuid here>.device
[email protected]
After=-.mount
After=tmp.mount
[Service]
Type=oneshot
ExecStart=/usr/bin/echo "Waiting for poweroff to trigger snapshot and archive transfer..."
ExecStop=/usr/bin/systemctl list-jobs | /usr/bin/egrep -q 'poweroff.target.*start'
ExecStop=-/usr/local/bin/btrfs-snapshots.sh --device='UUID=<uuid>' @ @boot @home
ExecStop=/usr/local/bin/btrfs-archive.sh --source='UUID=<uuid>' --target=/dev/mapper/ext
TimeoutSec=infinity
RemainAfterExit=true
[Install]
WantedBy=dev-disk-by\<uuid here>.device
答え2
私のユースケースは少し異なります。他のすべてのサービスが停止していることを確認し、再起動中にRsyncを使用してバックアップを実行したいと思います。以下はUbuntu 22.04で私に効果的でした。後で終了時にスクリプトを実行したい人のために、この答えをここに残してください。
サービスファイルは次のとおりです。
[Unit]
Description=Run my custom task at shutdown
DefaultDependencies=no
Before=systemd-reboot.service
After=final.target
[Service]
Type=oneshot
ExecStart=/usr/local/scripts/custom_script.sh
TimeoutStartSec=0
[Install]
WantedBy=systemd-reboot.service
私はどのようにcustom_script.sh
見えますか?
#!/bin/sh
ps aux > /usr/local/scripts/processes.txt
df -Th > /usr/local/scripts/df.txt
mount > /usr/local/scripts/mount.txt
sleep 180
sudo chmod 777 -R /usr/local/scripts/
これは単にテスト用なので、権限の問題がある場合に備えて実行しています。
私がテストしたステップは次のとおりです。
- 終了して再起動したときにスクリプトを実行するには、
sleep 180
次の手順を実行しますcustom_script.sh
。その後、オペレーティングシステムをシャットダウンします。わずか3分後、オペレーティングシステムは完全にシャットダウンします。スクリプトの実行中(待機中)Ubuntuロードロゴが表示されます。システムを起動して再起動しました。同じUbuntuロードロゴが表示され、3分後にシステムが再起動します。これは、終了/再起動時にスクリプトが実行されていることを証明します。 custom_script.sh
他のすべてのサービスが停止していることを確認してください。実行中に実行されていたすべてのプロセスを記録しましたps aux > processes.txt
。の出力にはprocesses.txt
他のサービスは含まれません。これは、他のすべてのサービスが停止したことを証明します。- ファイルシステムがまだマウントされていることを確認するために、
df -Th > df.txt
mountを使用して記録しますmount > mount.txt
。ファイル出力には、すべてのパーティションがマウントされ、読み取り/書き込みモードになっていることが示されます。