デバイスコネクターの開発
measurementプロジェクトのアプリケーション開発における、デバイスコネクターの開発について説明します。
measurementプロジェクトのデバイスコネクターはDockerコンテナ上で動作するため、以下の点に注意して開発する必要があります。
- 依存ライブラリのバージョン
デバイスコネクターが依存するライブラリのバージョンが、ビルド環境と実行環境で異なる場合、実行時にエラーや予期しない挙動が発生する可能性があります。 例えば、デバイスコネクターがglibcに依存する場合、ubuntu:22.04でビルドしたバイナリは、ubuntu:18.04ではglibcバージョンの不一致により実行することができません。
この問題を避けるため、デバイスコネクターは実行環境のDockerイメージと同じディストリビューションでビルドすることを推奨します。
- アーキテクチャの違い
コンパイルが必要なアプリケーションの場合、エッジコンピューターのアーキテクチャ向けにクロスビルドが必要です。
また、Terminal System 2のデバイスコネクターとして、以下の要件が必要です。
- intdash Edge Agent 2とのプロセス間通信
デバイスコネクターは、intdash Edge Agent 2とプロセス間通信をする際に、iscp-v2-compatフォーマット(または、非推奨のlogger-msgフォーマット)でデータを送受信する必要があります。 詳細については、 intdash Edge Agent 2 デベロッパーガイド を参照してください。
- 環境変数による設定
Terminal System APIのデバイスコネクター設定でデバイスコネクターに設定値を与える場合、環境変数により設定値を入力できるようにする必要があります。
推奨する開発方法
上記の要件を満たすデバイスコネクターを開発するために、以下の開発方法を推奨します。
アプトポッド製のデバイスコネクターdevice-connector-intdashを利用する
Device Connector Frameworkを利用し、カスタム開発部分を独自エレメントのプラグインとして開発する
この方法を選択すると、以下のメリットがあります。
上記の要件を満たすデバイスコネクターを容易に開発できます
環境変数による設定読み込み、スレッド管理などの基本機能や、intdash用のデータを扱う際に便利な機能を再利用できます
カスタム開発部分のみをプラグイン化することで、カスタム開発部分のみを構成管理でき、変更影響を少なくすることができます
一方、以下の制約があります。
device-connector-intdash(intdash Edge Agent 2)のシステム要件を満たさない環境では正しく動作しない可能性があります
実行環境にdevice-connector-intdashの依存ライブラリが必要です
device-connector-intdashが利用しているRustバージョンと同じバージョンでプラグインをビルドする必要があります
この方法で開発が必要となるファイルは、以下の2つです。
- 独自エレメントのプラグイン
Device Connector Frameworkを利用し、独自エレメントのプラグイン(共有ライブラリファイル、.so形式)を開発します。 カスタムインベントリを送信したい場合は、カスタムインベントリのディレクトリにJSON形式のインベントリデータを出力するようにします。
- パイプライン設定ファイル
デバイスコネクターで行いたい処理をエレメントの組み合わせで定義したファイルを用意します。 Terminal System APIのデバイスコネクター設定で設定値を与える場合、環境変数を
$(VARIABLE_NAME)
の形式で記述します。
注釈
Device Connector Frameworkおよびdevice-connector-intdashの詳細については、 デバイスコネクターデベロッパーガイド を参照してください。
以降の手順で、推奨する開発方法でデバイスコネクターを開発する方法を説明します。
ツールのインストール
推奨する開発方法では、RustおよびDockerのインストールが必要です。
テンプレートのビルド
独自エレメントのプラグインは、 Device Connector Template を利用して開発します。
プロジェクトを作成します。 プロジェクト名はプラグインのファイル名で使用されます。ここでは
custom
を指定して説明します。$ cargo install cargo-generate $ cargo generate --git https://github.com/aptpod/device-connector-template.git Project Name : custom
作成したプロジェクトに移動します。
$ cd custom
クロスビルド環境のDockerイメージをビルドします。
$ docker build -t rust-cross-builder .
クロスビルド環境のコンテナを起動します。
$ docker run --rm -it -v ${PWD}:/usr/local/src rust-cross-builder
ターゲットアーキテクチャを指定してサンプルのデバイスコネクターをビルドします。
エッジコンピューターのアーキテクチャを指定してビルドしてください。複数のアーキテクチャをサポートする場合は、それぞれビルドしてください。
# cargo build --release --target aarch64-unknown-linux-gnu
# cargo build --release --target armv7-unknown-linux-gnueabihf
# cargo build --release --target x86_64-unknown-linux-gnu
注釈
エッジコンピューターのアーキテクチャは、エッジコンピューターで
uname -m
コマンドを実行すると確認できます。 ターゲットアーキテクチャとuname -m
コマンドの対応関係は以下のとおりです。aarch64-unknown-linux-gnu:
aarch64
armv7-unknown-linux-gnueabihf:
armv7l
x86_64-unknown-linux-gnu:
x86_64
target/<ターゲットアーキテクチャ>/release
に、プラグインファイル(共有ライブラリ)libdc_custom.so
が出力されることを確認します。
テンプレートのビルドが確認できたら、独自エレメントを開発します。
独自エレメントの開発
Device Connector Frameworkを利用した一般的な独自エレメントの開発については、 デバイスコネクターデベロッパーガイド を参照してください。
Terminal System 2の推奨開発方法では、以下の点を考慮する必要があります。
クロスビルド環境のカスタマイズ
クロスビルド環境の Dockerfile
を必要に応じてカスタマイズします。
- プラグインのRustバージョンをdevice-connector-intdashと合わせる
Device Connector Frameworkの制約により、device-connector-intdashとプラグインのRustバージョンを合わせる必要があります。 クロスビルド環境のRustバージョンは、 Dockerfileの
RUST_TOOLCHAIN
で設定することが可能です。RUST_TOOLCHAIN
のデフォルト設定値は、最新のdevice-connector-intdashのバージョンに合わせて更新されるため、最新バージョンを利用する場合はデフォルト設定のままで構いません。設定するべきdevice-connector-intdashのRustバージョンは、デバイスコネクターデベロッパーガイド を参照してください。 実行環境で利用可能なdevice-connector-intdashのバージョンは、アプトポッドの公開リポジトリの設定後に以下のコマンドで確認が可能です。
表示例:
$ apt policy device-connector-intdash device-connector-intdash: Installed: 2.0.0 Candidate: 2.0.0 Version table: *** 2.0.0 500 500 https://repository.aptpod.jp/intdash-edge/linux/ubuntu focal/stable amd64 Packages 100 /var/lib/dpkg/status
- ベースイメージの選択および依存パッケージの追加
必要に応じてクロスビルド環境のDockerfileを編集し、
FROM
で使用するベースイメージを指定します。 device-connector-intdashの動作要件を満たしている、debian
やubuntu
をベースイメージに選択してください。 特にこだわりがなければ、 device-connector-intdashの動作要件を満たしているubuntu
の最新バージョンを推奨します。また、独自エレメントのビルドに必要な依存パッケージがある場合、クロスビルド環境のDockerfileを編集してパッケージを追加してください。
Dockerfileを変更した場合は、クロスビルド環境のDockerイメージをビルドして、デバイスコネクターを再ビルドしてください。
カスタムインベントリの送信
カスタムインベントリを送信したい場合は、カスタムインベントリのディレクトリにJSON形式のインベントリデータを出力するように実装してください。
テンプレートのソースコードを修正します。
hello-src
で、設定値の文字列をインベントリとして送信する場合、nextで以下のように/var/run/device-inventory/custom.d
ディレクトリにファイルを作成し、 設定値の文字列をJSON形式のデータで出力する処理を追加してください。fn next(&mut self, pipeline: &mut Pipeline, _receiver: &mut MsgReceiver) -> ElementResult { pipeline.check_send_msg_type(0, || MsgType::from_mime("text/plain").unwrap())?; sleep(Duration::from_millis(100)); let mut buf = pipeline.msg_buf(0); buf.write_all(self.conf.text.as_bytes())?; + let mut file = std::fs::File::create("/var/run/device-inventory/custom.d/custom-text")?; + let data = format!(r#"{{"text": "{}"}}"#, self.conf.text.as_str()); + file.write_all(data.as_bytes())?; + Ok(ElementValue::MsgBuf) } }
クロスビルド環境のコンテナを起動して、サンプルのデバイスコネクターをビルドします。
$ cd custom $ docker run --rm -it -v ${PWD}:/usr/local/src rust-cross-builder
# cargo build --release --target aarch64-unknown-linux-gnu # cargo build --release --target armv7-unknown-linux-gnueabihf # cargo build --release --target x86_64-unknown-linux-gnu
注意
カスタムインベントリを送信する場合、ホストのカスタムインベントリのディレクトリをコンテナにバインドマウントする必要があります。
警告
Menderサーバーは、基本的にはインベントリの削除に対応していません。 古いインベントリが残り続けることを防ぐため、インベントリのキー名には動的に増減する名称を避ける必要があります。
デバイスのインベントリを削除したい場合は、一度デバイスを削除し、デバイス認証を再実施する必要があります。
カスタムインベントリの詳細については、 device-inventory を参照してください。
パイプライン設定ファイルの作成
デバイスコネクターで行いたい処理をエレメントの組み合わせで定義したファイルを用意します。 推奨する開発方法では、以下の2点を考慮して作成してください。
- プラグインの設定
plugin_files
にプラグインファイルへのパスを指定します。 本ガイドでは、ビルドしたプラグインは Dockerイメージの作成 でコンテナの/usr/local/lib
に配置されます。- 設定値の環境変数
Terminal System APIのデバイスコネクター設定で設定値を与える場合、環境変数を
$(VARIABLE_NAME)
の形式で記述します。
パイプライン設定ファイルの作成例を以下に挙げます。(この例は次章 Dockerイメージの作成 でも引き続き使用します。)
プロジェクトディレクトリに
conf
ディレクトリを作成し、移動します。$ cd custom $ mkdir conf $ cd conf
confディレクトリに
custom-text-hexdump.yml
ファイルを以下の内容で作成します。 この設定ファイルは、本ガイドでの動作確認のために利用します(本番運用時は不要です)。plugin: plugin_files: - /usr/local/lib/libdc_custom.so tasks: - id: 1 element: hello-src conf: text: $(DC_TEXT) - id: 2 element: iscp-v2-compat-filter from: [[1]] conf: timestamp: stamp: clock_id: CLOCK_MONOTONIC convert_rule: string: name: custom_text - id: 3 element: hexdump-sink from: [[2]]
これは、環境変数
DC_TEXT
で指定された文字列を、string型のiscp-v2-compatフォーマットに変換し、16進数でダンプ出力するパイプラインになっています。プラグインファイル
libdc_custom.so
をロードしますテンプレートのプラグインに含まれる
hello-src
およびhexdump-sink
エレメントを利用しますdevice-connector-intdashに含まれる
iscp-v2-compat-filter
エレメントを利用します
次に、
custom-text.yml
ファイルを作成します。 この設定ファイルは、intdash Edge Agent2にデータを送信する際に利用します。plugin: plugin_files: - /usr/local/lib/libdc_custom.so tasks: - id: 1 element: hello-src conf: text: $(DC_TEXT) - id: 2 element: iscp-v2-compat-filter from: [[1]] conf: timestamp: stamp: clock_id: CLOCK_MONOTONIC convert_rule: string: name: custom_text - id: 3 element: print-log-filter from: [[2]] conf: duration_ms: 10000 tag: $(DC_PRINT_LOG_FILTER_CONF_TAG) output: stderr - id: 4 element: file-sink from: [ [3] ] conf: path: $(DC_FILE_SINK_CONF_PATH)
環境変数
DC_TEXT
で指定された文字列を、string型のiscp-v2-compatフォーマットに変換し、 環境変数DC_FILE_SINK_CONF_PATH
で指定されたFIFOに出力するパイプラインです。 また、print-log-filter
で、10秒ごとに iscp-v2-compat-filterフォーマットのデータのメッセージ数およびバイト数をログ出力しています。device-connector-intdashに含まれる
print-log-filter
およびfile-sink
エレメントを利用します
次章では、作成したプラグインおよびパイプライン設定ファイルを含めたDockerイメージを作成する方法を説明します。