ディスクアクセスでsystemdサービスを終了する[バックアップ]

ディスクアクセスでsystemdサービスを終了する[バックアップ]

小さなバックアップスクリプト(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/crypttabsystemd()とsystemd()noautoの組み合わせを介してバックグラウンドで処理されます。これは、上記のユニットで参照できるsystemd-cryptsetup-generatorsystemdユニットファイルを自動的に生成します。systemd-cryptsetup@<name>.service

しかし、一度[unit]セクションに次の要件を追加したら:

[email protected]
[email protected]

システムのシャットダウン/停電中にサービスは開始されなくなりました。

サービスを手動で起動しても問題はないので、systemctl start poweroff-backup.serviceサービスファイル自体に問題はありません... :-/


考える問題は、poweroff.targetviaがすべてのデバイス(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

おすすめ記事