記事ページを表示中

pythonプログラムをデーモン化する方法|Unitに処理を記述しsystemdで実行する

記事No.66

更新日時2023年02月18日

デーモンプログラムとは

デーモンとは、UNIX系のOSにおける常駐プログラムを指します。MacOSやLINUXはUNIX系OSに含まれます。常駐プログラムとは、常に動いているプログラムです。

現在はデーモンを管理するのに、systemdと呼ばれるプログラムが使用されています。systemdもデーモンプログラムです。

systemdは、システム管理デーモンで、カーネルによって最初に起動されるプログラムです。

systemdは、Unit単位で処理を実行します。Unitは、処理内容が書かれたファイルで、systemdは書かれている処理内容を実行します。

以下にUnitファイルの例をあげます。

このUnitファイルは、Serviceという種類のUnitファイルです。

[Unit]
Description = always_search daemon

[Install]
WantedBy = multi-user.target

[Service]
ExecStart = /home/ubuntu/always_get_relation/always_search.py

このUnitに書かれている、

ExecStart = /home/ubuntu/always_get_relation/always_search.py

この記述は、このUnitが実行された場合、/home/ubuntu/always_get_relation/always_search.pyを処理する旨が書かれています。

このように、pythonプログラムをデーモン化(常駐プログラム化)したい場合は、Unitに処理したいpythonプログラムを記述する事で、systemdが実行してくれます。

ですので、pythonプログラムをデーモン化するには、Unitの仕様を理解する必要があります。

コメントフォーム

Unitファイルが置かれる場所

Unitファイルが置かれる場所は、以下です。

・LinuxOSのデフォルト設定で使用されるUnitが置かれる場所

/usr/lib/systemd/system/

・自作の設定ファイルが置かれる場所

/etc/systemd/system/

また、外部からインストールされたデーモンファイルは、対象のプログラム毎に置かれる場所が異なるようです。たとえば、webサーバーソフトである、Nginxの保存先は以下のディレクトリとなっています。

/lib/systemd/system/

今回は、Unitを自作するので、保存場所は、/etc/systemd/system/となります。

Unitには、以下のような種類(拡張子)があり、systemdに実行させる処理の内容によって使い分けます。

.service

.mount

.socket

.device

.path

.target

今回は、自作したpythonプログラムを起動するので「指定のバイナリファイルを実行する拡張子」である「.service」を使用します。

コメントフォーム

.serviceファイルの書き方

.serviceファイルは、以下のセクションで構成されます。

・Unitセクション

・Installセクション

・Serviceセクション

Unitセクション

Unitの基本情報を記述します。以下のオプションがあります。

Description:Unitの説明を記述します。

Documentation:ドキュメントのURIを記述します。

Requires:このUnitが必要とするUnitを記述します。

After:このUnitより先に起動すべきUnitを記述します。

Before:このUnitより後に起動すべきUnitを記述します。

Installセクション

「systemctl enable」「systemctl disable」を設定した際に実行される内容を記述します。以下のオプションがあります。

※systemctl enableは、OSが再起動された時に、自動でサービス(.service)も再起動させる設定です。systemctl disableは、OSが再起動されてもサービス(.service)は再起動させない設定です。

WantedBy:enable時にこのUnitの.wantsディレクトリにリンクを作成します。

RequiredBy:enable時にこのUnitの.requiredディレクトリにリンクを作成します。

Also:enable/disable時に同時にenable/disableするUnitを記述します。

Alias:enable時にこのUnitの別名を用意します。

Serviceセクション

操作するデーモンに関する詳細設定を記述します。以下のオプションがあります。

ExecStart:このUnitを起動した際に実行するコマンドを記述します。

ExecStop:このUnitを停止した際に実行するコマンドを記述します。

ExecReload:このUnitをリロードした際に実行するコマンドを記述します。

Restart:このUnitが停止した際、Unitを再起動する条件を記述します。以下から条件を選択します。

・always:常に再起動する。

・no:再起動しない。

・on-success:終了コードが0で再起動する。

・on-failure:終了コードが0以外で再起動する。

RestartSec:再起動するまでの待ち時間(秒)を指定します。

Type:プロセスの起動方法を記述します。「起動完了」は次のユニットが実行可能である事を意味します。

・simple:プロセスが起動した時点で起動完了(デフォルト)

・forking:フォークして親プロセスが終了した時点で起動完了。

・oneshot:次のユニットを実行する前に自身のプロセスを終了する。

・dbus:D-Busを使うプロセスで、D-Busの接続名を見つけると起動完了

・notify:sd_notify()関数で起動完了のメッセージを受け取った際に起動完了

・idle:他のジョブが終了するまで待機

記述例

例として以下のように.serviceファイルを記述しました。

ファイル名:always_search.service

[Unit]
Description = always_search daemon

[Install]
WantedBy = multi-user.target

[Service]
ExecStart = /home/ubuntu/always_get_relation/always_search.py
Restart = no
Type = simple

ExecStartに指定するコマンドについて

ExecStartには、このUnitを起動した際に実行するコマンドを記述します。

上の記述例では、

ExecStart = /home/ubuntu/always_get_relation/always_search.py

となっています。このコマンドは、pythonファイルまでの、ただのパスのように見えます。

ですが、pythonファイルの中で、shebang(シバン)でインタプリタ(今回はpythonのインタプリタを使う)を指定する事でpythonファイル内に記述したプログラムを実行してくれます。

shebangは、以下のように記述します。

#!/home/ubuntu/.pyenv/shims/python3
#本番環境ではpyenvのpython3を使用

import sys
import psycopg2
import datetime
import requests
import time
import json
import os

#以下省略

shebangは「#!」に続けて実行ファイルのパスを指定します。

実行ファイルのパスは環境によって異なりますので、以下のようにenvコマンドを使用して実行ファイルの位置を探し出し指定する事もできます。

#!/usr/bin/env python

コメントフォーム

著者情報

名前:スカーレット
2010年からWEBサイトやWEBアプリを作成しています。最初は趣味でブログを書いていましたがSEOを勉強するのが楽しくなり、そのままブロガーとして独立しました。その後、記事を書くだけでは物足りなくなり自分でWEBアプリの作成をスタート。現在はブロガー兼プログラマーとして活動しています。このWEBアプリ(ブロトーク)もDjangoで自作しました。ブロトークはブログとSNSを合体させたようなWEBアプリです。ブログを読んで気づいた事や感想などあれば、気軽にメッセージを送って頂ければと思います。WEB技術を一緒に勉強していけたらと思います。