DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

Pythonコードをデーモン化する(Systemdとinit.dの違い)

プログラムを書いたらやはり「システム起動時に自動的に実行」ということがしたくなる。

pythonの場合、プログラム自体はシェルから

python sample.py

とすると実行できるが、実行中は他の作業が出来ない。

ctrl+zで一時停止させて

jobs

で表示されたナンバーを

bg 1

等とするとバックグラウンドで実行されるが面倒くさい。

元々

python sample.py&

とすると最初からバックで実行されるようになるが、ユーザーがログアウトしたら終了してしまう(のかな?)

 

最初から自動的にバックグラウンドアプリとして実行させるには「デーモン」というプログラムにする必要がある。

f:id:DreamerDream:20191230140457p:plain

(こりゃデビルか・・・)

 

Linuxではデーモンとして作ってサービスに設定することでシステム起動時に自動で実行したり、killされた場合は再度実行されたり、システム終了時に自動で読み出すように設定することも可能なようだ。

デーモンプログラムは名前の最後に「d」を付けるのが一般的なようでsample.pyではなく、sampled.pyのように名付けるそうだ。

 

こちらのブログを参考にさせていただいた。というかそのまま。

https://glorificatio.org/archives/1965

 

 -- sampled.py --

import os

import sys

import time

 

def sample():

        while 1:

                time.sleep(5)

                print "sample-daemon"

def fork():

        pid = os.fork()

 

        if pid > 0:

                f = open('/var/run/gpio_fan_controld.pid','w')

                f.write(str(pid)+"\n")

                f.close()

                sys.exit()

 

        if pid == 0:

                sample()

 

if __name__=='__main__': 

        fork()

 5秒ごとに「sample-daemon」と出力するだけのプログラム。

fork()でPID(プロセスID)をファイルに保存し、デーモンとして実行された時に追跡(?)出来るらしい。

 

このデーモンとして作ったプログラムをデーモンとしてシステムに登録することでデーモンプログラムとしてシステムから実行出来る。

デーモンプログラムを含め、各プロセス管理システムをサービスと呼ぶ。

 

ちなみに、sample.pyをデーモンとして実行させた場合、リモートでは実行されているかわからない。

Linuxでは標準出力したものはログファイルに残るようになっている。

なので確認は

sudo nano /var/log/syslog

で確認することが出来る。 

 

Raspbianではinit.dで管理しているサービスとsystemdで管理しているサービスがある。

これらはディストリビューションにより異なる。

init.dはWheezy以前の比較的古いシステム、systemdはJessie以降の比較的新しいで採用されている。

僕の場合、幸運なことに一台目でWheezy、二台目でJessieと2つとも触ることが出来たのでinit.dとsystemdの書き方を両方残しておく事にする。

sampled.pyのプログラム自体は変える必要はない。

 

 

 

==== まず、新しいsystemdの書き方 ====

サービスの設定ファイルを置く場所

cd /usr/lib/systemd/system

へ移動

sudo nano sampled.service

でサービス設定ファイルを作る

(/usr/lib/systemd/system/より、/etc/systemd/system/ のが優先的に使われるようです。)

中身はこんな感じ

-- sampled.service --

[Unit]
Description=Sample Daemon

[Service]
ExecStart=/usr/local/lib/sampled.py
Restart=always
Type=forking
PIDFile=/var/run/sampled.pid

[Install]
WantedBy=multi-user.target

Unitはデーモンの説明

Serviceが設定

ExecStartでシステム起動時にsampled.pyを起動するよう設定している。

(余談)ExecStopPost=/usr/local/lib/end.pyのように指定するとsampled.py終了時にend.pyプログラムを実行することが出来るようだ。 

Restartはプロセスが終了した場合の再起動条件

Typeはサービス起動完了の判定方法

PIDFileはsampled.pyで生成したPIDファイルの場所

その他、こちらのブログに詳しく書いてあるので割愛

Systemd入門(4) - serviceタイプUnitの設定ファイル - めもめも

 

上記のサービス設定ファイルが書けたら保存して

サービスの再読み込みをする。

sudo systemctl daemon-reload

サービスをスタート

sudo systemctl start sampled

動いているか確認

systemctl status sampled

システム起動時に自動的に実行させる

sudo systemctl enable sampled

起動時に実行する設定が有効かチェックする

systemctl is-enabled sampled

起動時に実行する設定を取り消す

systemctl disable sampled

その他systemdの使い方参考サイト

systemd - ArchWiki

 

<追記>Systemdだけで運用する場合、つまりinit.dとの互換性を保つ必用の無い場合は下URLの方法が楽です。

dreamerdream.hateblo.jp

 

 

 

==== init.dでの書き方 ====

/etc/init.d/skeleton が起動スクリプトのサンプルなのでコピーして書き換える

sudo cp /etc/init.d/skeleton /etc/init.d/sampled
sudo nano /etc/init.d/sampled

4カ所書き換える

-- sampled --

### BEGIN INIT INFO
# Provides: sample daemon

DESC=”sample_daemon
NAME=sampled
DAEMON=/usr/local/lib/$NAME.py

Provides:名前(?)

DESC プログラムの説明

NAME プログラム名

DAEMON NAMEで設定したpythonファイルのある場所

 

実行権をつける

chmod 755 /etc/init.d/sampled

サービス登録する

sudo insserv sampled

正しく登録されているか確認する

sudo find /etc/ -name "*sampled"

ランレベルごとのディレクトリにsampledが正しく入っていれば成功。

登録削除は

insserv -r sampled

サービスの起動

sudo /etc/init.d/sampled start

サービス一覧表示

service --status-all

ステータス表示

service sampled status

  

 

kampa.me