Container AdamAppの基本構成と開発指針
1. 初めに
Container AdamAppに対応したi-PRO Camera SDKでは、アプリの構成をDocker compose構成ファイルに記述することで、様々な構成のコンテナをi-PROカメラ内で動作させることができます。これにより新規機能拡張ソフトウェアをDockerコンテナの形で作成できるようになるほか、すでに他のサーバーやデバイス上で動作しているDockerコンテナが開発済みの場合は、本ドキュメントにしたがって移植を行うことで、簡単にカメラ上で動作させることが可能です。本ドキュメントでは、SDKに含まれるdocker_multi_imagesサンプルアプリを例にして複数コンテナ構成のContainer AdamAppを作成する方法を説明します。
2. 概要
2.1 ユーザー別のアプリ構成選択の指針
既存のAdamApp、AzureIoT用のContainer AdamApp及びext版のContainer AdamAppのそれぞれどれを選択すべきかについては、こちらをご参照ください。
ext形式Container AdamAppは、コンテナの構成をDocker composeの設定ファイル (docker-compose.yaml) で指定することが可能です。docker-compose.yamlファイルでは、サービス名を複数記載することで、複数のコンテナを起動できます。
以下に従来にAdamAppとContainer AdamAppの構成の違いの概念図を示します。
上記は一つの機能拡張ソフトウェア (ext形式のバイナリが一つ) の中で複数のコンテナを動作させる場合の概念図ですが、一方で新Xシリーズカメラでは、複数のアプリをインストールすることが可能なため、独立した複数のアプリを同時に動作させることも可能です。
用途によってどのような構成を選択するかの指針を以下に示します。
番号 | ユースケース | アプリの構成 | 概念図 |
---|---|---|---|
1 | すでにi-PRO CAMERA SDKを使用して開発したアプリをコンテナ化したい場合 | 既存のアプリをそのままコンテナ化した、一つのコンテナ構成を持つ一つのアプリ | |
2 | i-PROカメラ以外のデバイス向けに開発済みのAIアプリを、i-PROカメラ向けに移植したい場合 | 既存のアプリのAI機能や、映像取得部分をADAM APIに置き換えた、一つのコンテナの構成を持つ一つのアプリ | |
3 | i-PROカメラ以外のデバイス向けに開発済みの、AI機能を持たないアプリを簡単にi-PROカメラ向けに移植したい場合 | i-PROカメラ向け管理機能を持ったコンテナと、既存のアプリが動作するコンテナを含む、二つのコンテナの構成を持つ一つのアプリ | |
4 | i-PROカメラ以外のデバイス向けに開発済みの、OSS等複数のコンテナ構成を持つアプリをi-PROカメラ向けに移植したい場合 | i-PROカメラ向け管理機能を持つコンテナと、既存の複数のコンテナ構成を持つ一つのアプリ | |
5 | アプリ間で直接通信を行うことがなく、開発元も異なる関連性の低い二つのアプリをi-PROカメラ向けに移植したい場合 | 二つのアプリ | |
6 | ADAM APIを使用したいアプリが複数ある場合 | 二つのアプリ |
2.2 複数コンテナ構成でアプリを開発する場合の構成
SDKに含まれるdocker_multi_imagesは、2.1章のユースケース3や4を選んだ場合に参考となるサンプルアプリです。docker_multi_imagesサンプルアプリは2つのDockerイメージから構成されています。
docker_multi_images イメージ
カメラ本体からアプリの開始停止やキープアライブメッセージの応答を行うために存在します。本ドキュメントでは「メインイメージ」と呼びます。また、このイメージから生成されたコンテナを「メインコンテナ」と呼びます。サンプルアプリでは、イベントループを回して待機のみ実施しています。i-PRO CAMERA SDKでビルドします。web イメージ
DockerHubで公開されている 軽量版のnginx をベースにデフォルトの設定ファイル (default.conf) のみを置き換えたイメージとなります。本ドキュメントでは「サブイメージ」と呼びます。また、このイメージから生成されたコンテナを「サブコンテナ」と呼びます。nginxのTCP 80ポートを外部にTCP 8081ポートとして公開し、外部機器からのhttpリクエストを受け付けます。Container AdamAppを作成する際には、事前にDockerイメージとしてビルドされている必要があります。
既存のコンテナをi-PROカメラで動作させたい場合、docker_multi_imagesイメージをカメラからの管理用として新たに追加することで、既存コンテナは少ない変更量でカメラ上で動作させることができます。
2.3 移植にあたっての考慮事項
i-PROカメラ上で既存コンテナを動作させる場合、主に以下三点を考慮する必要があります。
RAM / ROM / CPUリソースが足りるか
データのストレージは必要か
i-PROカメラのセキュリティポリシーに合致しているか
ADAM APIを使用するコンテナは一つだけか
以下ではこれらの内容を説明します。
2.3.1 RAM / ROM / CPUリソース について
CV52カメラが機能拡張アプリケーションで使用できるリソースは i-PROカメラへのソフトウェアインストール条件 - チュートリアル・FAQ - Development Partner Portal をご参照ください。
移植対象のアプリがこの制限内で動作できることをご確認ください。
RAM/CPUの制限はcgroupsによって行われています。RAM使用量が制限値を超えた場合、OOM Killerによってアプリが強制終了します。
2.3.2 データのストレージについて
ボリュームをマウントすることで、カメラ内部のフラッシュメモリへデータの書き込みを行うことができます。ただし、フラッシュメモリには書き込み回数に上限があるため、頻繁にデータの書き込みを行う場合は、SDカードを活用ください。
SDカードにデータベースSQliteを構築するとも可能です。サンプルアプリsqlite_appで実装されています。
2.3.3 セキュリティポリシーについて
Container AdamAppに関するセキュリティポリシーの詳細は アプリの開発と動作確認方法(Container Adamapp編) - チュートリアル・FAQ - Development Partner Portal (i-pro.com) をご覧ください。
移植に関して特に考慮する内容を説明します。
コンテナはroot権限で動作させることはできません。
カメラ内ではuid 1000、gid 1000のユーザー権限でアプリが動作します。コンテナはread onlyでマウントされます。
コンテナ内に書き込みを行うことはできません。既存のアプリがコンテナ内に書き込みを行っている場合、一時的なデータであればtmpfs、永続的なデータであればボリュームを別途マウントし、そちらに書き込む必要があります。--previledgedなどのセキュリティを緩和するオプションは使用できません。
カメラ内から直接外部のコンテナレジストリよりイメージをpullすることはできません。必要なイメージは開発用PC上でpull、ビルドし、extファイル内に含まれる必要があります。
コンテナ内がread onlyでマウントされることによるデータディレクトリの影響について
ADAM APIでは、フラッシュROM上のdataディレクトリのパスを返却するAPIとして、ADAM_GetAppDataDirPath が用意されていますが、Container AdamAppの場合、このディレクトリは読み取り専用となり、書き込むことができません。データの書き込みを行いたい場合はボリュームをご使用ください。
2.3.4 ADAM APIの使用制限
2.3.4.1 ADAM APIを使用することのできるコンテナ
Container AdamAppに複数のコンテナが含まれている場合、ADAM APIが使用できるコンテナはメインコンテナのみとなり、サブコンテナからは使用できません。
カメラの機能を使用したい場合は、メインイメージ内に実装し、カメラに依存しない汎用的な機能をそのままカメラ上で動かしたい場合はサブイメージ内に実装することをお勧めします。
メインイメージ・サブイメージ間のデータ共有は、3.4章で説明します。
2.3.4.2 ADAM APIで取得できるディレクトリパス
AdamApp、Container AdamAPp、Container AdamApp for Azure IoTで取得できる各種ディレクトリパスは下表のようになります。 2.3.3でも言及しましたが、Container AdamAppにおいて、ADAM_GetAppTmpDirPathで取得できるパスは読み取り専用領域となります。
また、ADAM_GetAppTmpDirPathで取得できるディレクトリはホスト側(カメラ本体)と共有されますので、ホスト側からアクセスされたくないデータを一時保管する際はdocker-compose.yamlのtmpfsセクションで定義した領域をご使用ください。
| AdamApp | Container AdamApp | Container AdamApp for Azure IoT |
---|---|---|---|
ADAM_GetAppTmpDirPath | /dev/shm/Adamapp/[アプリ固有ID] | /dev/shm/Adamapp/[アプリ固有ID] | /tmp/local/appdata |
ADAM_GetAppDataDirPath | /app/data | /app/data | /ai_data |
3.開発手順
3.1 プロジェクトの作成
プロジェクトディレクトリの準備
SDKのサンプルアプリに含まれる iPRO_CAMERA_SDK/src/adamapp/docker_multi_images をコピーし、任意の名前にリネームします。ディレクトリ名がメインイメージのイメージ名と一致するとわかりやすいため、全て小文字にすることを推奨します。
container/docker-compose.yaml に含まれる「docker_multi_images」という文字列をメインイメージの名前に一括変換します。
メインイメージのバイナリ (multiImages) は特に変更する必要はありません。変更する場合は、Configuration.txt及びMakefileの編集も実施する必要が有ります。
アプリの情報記載
configuration.txtを開き以下の項目を編集します。
アプリバージョン名
カメラブラウザの管理画面上に表示されるバージョン情報となります。メインイメージのタグ名と合わせるとわかりやすいです。アプリ名
カメラブラウザの管理画面上に表示されるアプリ名となります。各言語で記述することが可能です。リソース関連情報
アプリが使用するROM/RAM/CPU使用率 (申告値)を記載します。インストール時に他のアプリで申告された値の合計が制限を超えていないかチェックするために使用されます。全アプリの申告値の合計が制限を超える場合、アプリはインストールに失敗します。ライセンス関連情報
開発開始時は初期値のまま使用ください。開発完了時、i-PROへ連絡し、割り当てられたFUNC IDへ置き換えてください。
3.2 サブイメージ (移植対象イメージ) の準備
既存のコンテナイメージを移植する場合はそのイメージをサブイメージとして作成します。
SDKのビルドスクリプトではサブイメージをビルドしませんので、事前に開発者自身でイメージを用意する必要があります。
別途DockerfileやDocker Composeを利用してサブイメージをビルドします。ビルド時のアーキテクチャ (プラットフォーム) はarm64を指定してください。
以下は、docker_multi_images内に含まれるnginxのイメージの準備を例に説明します。
docker_multi_images/web ディレクトリ以下にnginxのイメージに必要なファイルが含まれています。
web ディレクトリ以下に移動します。
cd [iPRO_CAMERA_SDKディレクトリ]/src/Aadamapp/[アプリディレクトリ]/web
docker imageをビルドします。
docker build -t web:0.0.1-arm64v8 .
dockerイメージがビルドされ開発環境に存在することを確認します。
docker images
出力例
3.3 docker-compose.yaml の編集
docker-compose.yaml内にサブイメージに関する情報を記載します。 docker-compose.yamlの記述方法自体については、 https://docs.docker.jp/compose/compose-file/index.html などをご参照ください。
services キーの子レベルにサブイメージの情報を追加します。 サンプルアプリではすでに記載されていますのでその内容を説明します。
webサービスについての全体の記載は以下となります。
images:
ここには3.2で作成したイメージ名とタグを指定します。ここで指定したイメージが存在しない場合、アプリのビルドスクリプトは失敗します。networks:
コンテナ間で通信したい場合、同じネットワークを指定する必要があります。restart:
コンテナが終了したときにどのように復旧するかを指定します。ext形式Dockerの場合、メインコンテナはDockerの仕組みを使用せずにカメラファームウェアによって監視されるため、noを指定することで、適切に再起動します。一方サブコンテナはカメラファームウェアから監視されませんので、実動作に合わせて設定します。ports:
サブイメージが外部から接続できるポートを公開する場合、[カメラ側]:[コンテナ側]の書式で記載します。volumes:
ボリューム、バインドマウントを記載します。
ボリュームは、サービス名(コンテナ名)と同名のボリューム名のもののみ作成できます。匿名ボリュームは作成できません。
メインコンテナの場合、ボリュームの”target”は “/ai_data” を指定する必要があります。サブコンテナにはこの制限はありません。
ここに定義されているボリューム名は別途yamlファイルトップのvolumes: セクションにも記載する必要があります。
バインドマウントできるディレクトリパスには制限があります。
カメラ内部のフラッシュメモリへデータの書き込みが行われます。フラッシュメモリには書き込み回数に上限があるため、頻繁にデータの書き込みを行う場合は、tmpfsまたはSDカードを活用ください。tmpfs:
セキュリティポリシーによりコンテナ内には書き込めないため、/var以下などのアプリが一時的に保存するディレクトリがある場合はここに指定します。
nginxの場合、 /var/cache/nginx、/var/run 以下に書き込みますので、これらをtmpfs として指定しています。
カメラ内部のRAMへデータの書き込みが行われます。必須のパラメータ
以下パラメータはi-RPOカメラのセキュリティポリシーを満たすために付与が必要です。 このままコピー&ペーストしてください。ルートレベルのvolumesの記載
yamlファイルのルート (トップ) 以下のvolumes: セクションに、ボリューム名を記載します。
3.4 独自の機能を実装する
3.4.1 コンテナ間の通信やデータ共有
メインイメージ・サブイメージ間や、コンテナとカメラ間でデータをやり取りするには以下の方法があります。
volumeを使用する。
docker-compose.yamlに記載することでvolumeをコンテナ間で共有することができますのでこの中でデータをやり取りできます。ただしこの領域はFlashROM上となり、寿命に影響がありますので高頻度のデータのやり取りには向きません。共有が許可されているtmpfsを使用する。
ADAM_GetTmpDirPath() APIで取得できる領域はtmpfs上にあり、一時的なデータ保存用として利用できます。
サブコンテナからこの領域にアクセスするためには、docker-compose.yamlのサブイメージの記述内のvolumes: に以下を追加します。ただし、サブコンテナからはADAM_GetTmpDirPath()を呼ぶことができませんので、別途volumeを使う方法などでメインコンテナからパスを通知する必要があります。
HTTP経由で取得する。
Dockerでは各コンテナに仮想のIPアドレスが割り当てられるため、こちらを利用して、カメラ外と同様にWebAPIを呼ぶことができます。また、docker-compose.yamlのhostnameキーでドメイン名を指定すると、この名前で通信を行うこともできます。
メインコンテナでは、ADAMの仕組みとして、sendDataToAdamApplication WEB APIを使用して通信を行うことができます。この仕組みはカメラ本体がメインコンテナにデータを仲介する方法ですので、あて先はカメラ本体のIPアドレスとなります。
また、同様にカメラのCGIを利用してカメラ本体の設定値などを取得することができます。
3.4.2 サンプルアプリの実装例
docker_multi_imagesサンプルアプリではコンテナ間ネットワークのDNS機能を使用し、メインコンテナからコンテナ名でサブコンテナへhttpリクエストを出すサンプルコードを実装しています。${SDK_DIR}
/adamapp/docker_multi_images/main.cpp の response_by_html関数内で以下の様にcurlでリクエストを行うsystem関数を呼び出しています。 ここで “web” はdocker-compose.yamlに記載されているサービス名となります。
カメラブラウザの「ソフトウェア管理画面」に表示された、「Dockerマルチイメージ」アプリの「設定画面へ」ボタンを押下することで、このコードが呼び出され、webコンテナのindex.htmlの内容をそのままブラウザに表示します。
3.5 アプリのビルド
開発環境構築については下記を参照ください。
開発環境構築(Install development environment編) - Technology Partner - Confluence (atlassian.net)
アプリ開発方法やビルドについては下記を参照ください。
開発方法(how develop編) - Technology Partner - Confluence (atlassian.net)