ルモーリン
ホーム 更新 Perl Sample ランドナー サービス 雑談 コースガイド 鉄ゲタ 自転車 Linux リンク 連絡先

一般ユーザーの常駐プログラムをサービス化

2019-08-17

背景

このサイトのWebサーバー(Mojolicious)や、その内部で使う簡易データーベース(redis-server)といった常駐プログラムを一般ユーザーから起動しています。 システムを再起動した際は、その都度sshでログインして起動していましたけれど、crontabの起動条件を「@reboot」にすることでシステム起動時に合わせて起動するようになり面倒が減りました。 けれど、何かのトラブルで停止するとそれきりなので、気が向いたときに自分でサイトをチェックしています。 チェックしてトラブルを見つけるまで停止したままというのもアレですし、なによりチェックするのが面倒になってきました。 チェックぐらいコンピューターが何とかしろよと考え始め、こーゆーのは自分で作るより先人の仕組みを利用しようと探しました。

CentOS7ならsystemctl

CentOS6で使っていたserviceからCentOS7ではsystemctlになり、一般ユーザーでもサービスを運用できるようになりました。 もしかしてCentOS6のserviceでも運用できた? ただしウチのシステムではsystemctl --userが上手いこと動作しません。 やってみると「dbusが接続を拒否しました」的なメッセージが出て終了します。 X-Window(おっさんか)…もとい、GUI前提のシステムですと、一般ユーザーが使う設定が完備しているのかもしれません。 ウチのはsshだけのシステムなのでsystemctlを一般ユーザーが使う前提にないのです(残念)。 次善の策としてシステムのサービスとして追加するけれど一般ユーザーで実行するように設定します。

常駐したいプログラム

とりあえず簡単な例でredis-serverを挙げます。 これは一般ユーザーがシェルから起動できる簡易なデーターベースサーバーのようです。 ログアウトと共に終了すると常駐しないので、起動用スクリプトの中でnohupを使い常駐させていました。 単に実行だけならredis-serverとするだけです。 注意点として起動時のディレクトリにデータファイルが生成されるため、スクリプトと同じディレクトリに移動(切替?)をしてから起動します。 オプションなしはこれまでの「ログインして起動する」動作として残し、サービスとして常駐する場合は起動/停止のオプションを指定するようにしました。 スクリプトのファイル名はmojoredis.shです(Mojoliciousで使うredisの略)。 中で使うreadlinkコマンドはこちらの記事をご覧ください→【 readlink 】コマンド――シンボリックリンクのリンク先を表示する:Linux基本コマンドTips(238) - @IT 記事の説明と異なり、普通のファイルを指定しても絶対パスを返します。

#!/bin/bash

THIS_FILE_PATH=`readlink -e $0`
FILE_DIRECTORY=${THIS_FILE_PATH%/*}
THIS_FILE=${THIS_FILE_PATH##*/}
# SCRIPT_FILE=${THIS_FILE/%.sh/.pl}
ERROR_LOG_FILE=${THIS_FILE%.sh}_error.log

# スクリプトがあるディレクトリに移動
cd ${FILE_DIRECTORY}

