Slackアプリで作った自作ラズパイゼロ定点カメラをSystemdデーモンで自動起動するやり方


※ 当ページには【広告/PR】を含む場合があります。
2022/03/04
【ラズパイDIY講座】ラズパイゼロで作る監視カメラ⑥〜Slackアプリから監視カメラ画像を取得してみる
蛸壺の中の工作室|Slackアプリで作った自作ラズパイゼロ定点カメラをSystemdデーモンで自動起動するやり方

以前の記事で、
『Slackサーバー化したラズパイゼロ定点カメラ』を設定する方法を紹介していました。

合同会社タコスキングダム|タコツボの中の工作室
【ラズパイDIY講座】ラズパイゼロで作る監視カメラ⑥〜Slackアプリから監視カメラ画像を取得してみる

Slackサーバーで監視カメラシステムを動かす話題を簡単に紹介しています。

ラズパイの最近の機種はCPUのアーキテクチャはARMv8となり、Dockerやk8sも簡単にインストールできるし、安定して動作するようになりました。このことで常駐プログラムがDockerコンテナで安定して動くので、著者的には普段Dockerコンテナ化して自動起動するサービスも作成しています。

対して、ラズパイゼロWは初期のアーキテクチャであるARMv6ですので、DockerコンテナにNode.jsを入れて常駐プログラムをデバッグしたり動かすのがかなり大変です。そこで常駐プログラムは昔ながらの
『Systemd』を利用することにします。

定点カメラである以上は、電源を入れたらSlackサーバーが自動で起動状態になっていることが好ましいことですので、今回はSystemdデーモンとしてSlackアプリを立ち上げるまでの設定を軽く解説します。


ラズベリーパイ4B 4GB 技適対応品

Raspberry Pi Zero W (ヘッダーハンダ付け済)

Raspberry Pi Zero 2 W 技適取得済

ラズベリーパイピコ

ラズベリーパイ カメラモジュールV2

ラズパイZere/Zero W用カメラFFCケーブル 2本セット(15ピン22ピン15cm)

RAVPower USB充電器 2ポート 24W 【最大出力5V,4.8A】

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

IoTの基本・仕組み・重要事項が全部わかる教科書

はじめに

そもそもラズパイゼロWはマシンスペックも低く、Dockerコンテナの中からではホストOSに接続した周辺機器の権限周りを設定するのも難儀になります。

低スペックなマシーンにわざわざ無理にDockerコンテナ化するとパフォーマンスもかなり落ちるので、ここは昔ながらのSystemdに登録するやり方を採用して、電源投入時にSlackアプリが立ち上がるようにした方が良い選択になります。

なお、ラズパイゼロの正規品はかなり価格が高騰して、通常の4〜5倍の価格で推移しております。

現状で少しでも価格を押さえてラズパイゼロを入手したい方は、サードパーティ製互換商品を検討することもできます。

参照|Semoic Raspberry Pi Zero W

また、ラズパイゼロWの後継機である
「ラズパイゼロ2」は既にリリースされいます。

最近ではネットショップなどで比較的入手できるようになっていますが、世界的な情勢不安が続いており半導体部品の供給が十分とは言えないため、まだまだ購入するには高価と感じてしまう状況が続いています。

こちらならSystemdでもDockerコンテナサービスでも常駐プログラム化を検討しても良いかも知れません。


ラズベリーパイ4B 4GB 技適対応品

Raspberry Pi Zero W (ヘッダーハンダ付け済)

Raspberry Pi Zero 2 W 技適取得済

ラズベリーパイピコ

ラズベリーパイ カメラモジュールV2

ラズパイZere/Zero W用カメラFFCケーブル 2本セット(15ピン22ピン15cm)

RAVPower USB充電器 2ポート 24W 【最大出力5V,4.8A】

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

IoTの基本・仕組み・重要事項が全部わかる教科書

Slackアプリ用のSystemdデーモンを仕込む

では早速電源投入後にSlackアプリが自動起動するようにSystemdサービスを自作していきます。

なお、ネット検索で「Systemd」とすると解説記事は山ほど出てきますので、一体どんなプログラムなのかの詳細は説明しませんが、ザックリと以下のようなものです。

            + Linux系OSの起動直後に走る主要な起動プロセスの一つ
+ Systemd自身のプロセスIDはinitプロセスと呼ばれ、
    常に1(PID=1)で実行状態になる
