自作プログラムを，PC起動時に自動的に起動する方法

大学院でIoT関連の研究を行っていることもあり，Raspberry Piに接続したセンサからデータを取得するプロセスを常駐させたいということが良くある．これから説明することは，今となっては当たり前のことなのだが，研究室の後輩に教えてあげたところ中々ウケが良かったので，他の誰かのためにもなればと思い，ここにまとめておく．

研究室に配属された当初は，Raspberry Piを起動するたびにSSHでログインして，下に示すようにnohupコマンドを使ってバックグラウンドでプログラムを実行していた．nohupコマンドを付けてコマンドを実行することで，ログアウトした際のHUP(HangUP)シグナル（SIGHUP：制御している端末の終了を伝えるシグナル）を無視してプログラムを継続して動かすことができるようになる．HUPを無視するからNo HUPという訳だ．ただし，これではRaspi起動時に自動的にプログラムを実行することはできない．

```
nohup 'command' &
```

しかし，Raspberry Piを起動するたびにSSHでログインして，コマンドを実行して…なんてことを毎回やるのは流石に面倒臭い．なんとかならないかと思い調べてみると，実はこんなに面倒臭いことをする必要はなく，デーモン(daemon)として動かしてあげれば良いらしい．デーモンというのは，OSに常駐して動作するプロセスのこと．例えば，Raspberry Piを起動してしばらくするとsshでログインできるようになるのも実はsshdというデーモンプロセスのおかげなのである．メールが正しく送信できなかったときの自動返信メールにあるMAILER-DAEMONというのも，デーモンプロセスの一種だ．

## 自作プログラムデーモン化プロセス
上の話をまとめると，自作プログラムをPCの起動と同時に起動するには，そのプログラムをデーモン化してあげれば良い．ここで，デーモンとは何か? という説明は他の詳しい方々に譲ることにして，「じゃあ，実際に何をすれば良いの?」という点に絞って説明をしていく．

仮に，`/usr`ディレクトリに`sample_daemon.py`というプログラムがあるとする．このプログラムをデーモン化するには，いくつかの選択肢がある(SysV init, Upstart, Systemd等)のだが，現在はSystemdが一般的になってきているようなので，ここではSystemdを使ったデーモン化のみ説明する．

### Service Unitの作成
上のプログラムをデーモンプロセスとして動かすには，まずその旨を宣言するためのService Unit(sample.serviceとする)を以下のように作成し，`/etc/systemd/system/`に保存する．実際に作成する場合は，DescriptionやExcecStartのところを自分のプログラムに合わせて書き換えれば良い．(ここで紹介しているService Unitの書き方は最も簡単なものであり，実際には他にもオプションが沢山ある．気になる方は，参考リンクなどを参考に自分で調べてみて欲しい)

``` sample.service
[Unit]
Description=Sample Daemon Process

[Service]
ExecStart=/usr/bin/python /usr/sample_daemon.py
Restart=always

[Install]
WantedBy=multi-user.target
```

### systemctl enable & systemctl start

上記のファイル(sample.service)を`/etc/systemd/system/`に保存したら，次はそのサービスを`systemctl`コマンドでenableして，startする．`systemctl enable 'Unit名'`を実行することで，指定したUnitが起動時に実行されるようになり，`systemctl start 'Unit名'`を実行することで，その場でUnitを開始できる．

```
$ sudo systemctl enable sample.service
$ sudo systemctl start sample.sercie
```

## 動作確認

以下のコマンドを実行することで，今回設定したデーモンプロセスが正しく動いているかを確認することができる．下のように`Active: active`となっていればOKだが，ここで`Active: failed`となっていたら，何かがおかしいのでエラーメッセージを確認してみよう．

```
pi@hostname:~# sudo systemctl status sample
● sample.service - Sample Daemon Process
   Loaded: loaded (/etc/systemd/system/sample.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2018-07-02 09:32:42 UTC; 9s ago
 Main PID: 2133 (python)
      CPU: 89ms
   CGroup: /system.slice/sample.service
           └─2133 /usr/bin/python /usr/sample-daemon.py

Jul 02 09:32:42 hostname systemd[1]: Started Sample Daemon Process.
```

## 一応，再起動して確認

最後に，端末を再起動して正しくデーモンプロセスが動いているかを確認してみるかをオススメする．再起動後にもう一度`sudo systemctl status sample`を実行して，上と同じように`Active: active`となっていれば問題なくプロセスは動いている．

## まとめ

最初はデーモンと言われるとなんだか難しそうと思ってしまうかもしれないが，一回自分でやってみればそこまで難しいことではないことがわかると思う．

まとめると，自作プログラムのデーモン化のためのステップは以下の通り．
1. デーモンとして動かすプログラムを作成する
2. デーモンとして動かすためのService Unitを`/etc/systemd/system/`に保存
3. systemctlコマンドでenable & start
4. (動作確認 systemctl status 'サービス名')

## 参考リンク
[デーモン (daemon)とは｜「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/word11000.html)
[Systemd入門(1) - Unitの概念を理解する](http://enakai00.hatenablog.com/entry/20130914/1379146157)
[Systemd入門(4) - serviceタイプUnitの設定ファイル](http://enakai00.hatenablog.com/entry/20130917/1379374797
)
[「Systemd」を理解する ーシステム管理編ー | ギークを目指して](http://equj65.net/tech/systemd-manage/)
[【 nohup 】コマンド――端末を閉じてもログアウトしても処理を続ける」](http://www.atmarkit.co.jp/ait/articles/1708/24/news022.html)