Raspberry Pi[59] 自作プログラムのサービス化
システムサービスだけではなく、自分で作ったプログラムもサービスとして動かすことができます。なんのメリットがあるかというと、systemctl コマンドで止めたり、動かしたり自由であること、エラーログを含めてユーザーが気にしなくてもログに記録してくれる。また、何らかの影響でプロセスが死んでも自動で再起動かけてくれるなど、自分でやると結構大変なことが簡単にできる。今回は二つのプロセスを動かすプログラムをサービス化してみました。この二つは最初に起動したプロセスが共有メモリをファイルに書き出し、それを二番目のプログラムが読んでプロセス間通信をするため、若干起動を遅らせるなどの処理をしています。
まず、必要なのは、各プログラムをサービスに登録することと、二つの関連を各ファイルが必要です。
#/etc/systemd/system/xing_alart.service
[Unit]
Description=XING Alert
After=network.target
PartOf=xing_all.target
[Service]
WorkingDirectory=/home/pi/work/XING
ExecStart=/home/pi/work/XING/xing_alart -d 1 -c /home/pi/work/XING/config_iwate_obc.txt -ip 2 "192.168.1.2" "192.168.100.201"
Restart=always
RestartSec=3
StandardOutput=null
StandardError=journal
[Install]
WantedBy=multi-user.target
🔹 [Unit]
セクション
このセクションは「サービスの関係性や起動条件」を定義する部分。
Description=XING Alert
- このサービスの説明(任意)
systemctl status
やjournalctl
で表示される名前になるだけ
After=network.target
- ネットワークが有効になってから起動することを保証
ip
オプションでネットワークを使っているため、これは重要
PartOf=xing_all.target
xing_all.target
をstop
またはrestart
したときに、このサービスも連動して止まる・再起動される- ただし、
xing_alart
を個別に止めてもxing_all.target
には影響しない(一方向の関連)
🔹 [Service]
セクション
サービスの本体の動作内容と挙動制御を定義する。
WorkingDirectory=/home/pi/work/XING
- カレントディレクトリをここに設定
shared_id.txt
など、相対パスでファイルアクセスするなら必須
ExecStart=...
- 実行するコマンド
- ここに書かれたプログラムがこのサービスの本体になる
Restart=always
- プログラムが終了した場合、どんな理由であれ再起動する
RestartSec=3
- 再起動するまで 3秒待つ
StandardOutput=null
printf()
などの出力を 無視して捨てる- journal にログがたくさん出るのを防ぐため
StandardError=journal
fprintf(stderr, ...)
のようなエラー出力は journal に記録される- 異常時のログはしっかり残せるようにしてある
🔹 [Install]
セクション
このセクションは **「このサービスをいつ起動するか」**を決めるもの。
WantedBy=multi-user.target
- システムが通常のマルチユーザー状態(ログイン可能な状態)になったときに、自動で起動される
sudo systemctl enable xing_alart
をしたとき、このターゲットに登録される
後から起動するプログラムはほとんど同じ
# /etc/systemd/system/esp32-com.service
[Unit]
Description=ESP32 COM
Requires=xing_alart.service
After=xing_alart.service
PartOf=xing_all.target
# BindsTo=xing_alart.service
[Service]
Type=simple
WorkingDirectory=/home/pi/work/XING
ExecStartPre=/bin/sleep 2
ExecStart=/home/pi/work/XING/esp32-com -d 1
Restart=always
RestartSec=3
StandardOutput=null
StandardError=journal
[Install]
WantedBy=multi-user.target
先ほどと異なるところだけ説明すると
[Unit]
セクションの違い
Requires=xing_alart.service
- このサービスを起動するには
xing_alart
が必要 - つまり、
esp32_com
をstart
すると、自動的にxing_alart
もstart
される
After=xing_alart.service
- 起動の順序制御
xing_alart
が起動してからesp32_com
を起動する(共有メモリ作成を待つため)
🔹 [Service]
セクションの違い
ExecStartPre=/bin/sleep 2
ExecStart
を実行する前に2秒間待機- これは
xing_alart
が共有メモリを作成・初期化し終わる時間を稼ぐための処置 - 地味だけど、安定起動のためにとても効果的
必要だった systemctl
コマンドを一連の作業ごとに分けて整理しておく。
✅ 1. サービスファイルを編集・反映
bashコピーする編集するsudo systemctl daemon-reload
✅ 2. サービスを有効化(起動時に自動起動)
bashコピーする編集するsudo systemctl enable esp32_com.service
WantedBy=multi-user.target
に基づいて起動時に有効化される
※一緒に使っていた サービスを一括有効化するなら:
bashコピーする編集するsudo systemctl enable xing_all.target
xing_all.target
はこんな感じ
# /etc/systemd/system/xing_all.target
[Unit]
Description=All XING Services
Requires=xing_alart.service esp32_com.service
After=network.target
4. サービスの状態確認
bashコピーする編集するsudo systemctl **.service
- 実行中かどうか・最終ログの一部が見られる
✅ 5. ログの確認(詳細ログ)
bashコピーする編集するsudo journalctl -u **.service -n 50 --no-pager
printf()
やstderr
の出力、失敗理由などを確認-n 50
は「直近50行」を表示。もっと見たいなら-n 100
とかに変更可能
✅ (補足)一括制御(target 経由)
bashコピーする編集するsudo systemctl restart xing_all.target
sudo systemctl stop xing_all.target
- すべての関連サービス(
PartOf=xing_all.target
を持つ)を一気に制御できる