+ 登録しておいた複数のアプリケーションを
    子プロセス(ユニットプロセス)として起動することができる
        

ラッパースクリプトを準備する

まずは起動時に開始したい子プロセスの中身を記述したシェルスクリプト、通称ラッパースクリプトから作成してみましょう。

前回の内容で完成していたSlackアプリのプロジェクトフォルダ内に以下のstart-slack-app.shをラッパースクリプトとして置いておきます。

            #!/bin/bash

export SLACK_BOT_TOKEN=xoxb-xxxxxxx-xxxxxxx-xxxxxxxxxxxxx
export SLACK_APP_TOKEN=xapp-x-xxxxxxxx-xxxxxxxx-xxxxxxxxxxxxxxx

WORK_DIR=[index.jsが存在するフォルダまでの絶対パス]

node $WORK_DIR/index.js
        

Systemdで走らせるための子プロセス(ユニットプロセス)を作る際のポイントとしては、Systemdがルートユーザーの権限で起動しているプロセスですので、個別のユーザーの使っている
.bashrcなどに書かれた環境変数は読み込まれません。

したがって、Slackアプリで認証に使われるクレデンシャルが有効になっていないままnodeコマンドを実行してしまうと、当然Slackアプリは起動しないので、ラッパースクリプトの最初に
SLACK_BOT_TOKENSLACK_APP_TOKENを一時的な環境変数として読み込めるようにexportしておきます。

また、リソースファイルにアクセスする場合、ユーザーからの
$HOMEディレクトリは変化するので、相対パスでのコマンド引数からのファイル指定は曖昧になります。

このためルートユーザーからファイルの位置が分かるように絶対パスで引数に与えます。

serviceファイルの作成と設置

次に
「serviceファイル」(iniファイル)を作成します。

このファイルで、どのようなユニットプロセスを走らせるのかを記述するファイルで、
.serviceという拡張子で作成されるものになります。

自作のSystemdサービスを作る場所は決まっていて、
/etc/systemd/sytem/フォルダ以下にseri置いて置くことで、起動時にSystemdが自動で読み込んで子プロセスとして走らせるようになります。

試しに
/etc/systemd/systemを覗いてみると、

            $ ls -la /etc/systemd/system
-rw-r--r--  1 root root 1552 Jul 20  2021 autologin@.service
drwxr-xr-x  2 root root 4096 May  7  2021 bluetooth.target.wants
lrwxrwxrwx  1 root root   42 May  7  2021 dbus-fi.w1.wpa_supplicant1.service -> /lib/systemd/system/wpa_supplicant.service
lrwxrwxrwx  1 root root   37 May  7  2021 dbus-org.bluez.service -> /lib/systemd/system/bluetooth.service
lrwxrwxrwx  1 root root   40 May  7  2021 dbus-org.freedesktop.Avahi.service -> /lib/systemd/system/avahi-daemon.service
lrwxrwxrwx  1 root root   45 May  7  2021 dbus-org.freedesktop.timesync1.service -> /lib/systemd/system/systemd-timesyncd.service
lrwxrwxrwx  1 root root   34 May  7  2021 dhcpcd5.service -> /lib/systemd/system/dhcpcd.service
drwxr-xr-x  2 root root 4096 May  7  2021 dhcpcd.service.d
drwxr-xr-x  2 root root 4096 May  7  2021 getty.target.wants
drwxr-xr-x  2 root root 4096 May  7  2021 getty@tty1.service.d
drwxr-xr-x  2 root root 4096 May  7  2021 halt.target.wants
drwxr-xr-x  2 root root 4096 Mar  3 02:09 multi-user.target.wants
drwxr-xr-x  2 root root 4096 May  7  2021 network-online.target.wants
drwxr-xr-x  2 root root 4096 May  7  2021 poweroff.target.wants
drwxr-xr-x  2 root root 4096 May  7  2021 rc-local.service.d
drwxr-xr-x  2 root root 4096 May  7  2021 reboot.target.wants
drwxr-xr-x  2 root root 4096 May  7  2021 remote-fs.target.wants
drwxr-xr-x  2 root root 4096 Feb  6 05:23 sockets.target.wants
lrwxrwxrwx  1 root root   31 Jul 20  2021 sshd.service -> /lib/systemd/system/ssh.service
drwxr-xr-x  2 root root 4096 May  7  2021 sysinit.target.wants
lrwxrwxrwx  1 root root   35 May  7  2021 syslog.service -> /lib/systemd/system/rsyslog.service
drwxr-xr-x  2 root root 4096 May  7  2021 timers.target.wants
        
