小ネタ。あれもしかしてそうなの?と思って確認したら首題の通りだった。
割と便利で、定期実行ジョブをcronからsystemdに置き換えたいと思うモチベーションになり得る。
検証
とりあえず親となるparent.shと、子プロセスになるchild.shを作る。どちらも毎秒「parent」、「child」のメッセージを標準出力に出力する。
以下はrootで実行を想定。
cat > /root/parent.sh << EOF
#! /bin/bash
/root/child.sh &
while true
do
echo parent
sleep 1
done
EOF
chmod 700 /root/parent.sh
cat > /root/child.sh << EOF
#! /bin/bash
while true
do
echo child
sleep 1
done
EOF
chmod 700 /root/child.sh
このままparent.shを起動するとchild.shを止めるのが面倒なので、systemd serviceとして起動する。
cat > parent.service << EOF
[Unit]
Description=Parent
[Service]
ExecStart=/root/parent.sh
[Install]
WantedBy=multi-user.target
EOF
cp parent.service /etc/systemd/system/
systemctl daemon-reload
systemctl start parent
サービスが起動したところで、systemctl statusを見ると、メッセージに「parent」、「child」と、子プロセス側の標準出力も含めてjournaldに流れていることがわかる。
なお、止めるときは「systemctl stop parent
」でchild.shも止まる。これも便利。
timerでも試す
service的な使い方をするのでも便利なのだが、この、子プロセスを含めて標準出力をjournaldに送ってくれるというのは、定期実行する運用スクリプトでもありがたい。何がありがたいかというと、スクリプトごとにいちいち出力するログファイル名を決めてそのファイルを管理する必要がないのだ。cronで標準出力するとmailが残るが、どちらかというとmailが残るのが煩わしかった。
後はまあなんだ、dockerコンテナとの親和性である。
上のような例で、5秒毎にメッセージを記録するtimerのsystemdジョブを作るなら、以下の通り。
(なお、1秒ごとだと忙しすぎるらしく「repeated too quickly.」と言ってたまにコケる)
cat > /root/parent-t.sh << EOF
#! /bin/bash
echo parent-t
/root/child-t.sh
EOF
chmod 700 /root/parent-t.sh
cat > /root/child-t.sh << EOF
#! /bin/bash
echo child-t
EOF
chmod 700 /root/child-t.sh
cat > parent-t.service << EOF
[Unit]
Description=Parent-t
[Service]
Type=oneshot
ExecStart=/root/parent-t.sh
[Install]
WantedBy=multi-user.target
EOF
cat > parent-t.timer << EOF
[Unit]
Description=Parent-t timer
[Timer]
OnCalendar = *-*-* *:*:0/5
Unit = parent-t.service
AccuracySec=1s
[Install]
WantedBy = timers.target
EOF
cp parent-t.service parent-t.timer /etc/systemd/system/
systemctl daemon-reload
systemctl start parent-t.timer
systemctl enable parent-t.timer
journalctlに-fを付けてログを眺めると、5秒ごとにparant-tとchild-tのメッセージが出力されるのが確認できる。
ログファイル名フリーである。
journaldに送られたログは、syslog経由でテキストログにも保管される。一応。
RHEL系なら/var/log/messagesだし、ubuntuなら/var/log/syslog。
なお、timerでの定期実行を止めたい場合は「systemctl stop parent-t.timer
」。