systemdのユニットの起動を遅延させる(systemd.timerを使う)

背景

Ubuntuで起動時にTailscaleネットワーク上のNFSサーバーのディレクトリーをマウントしたかったけど、起動直後だとTailscaleのMagicDNS?がうまく動かなくてマウント失敗していた。

解決法

systemdのtimerを使って、雑に起動後30秒経ってからsystemdのunitを実行するようにした。以下は適当なserviceを遅延実行させる例。

まず適当なサービスのunitを作る。timerから実行するので[Install]WantedByは必要ない。

cat << EOF | sudo tee /etc/systemd/system/test.service
[Unit]
Description=test service

[Service]
ExecStart=/usr/bin/echo service started
EOF

次に上記のunitを起動後30秒後に実行するtimerのunitを作る。

cat << EOF | sudo tee /etc/systemd/system/test.timer
[Unit]
Description=test service trigger

[Timer]
OnBootSec=30
Unit=test.service

[Install]
WantedBy=timers.target
EOF

timerを有効にする。

sudo systemctl daemon-reload
sudo systemctl enable test.timer

これで起動後30秒したらtest.serviceが自動実行されるようになる。以下が確認方法。

sudo reboot

# -- 再起動後 --

sudo systemctl status test.timer
# 実行結果:
# ● test.timer - test service trigger
#      Loaded: loaded (/etc/systemd/system/test.timer; enabled; vendor preset: enabled)
#      Active: active (elapsed) since Sat 2024-03-30 16:43:07 JST; 26min ago
#     Trigger: n/a
#    Triggers: ● test.service

sudo systemctl status test.service
# ○ test.service - test service
#      Loaded: loaded (/etc/systemd/system/test.service; static)
#      Active: inactive (dead) since Sat 2024-03-30 16:43:37 JST; 27min ago
# TriggeredBy: ● test.timer
#     Process: 2018 ExecStart=/usr/bin/echo service started (code=exited, status=0/SUCCESS)
#    Main PID: 2018 (code=exited, status=0/SUCCESS)
#         CPU: 1ms
# 
# Mar 30 16:43:37 systemd[1]: Started test service.
# Mar 30 16:43:37 echo[2018]: service started
# Mar 30 16:43:37 systemd[1]: test.service: Deactivated successfully.

参考: systemd.timer

付録 Tailscaleネットワーク上のNFSマウントの場合

駄目だったパターン

# /etc/systemd/system/nfs-aaa.mount

[Unit]
Description=mount nfs
After=network-online.target tailscaled.service
Wants=network-online.target tailscaled.service

[Mount]
What=aaa.bbb-ccc.ts.net:/dir
Where=/nfs/aaa
Type=nfs
Options=

[Install]
WantedBy=multi-user.target

tailscaled.serviceの後に実行すればいけるかなと思ったけど、以下のようにMagicDNSのドメイン名が解決できなくて失敗していた。ドメイン名ではなくTailscaleネットワークのIPアドレスにしても駄目だった。

systemd[1]: Mounting Mount NFS shares...
mount[1093]: mount.nfs: Failed to resolve server aaa.bbb-ccc.ts.net: Name or service not known
systemd[1]: nfs-aaa.mount: Mount process exited, code=exited, status=32/n/a
systemd[1]: nfs-aaa.mount: Failed with result 'exit-code'.
systemd[1]: Failed to mount Mount NFS shares.

うまく行ったパターン

以下のような感じのユニットファイルを用意して、

# /etc/systemd/system/nfs-aaa.mount

[Unit]
Description=mount nfs

[Mount]
What=aaa.bbb-ccc.ts.net:/dir
Where=/nfs/aaa
Type=nfs
Options=
# /etc/systemd/system/nfs-aaa.timer

[Unit]
Description=mount nfs trigger

[Timer]
OnBootSec=30
Unit=nfs-aaa.mount

[Install]
WantedBy=timers.target

timerを有効にしてやれば、上手くいくようになった。

sudo systemctl daemon-reload
sudo systemctl enable nfs-aaa.timer

以上です。