systemd で crontab を置き換えるための最低限の設定の書き方を紹介したいと思います。 今回はまず crontab での @reboot (起動時に1回だけ実行される) 相当の処理をできるようにしたいと思います。

確認環境

  • Ubuntu 18.04 LTS

最小限の unit ファイル例

sudoedit /etc/systemd/system/hello.service などで作成します。

ini ファイル形式で、 最低限の設定は [Service] セクションに書きます。

[Service]
Type=oneshot
ExecStart=/bin/echo hello

Type のデフォルトは simple でデーモンを想定しているので、 すぐに終了するコマンドの場合は Type=oneshot にしておきます。

ExecStart が実際に実行するコマンドです。 コマンドはフルパスで書く必要があります。

出力は systemd journal に送られるので、 crontab と違って リダイレクトなどは気にしなくても大丈夫です。

確認

systemctl cat hellosystemctl status hello で確認します。 service unit の場合は拡張子の .service は省略できます。

$ systemctl cat hello
# /etc/systemd/system/hello.service
[Service]
Type=oneshot
ExecStart=/bin/echo hello
$ systemctl status hello
● hello.service
   Loaded: loaded (/etc/systemd/system/hello.service; static; vendor preset: enabled)
   Active: inactive (dead)

実行

sudo systemctl start hello で実行できます。

$ sudo systemctl start hello
$ systemctl status hello
● hello.service
   Loaded: loaded (/etc/systemd/system/hello.service; static; vendor preset: enabled)
   Active: inactive (dead)

Sep 12 HH:MM:SS vagrant systemd[1]: Starting hello.service...
Sep 12 HH:MM:SS vagrant echo[1864]: hello
Sep 12 HH:MM:SS vagrant systemd[1]: Started hello.service.

ログ確認

systemctl status でも一部出ていますが、 journalctl -u hello でログが確認できます。

oneshot なので、 Starting から Started までの間が実際の処理 (ExecStart) になっています。

デーモンに書き換え

crontab の @reboot で何かを起動しておくのを 置き換えるのを想定して、 デーモンの例も書いておきます。

まず hello.service を以下の内容に書き換えます。

[Service]
ExecStart=/bin/sleep inf

書き換えた後は sudo systemctl daemon-reload で再読み込みが必要です。 再読み込みしていないと警告が出るので、忘れていても気付きやすいと思います。

$ sudoedit /etc/systemd/system/hello.service
$ systemctl cat hello
# Warning: hello.service changed on disk, the version systemd has loaded is outdated.
# This output shows the current version of the unit's original fragment and drop-in files.
# If fragments or drop-ins were added or removed, they are not properly reflected in this output.
# Run 'systemctl daemon-reload' to reload units.
# /etc/systemd/system/hello.service
[Service]
ExecStart=/bin/sleep inf
$ sudo systemctl daemon-reload
$ systemctl cat hello
# /etc/systemd/system/hello.service
[Service]
ExecStart=/bin/sleep inf

起動

sudo systemctl start hello で起動して、 sudo systemctl stop hello で停止できます。

$ sudo systemctl start hello
$ systemctl status hello
● hello.service
   Loaded: loaded (/etc/systemd/system/hello.service; static; vendor preset: enabled)
   Active: active (running) since Wed 2018-09-12 HH:MM:SS UTC; 6s ago
 Main PID: 2026 (sleep)
    Tasks: 1 (limit: 1135)
   CGroup: /system.slice/hello.service
           └─2026 /bin/sleep inf

Sep 12 HH:MM:SS vagrant systemd[1]: Started hello.service.
$ sudo systemctl stop hello
$ systemctl status hello
● hello.service
   Loaded: loaded (/etc/systemd/system/hello.service; static; vendor preset: enabled)
   Active: inactive (dead)

(ログ略)

自動起動

@reboot を置き換えるためには、 OS 起動時にデーモンも自動起動する必要があるので、 [Install] セクションを追加します。

[Install]
WantedBy=multi-user.target

[Install] セクションを追加して systemctl enable すると symlink が作成されて、 OS 起動時に自動起動するようになります。

systemctl enable --now hello のように --now オプションをつけると enablestart を同時にできます。

$ sudoedit /etc/systemd/system/hello.service
sudoedit: /etc/systemd/system/hello.service unchanged
$ sudo systemctl daemon-reload
$ systemctl cat hello
# /etc/systemd/system/hello.service
[Service]
ExecStart=/bin/sleep inf

[Install]
WantedBy=multi-user.target
$ sudo systemctl status hello
● hello.service
   Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

(ログ略)
$ sudo systemctl enable hello
Created symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.
$ sudo systemctl status hello
● hello.service
   Loaded: loaded (/etc/systemd/system/hello.service; enabled; vendor preset: enabled)
   Active: inactive (dead)

(ログ略)

削除

systemctl disable して service ファイルも削除すれば元に戻ります。

systemctl disable --now hello のように --now オプションをつけると disablestop を同時にできます。

$ sudo systemctl disable hello
Removed /etc/systemd/system/multi-user.target.wants/hello.service.
$ sudo systemctl status hello
● hello.service
   Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

(ログ略)
$ sudo rm /etc/systemd/system/hello.service
$ sudo systemctl daemon-reload
$ sudo systemctl status hello
Unit hello.service could not be found.

まとめ

crontab で @reboot some-command args で常駐させているデーモンを置き換えるには、 以下のような unit ファイルを作って systemctl enable --now すれば良いということを紹介しました。

[Service]
ExecStart=/path/to/some-command args

[Install]
WantedBy=multi-user.target
Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published