スクリプト をサービス登録するテンプレート[init.d編]

> <sup>🐒 &nbsp; この記事は [fhd@github](https://github.com/fhd) 氏の**スクリプトをサービス登録するためのテンプレート「[init-script-template](https://github.com/fhd/init-script-template)」**の「[README.md](https://github.com/fhd/init-script-template/blob/master/README.md)」を翻訳したものです。ライセンスはオリジナルと同じ [MIT ライセンス](https://github.com/fhd/init-script-template/blob/master/LICENSE)です。</sup>

## 「お前もサービスにしてやろうか」俺様スクリプトのデーモン化

このテンプレートを使うと：

- 任意のスクリプトを [Daemonize](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%83%A2%E3%83%B3_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2)) できます。<br>（`start`, `stop`, `restart`, `status` コマンドに対応させつつサービスに登録できます）
- 自作スクリプト問わずコマンド実行できれば何でもサービス化できます.
- CentOS6 などの init.d 対応の Linux OS で利用できます。
- Raspberry Pi（Raspbian Wheezy 以前）などで、いい感じで動いた Node.js アプリを登録するのに便利です。
    - Raspbian Jessy 以降の場合は [SystemD を使う](https://qiita.com/KEINOS/items/f3e6b3064b0cbe35fd03#systemd-%E3%81%A7%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AB%E4%BB%BB%E6%84%8F%E3%81%AE%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)ことが推奨されています。
- PHP, Perl, Python だって登録可能です。
- 同じもので `init.d` でなく `SystemD` のテンプレートをお求めの場合は[こちら](https://qiita.com/KEINOS/items/f3e6b3064b0cbe35fd03#systemd-%E3%81%A7%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AB%E4%BB%BB%E6%84%8F%E3%81%AE%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)。

まずは「コマンドを叩いたら動作する適当な常駐系のスクリプト」が用意できた前提でご覧ください。

ここでいう「常駐系」とは、**無限ループなどで永遠と処理を実行するタイプのアプリ**を言います。例えば、特定ディレクトリを定期的にチェックし、変更があったら cURL などで WebHook[^webhook] 先の URL を叩いたり、メールを飛ばすなどのアプリを指します。

[^webhook]: 【WebHook（ウェブフック）とは】何かの条件に反応して指定された URL を叩くこと。トリガーのようなもの。[IFTTT](https://ja.wikipedia.org/wiki/IFTTT)が有名。GitHub などではリポジトリに変更があると、登録された URL に JSON データを POST することで WebHook 機能を実装しており、これを利用して [CI](https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) や Slack 通知などが実現できている。

なお、本記事は [Amazon Dash Button をラズパイで遊ぶ](/KEINOS/items/646bc4583d8efbae2870#%E6%89%80%E6%84%9F)のに利用した [Dasher](/search?q=dasher) の中の人が [README](https://github.com/maddox/dasher/blob/master/README.md) 内でこっそり[教えてくれてた](https://github.com/maddox/dasher/blob/master/README.md#raspberry-pi)内容を元にしています。また、**起動時（ブート時）にサービスを自動起動したい場合**も [Dasher の Wiki が詳しい](https://github.com/maddox/dasher/wiki/Running-Dasher-on-a-Raspberry-Pi-at-startup)です。<sup>~~（これも訳した方がいいかしら？ 👍10個ついたら訳そうと思います）~~</sup>

> <sup>🐒 &nbsp;【2019/02/26 追記】</sup>
> <sup>気づいたら [20 :thumbsup: いただいちゃってた](https://file.qiitadon.com/media_attachments/files/003/007/834/original/51df9c2d91e438b5.png)ので記事を作成しました。SystemV 系の init.d だけでなく **SystemD のテンプレート**も記載してあります。</sup>
>
> - <sup>「[任意のスクリプトをサービスとして登録し起動時（ブート時）に自動起動させる](https://qiita.com/KEINOS/items/f3e6b3064b0cbe35fd03)」@ Qiita</sup>
>
> <sup>また、本記事と直接は関係ありませんが、参考文献となった Node.js ベースの [Dasher](https://github.com/maddox/dasher/) は開発を終了し、代替として Python ベースの「[Nekmo/amazon-dash](https://github.com/Nekmo/amazon-dash)」がお薦めされています。また、[Amazon Dash Button も販売が終了した](https://www.google.com/search?q=amazon+dash+button+%E8%B2%A9%E5%A3%B2+%E7%B5%82%E4%BA%86)そうです。残念。</sup>

▼以下訳

----

System V init スクリプト・テンプレート
=============================

`Init` スクリプトに、`start`, `stop`, `restart`, `status` コマンドを提供するシンプルなテンプレートです。

[Node.js](http://nodejs.org) アプリや、その他の実行可能なスクリプトにも手軽に使えて便利です。

#準備
スクリプトの_[テンプレート](https://github.com/fhd/init-script-template/blob/master/template)_を `/etc/init.d/` にコピーして、わかりやすいファイル名（=サービス名）に変更してください。次にファイルを開き _Provides:_ の項目の後にスクリプト名を入力します。（_### BEGIN INIT INFO_ と _### END INIT INFO_ の間にあります）

<details><summary>テンプレート</summary><div>

本記事の元となった [Dasher](https://github.com/maddox/dasher/) が開発を終了したため、念の為以下に[テンプレート](https://github.com/fhd/init-script-template/blob/master/template)のバックアップをおきます。（2019/02/26）

```sh:init-script-template.sh
#!/bin/sh
### BEGIN INIT INFO
# Provides:
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
### END INIT INFO

dir=""
cmd=""
user=""

name=`basename $0`
pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.err"

get_pid() {
    cat "$pid_file"
}

is_running() {
    [ -f "$pid_file" ] && ps -p `get_pid` > /dev/null 2>&1
}

case "$1" in
    start)
    if is_running; then
        echo "Already started"
    else
        echo "Starting $name"
        cd "$dir"
        if [ -z "$user" ]; then
            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
        else
            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
        fi
        echo $! > "$pid_file"
        if ! is_running; then
            echo "Unable to start, see $stdout_log and $stderr_log"
            exit 1
        fi
    fi
    ;;
    stop)
    if is_running; then
        echo -n "Stopping $name.."
        kill `get_pid`
        for i in 1 2 3 4 5 6 7 8 9 10
        # for i in `seq 10`
        do
            if ! is_running; then
                break
            fi

            echo -n "."
            sleep 1
        done
        echo

        if is_running; then
            echo "Not stopped; may still be shutting down or shutdown may have failed"
            exit 1
        else
            echo "Stopped"
            if [ -f "$pid_file" ]; then
                rm "$pid_file"
            fi
        fi
    else
        echo "Not running"
    fi
    ;;
    restart)
    $0 stop
    if is_running; then
        echo "Unable to stop, will not attempt to start"
        exit 1
    fi
    $0 start
    ;;
    status)
    if is_running; then
        echo "Running"
    else
        echo "Stopped"
        exit 1
    fi
    ;;
    *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac

exit 0
```

</div></details>

続けて以下の３つの項目の値を設定します。

<dl>
  <dt>dir</dt>
  <dd>プロセスの作業ディレクトリを指定します</dd>
  <dt>cmd</dt>
  <dd>プロセスを実行するコマンド（いつも入力しているコマンド）</dd>
  <dt>user</dt>
  <dd>コマンドを実行するユーザー（オプション）。実行ユーザーが指定されていない場合は `sudo ...` を通して `root` として実行されます。</dd>
</dl>

## 設定例
以下は [algorithms](http://algorithms.ubercode.de) という Node.js アプリの場合の設定例です。

```bash:/etc/init.d/algorithms
...
    dir="/var/apps/algorithms"
    cmd="node server.js"
    user="node"
...
```

# 使い方

## Start
アプリを開始します。

    /etc/init.d/algorithms start

## Stop
アプリを停止します。

    /etc/init.d/algorithms stop

## Restart
アプリを再起動します。（stop→start）

    /etc/init.d/algorithms restart

## Status
アプリが実行中か確認できます。実行中の場合は _Running_（戻り値 _0_ ） 、それら以外の場合は _Stopped_ （戻り値 _1_ ）が表示されます。

    /etc/init.d/algorithms status

##ログ出力
デフォルトの設定では、標準出力は _`/var/log/<scriptname>.log`_ に出力され、エラー出力は
 _`/var/log/<scriptname>.err`_ に出力されます。出力先を変更したい場合は `stdout_log` と `stderr_log` の項目を変更してください。

# ライセンス

Copyright (C) 2012-2014 [Felix H. Dahlke](https://github.com/fhd)

これは MIT ライセンスの OSS です。詳細は [LICENSE](https://github.com/fhd/init-script-template/blob/master/LICENSE) ファイルをご覧ください。