みたいに既にOSデフォルトで登録されているユニットサービスが沢山あるようです。

ちなみに
[⭕⭕.service.d]という名前のフォルダ作ってから、その中に[⭕⭕.service]の中身を入れることでもsystemdがそのファイルを認識してくれます。

このservice.dファイルを使うことで一つのユニットプロセスが使うリソースファイルをまとめて整理できるので、
/etc/systemd/system直下をごちゃごちゃと汚さずに済みます。

他はファイルリンクを使ってserviceファイルごと別の場所に置くことも可能です。

今回はあまり良い方法ではありませんが、大したserviceファイルではありませんので、
/etc/systemd/system直下に置きます。

まずは以下のようにserviceファイルを
slack-cam.serviceを作成します。

            [Unit]
Description=Slack Remoted Camera Service
After=network-online.target local-fs.target
ConditionPathExists=/root

[Service]
Type=simple
User=root
Group=root
Restart=no
ExecStart=[ラッパースクリプトが存在するフォルダまでの絶対パス]/start-slack-app.sh

[Install]
WantedBy=multi-user.target
        
これを/etc/systemd/systemへ移動します。

            $ sudo mv slack-cam.service /etc/systemd/system/
$ sudo chown root:root /etc/systemd/system/slack-cam.service
$ sudo chmod 644 /etc/systemd/system/slack-cam.service
$ ls -la /etc/systemd/system/ | grep slack-cam
-rw-r--r--  1 root root  482 Mar  3 02:48 slack-cam.service
        
移動した後は、ルートユーザーに所有権と実行権限の書き換えも済ませます。

起動テスト

まずは追加したサービスの設定ファイルを読み込んでみます。

            $ sudo systemctl daemon-reload
        
でユニットプロセスを手動で走らせてみましょう。

            $ sudo systemctl start slack-cam
        
内部で起動完了するまで少し待ってから、プロセスの状態を確認してみます。

            $ systemctl status slack-cam
● slack-cam.service - Slack Remoted Camera Service
   Loaded: loaded (/etc/systemd/system/slack-cam.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2022-03-03 03:07:09 GMT; 24h ago
 Main PID: 426 (start-slack-app)
    Tasks: 12 (limit: 725)
   CGroup: /system.slice/slack-cam.service
           ├─426 /bin/bash /*****************/start-slack-cam.sh
           └─430 node /*****************/index.js

Mar 03 03:07:46 raspberrypi start-slack-app.sh[426]: ⚡️ Bolt app is running!
        
で正常に動作しているようなら、次に常駐プログラムとして登録していきます。

Systemdサービスの有効化

上記までで常駐プログラム化のスタンバイはOKですので、起動時に立ち上がるようにします。

            $ sudo systemctl enable slack-cam
        
として常駐化が有効になります。

後は再起動してバックグラウンドでユニットプロセスが起動状態になれば完了です。

なお常駐化を無効化したい場合には、

            $ sudo systemctl disable slack-cam
        
として登録を解除もできます。


ラズベリーパイ4B 4GB 技適対応品

Raspberry Pi Zero W (ヘッダーハンダ付け済)

Raspberry Pi Zero 2 W 技適取得済

ラズベリーパイピコ

ラズベリーパイ カメラモジュールV2

ラズパイZere/Zero W用カメラFFCケーブル 2本セット(15ピン22ピン15cm)

RAVPower USB充電器 2ポート 24W 【最大出力5V,4.8A】

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

IoTの基本・仕組み・重要事項が全部わかる教科書

まとめ

今回はラズパイゼロWで特定のプログラム常駐化させたい場合に利用するSystemdの使い方をおさらいしていきました。

電源投入すると監視カメラが立ち上がるように出来るだけでも、グッと市販の監視カメラっぽい動作になると思います。

参考サイト

自作したシェルスクリプトを Linux の systemd サービスとして起動する方法

systemdを用いたプログラムの自動起動

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

電子工作を身近に知っていただけるように、材料調達からDIYのハウツーまで気になったところをできるだけ細かく記事にしてブログ配信してます。