はじめに

以前から話題になっているcronの代替になるものとして有名な systemd-timer について調べたので覚書をする。

環境

1
AWS EC2 (t4g.nano) - AmazonLinux2023

前提

今回、systemd-timerの検証用にAWS EC2にインスタンスを作成したが、UTCのままタイムゾーンを変更していないことに注意。  

systemd-timer有効なもの

loadedされており、activeなものを出力する際は、systemctl -t timerで確認をする。

1
systemctl -t timer
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[ec2-user@ip-172-31-26-155 ~]$ systemctl -t timer
  UNIT                             LOAD   ACTIVE SUB     DESCRIPTION
  fstrim.timer                     loaded active waiting Discard unused blocks once a week
  logrotate.timer                  loaded active waiting Daily rotation of log files
  [email protected] loaded active waiting [email protected]
  sysstat-collect.timer            loaded active waiting Run system activity accounting tool every 10 minutes
  sysstat-summary.timer            loaded active waiting Generate summary of yesterday's process accounting
  systemd-tmpfiles-clean.timer     loaded active waiting Daily Cleanup of Temporary Directories
  update-motd.timer                loaded active waiting Timer for Dynamically Generate Message Of The Day

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.
7 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

--all オプションをつけると inactiveなものも確認できる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[ec2-user@ip-172-31-26-155 ~]$ systemctl -t timer --all
  UNIT                             LOAD   ACTIVE SUB     DESCRIPTION
  fstrim.timer                     loaded active waiting Discard unused blocks once a week
  logrotate.timer                  loaded active waiting Daily rotation of log files
  [email protected] loaded active waiting [email protected]
  sysstat-collect.timer            loaded active waiting Run system activity accounting tool every 10 minutes
  sysstat-summary.timer            loaded active waiting Generate summary of yesterday's process accounting
  systemd-tmpfiles-clean.timer     loaded active waiting Daily Cleanup of Temporary Directories
  update-motd.timer                loaded active waiting Timer for Dynamically Generate Message Of The Day

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.
7 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.

スケジュールの確認

systemctl list-timers で次の実行時刻を知ることができる。
NEXT の列が次回実行時刻

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[ec2-user@ip-172-31-26-155 ~]$ systemctl list-timers
NEXT                        LEFT          LAST                        PASSED   UNIT                             ACTIVATES
Sun 2024-06-09 06:30:00 UTC 4min 17s left -                           -        sysstat-collect.timer            sysstat-collect.service
Sun 2024-06-09 06:38:42 UTC 12min left    -                           -        systemd-tmpfiles-clean.timer     systemd-tmpfiles-clean.service
Sun 2024-06-09 21:25:02 UTC 14h left      -                           -        update-motd.timer                update-motd.service
Mon 2024-06-10 00:00:00 UTC 17h left      -                           -        logrotate.timer                  logrotate.service
Mon 2024-06-10 00:07:00 UTC 17h left      -                           -        sysstat-summary.timer            sysstat-summary.service
Mon 2024-06-10 00:57:15 UTC 18h left      -                           -        fstrim.timer                     fstrim.service
-                           -             Sun 2024-06-09 06:25:42 UTC 57ms ago [email protected] [email protected]

7 timers listed.
Pass --all to see loaded but inactive timers, too.

systemd-timerで定期的にジョブを実行させる

systemd-timerは主に2つのユニットファイルで構成されており、

  • サービスユニットファイル (.service)
      実際に実行されるコマンドやスクリプトを定義

  • タイマーユニットファイル (.timer)
      サービスユニットの実行タイミングを定義

上記の2つを作成することで、スケジュールに沿ったジョブ実行が可能となる。

サービスユニットファイルを作成する

/etc/systemd/system/以下に、例としてmy-task.service を作成する。

1
sudo vim /etc/systemd/system/my-task.service
1
2
3
4
5
6
[Unit]
Description=My Task

[Service]
Type=oneshot
ExecStart=/usr/local/sh/hello.sh
1
2
3
4
sudo mkdir -p /usr/local/sh/
sudo touch /usr/local/sh/hello.sh
sudo chmod +x /usr/local/sh/hello.sh
sudo vim /usr/local/sh/hello.sh
1
2
3
#!/bin/sh