# オプションなし
if [ 0 -eq $# ]; then
	# コマンドラインから起動(ログアウト後も継続)
	echo start redis server.
	nohup redis-server </dev/null >/dev/null 2>>${ERROR_LOG_FILE} &

	sleep 3
	pgrep -fa redis-server
	echo done.
elif [ "start" = $1 ]; then
	# 起動
	redis-server
elif [ "stop" = $1 ]; then
	# 停止
	redis-cli shutdown save
else
	echo "使い方:$0 [start|stop]"
fi

.serviceファイル

サービスの設定をテキストファイルに書きます。 大抵は/etc/systemd/systemの下に.serviceファイルを作りますけれど、ここでは一般ユーザーで管理しますから.serviceファイルをユーザーのホームディレクトリの下に作ります。 ファイル名はmojoredis.service、サービス名はmojoredisです。 設定のうちRestartをnoにして無事に稼働したのを確認できてからalwaysに変更します。 alwaysは起動に失敗すると再起動を繰り返した上で再起動を停止するので原因追及の邪魔になります。

[Unit]
Description=Redis Server for Mojolicious
After=network.target

[Service]
User=mojolicious
Type=simple
ExecStart=?????/mojoredis.sh start
ExecStop=?????/mojoredis.sh stop
Restart=no

[Install]
WantedBy=multi-user.target

.serviceの追加

スーパーユーザーでシステムに.serviceファイルを追加しましょう。 /etc/systemd/systemから前述の.serviceファイルにシンボリックリンクを貼ります。 これ、セキュリティ的にどうなんだろう→cd /etc/systemd/system→ln ?????/mojoredis.service

サービスの追加

ここから一般ユーザーに戻ります。 systemctlは一般ユーザーでも使うようにできてるので、システムのサービスに手を加える操作を行うと、どのアカウント(の権限?)で実行するか選択できます。 選択したアカウントのパスワードを入力して認証をパスすれば実行します。 ファイルを作ったり書き替えたらsystemctl daemon-reloadで再読み込みさせるとmojoredisが追加されています(きっと)。 systemctl status mojoredisでサービスの存在を確認しましょう。 表示例は稼働後に停止させて取得したものなので実際と異なります。 表示例の?????はパス、ホスト名等です。


systemctl status mojoredis
● mojoredis.service - Redis Server for Mojolicious
   Loaded: loaded (?????/mojoredis.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since 土 2019-08-17 15:18:22 JST; 6s ago
  Process: 26583 ExecStop=?????/mojoredis.sh stop (code=exited, status=0/SUCCESS)
  Process: 4438 ExecStart=?????/mojoredis.sh start (code=killed, signal=TERM)
 Main PID: 4438 (code=killed, signal=TERM)

これまで常駐していたredisを一旦停止させてから、systemctl start mojoredisで起動してみましょう。 上手く行ったか再度systemctl status mojoredisで表示させると分かります。 無事に常駐したのを確かめてからmojoredis.serviceのRetry=noをRetry=alwaysに変更、systemctl daemon-reloadで再読み込みしてください。 最後にsystemctl enable mojoliciousでシステム再起動と共に起動するよう設定します。

サービスのできあがり

できあがったmojoredisサービスはこんな感じです。 redis-serverの出力がログに統合されているので動作確認が超便利♪ 制御盤の運転ランプのような○/を表示してカラー対応になっています。 redisは定期的にファイルに保存するみたいだ(おい)。 表示例の?????はパス、ホスト名等です。


systemctl status mojoredis
 mojoredis.service - Redis Server for Mojolicious
   Loaded: loaded (?????/mojoredis.service; enabled; vendor preset: disabled)
   Active: active (running) since 水 2019-08-14 12:36:04 JST; 2 days ago
 Main PID: 4438 (mojoredis.sh)
   CGroup: /system.slice/mojoredis.service
           tq4438 /bin/bash ?????/mojoredis.sh start
           mq4440 redis-server *:6379

 8月 16 14:10:31 ????? mojoredis.sh[4438]: 4440:M 16 Aug 14:10:31.074 * 1 changes in 3600 seconds. Saving...
 8月 16 14:10:31 ????? mojoredis.sh[4438]: 4440:M 16 Aug 14:10:31.076 * Background saving started by pid 8318
 8月 16 14:10:31 ????? mojoredis.sh[4438]: 8318:C 16 Aug 14:10:31.079 * DB saved on disk
 8月 16 14:10:31 ????? mojoredis.sh[4438]: 8318:C 16 Aug 14:10:31.080 * RDB: 0 MB of memory used by copy-on-write
 8月 16 14:10:31 ????? mojoredis.sh[4438]: 4440:M 16 Aug 14:10:31.176 * Background saving terminated with success
 8月 16 15:10:32 ????? mojoredis.sh[4438]: 4440:M 16 Aug 15:10:32.068 * 1 changes in 3600 seconds. Saving...
 8月 16 15:10:32 ????? mojoredis.sh[4438]: 4440:M 16 Aug 15:10:32.068 * Background saving started by pid 9008
 8月 16 15:10:32 ????? mojoredis.sh[4438]: 9008:C 16 Aug 15:10:32.073 * DB saved on disk
 8月 16 15:10:32 ????? mojoredis.sh[4438]: 9008:C 16 Aug 15:10:32.074 * RDB: 0 MB of memory used by copy-on-write
 8月 16 15:10:32 ????? mojoredis.sh[4438]: 4440:M 16 Aug 15:10:32.169 * Background saving terminated with success