Help us understand the problem. What is going on with this article?

systemdを時間帯で管理したい!!

はいはいはいはい、皆さんこんにちは、○○です。
ええ、自粛期間中はYoutubeが捗りますね、いつも面白い動画をありがとうございます。

systemdを用いてデーモンを特定の時間帯だけ起動させる方法についてです。
意外と需要ありそうなのですが関連する記事が見当たらなかったので備忘録的に試行錯誤を記しておこうと思います。

やりたいこと

8時から23時の間だけデーモン(以下ダエモンさんことMr.daemon)を起動しておきたい。
その他の時間は消費電力削減のために停止しておきたい。
ちなみに、操作したいデーモンは自作のもので、起動中にffmpegでHLSを用いて音声をストリーミング配信し続けるというものです。
余談ですがサービスとデーモンの何が違うのか調べたら、どちらも常駐プログラムで、サービスはWindows系で使われデーモンはUnix系で使われるそうです。

まず思いついた方法

後ほど問題点を記しますがとりあえず。

起動編

systemdを用いたダエモンさんの起動方法は主に二つ挙げられると思います。

  • 自動起動 systemctl enable {Mr.daemon}
  • 手動起動 systemctl start {Mr.daemon}

ですが、これらの方法では時間を指定することはできません。
自動起動ではいつ何時も問答無用で起動してしまいますし、手動起動は言わずもがなです。
そこで時間を指定するためには以下の方法を使えるかと思います。

  • タイマー {Mr.daemon}.timer
  • cron 0 8 * * * systemctl start {Mr.daemon}

systemdのタイマー

systemdのタイマー機能を利用して特定の時間にダエモンさんを起動できます。

{Mr.daemon}.timer
[Unit]
#任意の説明
Description=Run {Mr.daemon}.service

[Timer]
#起動したい時刻
OnCalendar=*-*-* 8:00:00 #year-month-date hour:minute:second
#OnCalenderで指定した時刻にOSが寝ていた場合、次回起動時にデーモンを起動
Persistent=true 

[Install]
WantedBy=timers.target

このようにユニットファイルを記したらsudo systemctl enable {Mr.daemon}.timerでタイマーを有効にします。

管理者権限cron

管理者権限のcronでも時間を指定してsystemctl startを走らせることで同様のことができます。

  1. sudo crontab -e
  2. 右を追記 0 8 * * * systemctl start {Mr.daemon}

停止編

systemdのタイマーでは起動することはできても停止することはできないそうです。
ですので停止するためにはいずれにせよcronを使います。
管理者権限のcronに以下のように追記すればよいです。

0 23 * * * systemctl stop {Mr.daemon}

上記方法の問題点

さて、上の方法で実装したところ幾つか不都合がありました。
それは8時から23時の間に再起動した後デーモンが起動しないという点です。
当然ですが始まりと終わりのトリガーしか設定していないので、例えばメンテナンス等で9時に再起動した場合は手動で起動しないと翌8時までダエモンさんは眠ったままです。
これでは特定の時間帯だけ稼働するデーモンとしては不十分です。

ではどうするか

デーモンの起動スクリプトをいじることにしました。

stream.sh
###追記部分
NOW=`date +%H` #現在時刻の取得
if [ $NOW -ge 23 -o $NOW -lt 8 ]; then #現在時刻が23時~翌8時の間なら
    systemctl stop {Mr.daemon} #デーモンを停止
    exit 0 #正常終了
fi
###

function fork() {
    #処理
}
fork > /dev/null 2>&1 </dev/null &
echo $! > /run/{Mr.daemon}.pid

追記部分で23時から翌8時の間にこのスクリプトが走ると処理から抜けるようにしてあります。
この状態でsudo systemctl enable {Mr.daemon}として、常に自動起動するようにします。
8時から23時の間では自動起動しますが、23時から翌8時の間は自動起動がキャンセルされるのでダエモンさんは眠ったままです。
最初に試したsystemdのタイマーとデーモンを停止するcronと組み合わせれば特定の時間帯に起動しているダエモンさんの出来上がりです。

解説

当初ifの中はexitだけでしたが、その状態だと起動が失敗したとエラーが吐かれてしまいました。
exit 0として正常終了を返しても同じでした。
別に問題ないといえばそれまでなのですが気持ちが悪いのでsystemctl stop {Mr.daemon}を記述したところ起動キャンセル扱いとなりエラーは出なくなりました。

cronでは?

試していませんがデーモン起動スクリプトをいじれなければ同様のことをcronでも実現できるでしょう。

@reboot if [ $NOW -lt 23 -a $NOW -ge 8 ]; then systemctl start {Mr.daemon}; fi

このように管理者権限cronに追記しておけば23時から8時の間にOSが起動された時ダエモンさんも起動します。
無駄に起動させないのでcronのほうがスマートな気もしますがAfterや依存関係などsystemd関連の順番を調整するのが面倒だったのでsystemdのほうで自動起動するようにしました。

最後に

どうも何れのやり方もスマートな感じがしないので良い方法をご存じの方がいらっしゃいましたらご教授ください。

genshibangou16
趣味グラマー
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away