echo [$(date '+%Y/%m/%d %H:%M:%S')] "Hello,World" >> /tmp/hello

タイマーユニットファイルの作成

/etc/systemd/system/以下に、例としてmy-task.timer を作成する。

1
sudo vim /etc/systemd/system/my-task.timer
1
2
3
4
5
6
7
8
[Unit]
Description=Run My Task every 5 minutes

[Timer]
OnCalendar=*-*-* *:0/5:00

[Install]
WantedBy=timers.target

Persistent=true をつけると、起動時間を過ぎて、何らかの理由でジョブを起動できなかった場合に、即実行されるようになる。 ※cronanacron と同じですね。

タイマーの設定確認

OnCalendar の日時の指定方法は systemd-analyze ユーティリティの calendar オプションを使用することでテストすることができます。タイマーユニットで使用したときに次に実行される日時も確認できます。例えば、systemd-analyze calendar weekly や systemd-analyze calendar “Mon,Tue --01..04 12:00:00” のようにコマンドを実行することでテストできます。

と ArchWikiに書いてあるので、設定内容はこれで良いかをテストする。

1
systemd-analyze calendar "*-*-* 00:00:00"

1
2
3
4
[ec2-user@ip-172-31-26-155 ~]$ systemd-analyze calendar "*-*-* 00:00:00"
Normalized form: *-*-* 00:00:00
    Next elapse: Mon 2024-06-10 00:00:00 UTC
       From now: 17h left

次回実行日まで丁寧に教えてくれる。

OnCalendarの書式について

1
DayOfWeek Year-Month-Day Hour:Minute:Second

とのことなので、 5分毎に実行であれば、下記のように書く。

1
OnCalendar=*-*-* *:0/5:00

※秒単位で設定できるので、cronより細かい時間単位で設定できる

1
2
3
4
5
6
7
8
[ec2-user@ip-172-31-26-155 ~]$ date
Sun Jun  9 06:27:59 UTC 2024

[ec2-user@ip-172-31-26-155 ~]$ systemd-analyze calendar "*-*-* *:0/5:00"
  Original form: *-*-* *:0/5:00
Normalized form: *-*-* *:00/5:00
    Next elapse: Sun 2024-06-09 06:30:00 UTC
       From now: 1min 48s left

タイマーの有効化と起動

下記で実行および、起動時に実行されるように設定する。

1
2
sudo systemctl enable my-task.timer
sudo systemctl start my-task.timer
1
2
3
[ec2-user@ip-172-31-26-155 ~]$ sudo systemctl enable my-task.timer
Created symlink /etc/systemd/system/timers.target.wants/my-task.timer → /etc/systemd/system/my-task.timer.
[ec2-user@ip-172-31-26-155 ~]$ sudo systemctl start my-task.timer

実行後のステータス確認

1
sudo systemctl status my-task.timer

1
2
3
4
5
6
7
8
[ec2-user@ip-172-31-26-155 ~]$ sudo systemctl status my-task.timer
● my-task.timer - Run My Task every 5 minutes
     Loaded: loaded (/etc/systemd/system/my-task.timer; enabled; preset: disabled)
     Active: active (waiting) since Sun 2024-06-09 06:28:42 UTC; 10s ago
    Trigger: Sun 2024-06-09 06:30:00 UTC; 1min 7s left
   Triggers: ● my-task.service

Jun 09 06:28:42 ip-172-31-26-155.ap-northeast-1.compute.internal systemd[1]: Started my-task.timer - Run My Task every 5 minutes.

今回のスクリプトでは、 /tmp/hello ファイルに追記されていくので、timerの時刻を過ぎた後にファイルを確認して動作できているかを検証する。 初回実行前は、/tmp/hello ができていないので一旦待つ。  

1
tail -f /tmp/hello
1
2
[ec2-user@ip-172-31-26-155 ~]$ tail -f /tmp/hello
[2024/06/09 06:30:00] Hello,World

参考

おわりに

systemd-timerについてcronの代替となると聞いていたので気になって試してみた。
今後、cronより増えていくのかなと思うが、cronの設定のシンプルさや浸透具合から考えるとまだまだかかりそう。
ただ、AmazonLinux2023ではcron(chrony)がデフォルトで入っていないので、systemd-timerが使われる機会が多くなりそうかな…?