ブログ

Armadillo Base OS:Debianコンテナ内のアプリケーションをsystemdで管理する

at_takuma.fukuda
2023年12月19日 13時16分

はじめに

Armadillo Base OSのコンテナアプリケーションは、
コンテナ起動時に指定したコマンドを実行するものとなっています。
アプリケーションにおいて実行させたい処理をこのコマンドによって実行させます。
実行させたい処理が複数ある場合や、条件分岐などが必要な場合は、
シェルスクリプトなどでそれらを制御する管理プロセスを実装し、
この管理プロセスをコンテナ起動時にコマンドで実行させます。

簡単なものであれば自身で管理プロセスを実装することもできますが、
複数のプロセスの動作順序の管理など処理内容が複雑になると、
開発工数を消費したり不具合を招くこともあります。
そこで、既存のソフトウェアを活用することで、ここにかかるコスト・リスクの低減を図ります。

この記事ではDebianコンテナ内でsystemdを管理プロセスとして動作させ、
メインアプリケーションをsystemdで管理・実行させる方法を紹介します。

手順紹介

メインアプリケーションの実装

まず、メインアプリケーションを実装します。
今回は、周辺のBLEデバイスをスキャンして、MACアドレスなどを出力するプログラムを実装します。
このプログラムはpythonでbluepyを使って実装します。
コードは以下の通りです。
scanner.py

from bluepy import btle
 
scanner = btle.Scanner(0)
devices = scanner.scan(30.0)
for device in devices:
  print(f'MAC Address: {device.addr}')
  print(f' Address type : {device.addrType}')
  print(f' RSSI : {device.rssi}')
  print(f' Advertising data : ')
  for (adTypeCode, description, valueText) in device.getScanData():
    print(f' {description} : {valueText}')

*下記Webページに掲載されていたサンプルプログラムを参考にしたものです。
bluepyで始めるBluetooth Low Energy(BLE)プログラミング

このpythonコードを実行して、テキストに日時と結果を出力するシェルスクリプトを作成します。
main.sh

#!/bin/sh
date >> /root/volumes/scanlog.txt
python3 /usr/local/bin/scanner.py >> /root/volumes/scanlog.txt

メインアプリケーションはこれで完成です。

サービスの定義

実装したメインアプリケーションを、systemdの管理するサービスとして動作させるための定義を行います。
定義はユニットファイルと呼ばれるファイルによって行います。
サービスの名称・実行タイミング・処理内容などを定義します。
ユニットファイルの詳しい内容については、下記などが参考になります。
Armadillo-X1, Armadillo-IoT G3/G3L: systemdでアプリを自動起動する方法(その1)
先ほど作成したmain.shが/usr/local/bin/に格納されている想定で、これを実行するサービスを以下のように定義します。
blescanner.service

[Unit]
Description = blescanner daemon
Requires = bluetooth.target
 
[Service]
ExecStart = /bin/sh /usr/local/bin/main.sh
Restart = always
Type = simple
 
[Install]
WantedBy = default.target

bluepyの機能を使うにはbluetoothサービスが動作している必要があるため、
下記のようにbluetoothサービスが動作していることをサービス起動の必須条件としています。

Requires = bluetooth.target

またそのまま処理を実行すると、一度実行して終わりになってしまうため、

Restart = always

で、サービスを終了ごとに再起動させて何度も実行させるものとしています。

コンテナイメージのビルド

ここまで作成したファイルを元にコンテナを構築します。
コンテナ構築のためのDockerfileを以下の通り作成します。
各ファイルの配置や、実行権限の設定、必要なライブラリのインストールを実行するとともに、
定義したサービスをsystemdで実行させるための設定も行っています。
Dockerfile

#Armadillo-IoT G4の場合
ARG arch=arm64v8
#Armadillo-IoT A6E/Armadillo-640の場合
ARG arch=arm32v7
 
FROM docker.io/${arch}/debian:bullseye-slim
#sytemdのインストール(必須)
RUN apt update && apt -y upgrade && apt -y install systemd
#BluetoothとPythonを動作させるためのパッケージインストール(内容に応じて行う)
RUN apt -y install dbus bluez python3 python3-pip build-essential libglib2.0-dev
RUN pip3 install bluepy
 
COPY scanner.py /usr/local/bin/
COPY main.sh /usr/local/bin/
COPY blescanner.service /etc/systemd/system/
RUN chmod +x /usr/local/bin/main.sh && systemctl enable blescanner

このDockerfileとその他に作成したファイルを同じディレクトリに配置し、以下のようにpodman buildコマンドでコンテナイメージをビルドします。
以下の例ではコンテナイメージ名をblescannerとしています。

[armadillo ~]# podman build -t localhost/blescanner:latest .

コンテナ実行

作成したコンテナイメージからコンテナを作成・実行して動作を確認します。
Armadillo Base OSでは/etc/atmark/containers/ディレクトリの下に定義ファイルを作成することで、
Armadillo起動時にコンテナが自動的に作成・実行されます。
今回の定義ファイルは以下のものとします。
debian_ble.conf

set_image localhost/blescanner:latest
#BLEデバイスを使用するための権限設定を行います。
add_args --cap-add=NET_ADMIN
set_network host
#出力結果をコンテナ外から確認できるよう、ホストOSのディレクトリをマウントします。
add_volumes /var/app/volumes:/root/volumes
#コンテナ起動時にsystemdを実行するよう設定します。
set_command /lib/systemd/systemd

このファイルを作成後、persist_fileコマンドで永続化保存し、Armadilloを再起動すると、コンテナが自動実行されます。
コンテナ内でサービスが実行されているか否かは以下のコマンドで確認することができます。

[armadillo ~]# podman exec -ti blescanner systemctl status blescanner

また、今回のアプリケーションについては、以下のコマンドで実行結果がファイルに出力されていることを確認できます。

[armadillo ~]# cat /var/app/volumes/scanlog.txt

正常にサービスが実行されていない場合は、定義ファイルやアプリケーションの処理などに問題がある可能性があるので、切り分け調査を行ってみてください。