Kinesis Video Streams Edge AgentをRaspberry PI上のDocker(Ubuntu)へデプロイして、ローカルのIPカメラの映像を送信してみました
1 はじめに
CX 事業本部 delivery部の平内(SIN)です。
先月、Kinesis Video Streams Edge Agent(以下、Edge Agent)がGAされたとアナウンスがありました。
Amazon Kinesis Video Streams エッジエージェントの一般提供を開始
Edge Agentは、Javaのプログラムとして提供されており、そのままデプロイして使用することもできますが、Greengrassのカスタムコンポーネントとしても利用可能です。 ドキュメントには、「Greengrass」と「それ以外」へのデプロイ方法として案内されています。
https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/edge.html
今回は、Raspberry PI上のDockerでUbuntu(18.04)を使用し、Greengrassを使用しない要領 (Run Amazon Kinesis Video Streams Edge Agent in non-AWS IoT Greengrass mode)を試してみました。
やってみた構成は、以下のようなイメージです。
Ubuntu(18.04)を使用した理由は、Edge Agentの対応OSが以下のようになっており、RasPI(ARM)で使用するためです。
https://docs.aws.amazon.com/ja_jp/kinesisvideostreams/latest/dg/edge-faq.html
2 IPカメラ
IPカメラは、TP-Link Tapo C200 を使用しました。
https://www.amazon.co.jp/gp/product/B07YG7RNF2/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
このカメラは、RTSPでの配信が可能になっています。
参考:Tapoを使用したRTSPライブストリーミングの利用方法
アカウントを設定することで、下記のようなURIでアクセス可能になります。
rtsp://ユーザー名:パスワード@IPアドレス:554/stream1
ユーザー名及び、パスワードを設定して、VLCプレーヤーでrtspによる接続を確認している様子です。
3 構築
Edge Agentの構築の手順は、以下の通りです。
(1) ダウンロード
(2) リソースの作成(CDK)
(3) モノの作成
(4) Dockerイメージの作成
(5) エージェントの設定
(1) ダウンロード
Edge Agentを使用するには、フォームに記入して、ダウンロードのURLをリクエストする必要があります。
ダウンロードした、ファイルは、12Mbyte程度の、1.1.0.tar.gzでした。1.1.0は、バージョンを表現しているため変化するものと思われます。
% ls -la *.tar.gz -rw-r--r--@ 1 sin staff 11888640 6 30 10:58 1.1.0.tar.gz
(2) リソース作成(CDK)
AWS側で必要なリソースを、CDKで作成しました。
- Kinesis Video Streams kvs-adge-agent-stream
- SecretManager kvs-adge-agent-secret
- Role kvs-adge-agent-role
- RoleAlias kvs-adge-agent-role-alias
- Policy (IoT Coore) kvs-adge-agent-policy
ここでは、Kinesis Video Stremasのストリーム及び、IPカメラのURI情報をSecret Managerで作成し、これらにアクセスするためのロールを作成しています。 ロールは、IoT Codeから証明書で利用(Authorizing Direct Calls)が可能なようにロールエリアスが設定されています。
※「mediaURI」は、IPカメラのURIにあわせて編集が必要です
import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import { aws_iam, aws_secretsmanager, aws_iot, aws_kinesisvideo, } from "aws-cdk-lib"; export class KvsEdgeAgentStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const tag = "kvs-edge-agent"; const mediaURI = "rtsp://user:password@192.168.1.48:554/stream1"; // 【編集必要】 const streamName = `${tag}-stream`; // Kinesis Video Streams const kvsStream = new aws_kinesisvideo.CfnStream(this, "KvsStream", { dataRetentionInHours: 2, name: streamName, }); // Secrets Manager const secretString = new aws_secretsmanager.Secret(this, "Secret", { secretName: `${tag}-secret`, secretObjectValue: { MediaURI: cdk.SecretValue.unsafePlainText(mediaURI), }, }); // Role const role = new aws_iam.Role(this, "Role", { roleName: `${tag}-role`, assumedBy: new aws_iam.ServicePrincipal("credentials.iot.amazonaws.com"), }); role.addToPolicy( new aws_iam.PolicyStatement({ resources: ["*"], actions: [ "cloudwatch:PutMetricData", "kinesisvideo:ListStreams", "iot:Connect", "iot:Publish", "iot:Subscribe", "iot:Receive", ], }) ); role.addToPolicy( new aws_iam.PolicyStatement({ resources: [`arn:aws:kinesisvideo:*:*:stream/${streamName}/*`], actions: [ "kinesisvideo:DescribeStream", "kinesisvideo:PutMedia", "kinesisvideo:TagStream", "kinesisvideo:GetDataEndpoint", ], }) ); role.addToPolicy( new aws_iam.PolicyStatement({ resources: [secretString.secretArn], actions: ["secretsmanager:GetSecretValue"], }) ); // RoleAlias const roleAlias = new aws_iot.CfnRoleAlias(this, "MyCfnRoleAlias", { roleArn: role.roleArn, roleAlias: `${tag}-role-alias`, }); // IoT Policy const cfnPolicy = new aws_iot.CfnPolicy(this, "IotPolicy", { policyDocument: { Version: "2012-10-17", Statement: [ { Effect: "Allow", Action: [ "iot:Connect", "iot:Publish", "iot:Subscribe", "iot:Receive", ], Resource: ["*"], }, { Effect: "Allow", Action: ["iot:AssumeRoleWithCertificate"], Resource: roleAlias.attrRoleAliasArn, }, ], }, policyName: `${tag}-policy`, }); } }
CDKをデプロイすると、Outputsに StreamARN と MediaUriSecretArn が出力されます。これらは、「(5)エージェント設定」で使用されます。
- StreamARN (Kinesis Video Staream に作成したストリームのARN)
- MediaUriSecretArn (SecretManagerに作成したシークレットのARN)
% cdk deploy ・・・略・・・ Outputs: KvsEdgeAgentStack.MediaUriSecretArn = arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:kvs-edge-agent-secret-UUWmql KvsEdgeAgentStack.StreamARN = arn:aws:kinesisvideo:ap-northeast-1:xxxxxxxxxxxx:stream/kvs-edge-agent-stream/1689011376458 ・・・略・・・
以下、参考までに、CDKで作成されたリソースです。
- Kinesis Video Streamsに作成されたストリーム
- Secret Managerに作成されたシークレット
- Kinesis Video Streams及び、Secret Managerにアクセスするためのロール
* ロールにアクセスするためのロールエリアス
- モノで使用するポリシー
(3) モノ作成
モノの作成は、証明書等の扱いがあるため、手動で作成しました。(Thing名は、kvs-adge-agent としています)
証明書に紐づけるポリシーは、「(2) リソースの作成(CDK)」で作成されたポリシーです。
作成されたモノのARNは、「(5)エージェントの設定」で使用します。また、ダウンロードした証明書は、「(4) Dockerイメージの作成」で使用します。
(4) Dockerイメージの作成
使用したのは、RaspberryPi 4B(4G) で、OSは、今年5月の最新版(2023-05-03) Raspberry Pi OS (64-bit) A port Debian Bullseye with the Respbeyy Pi Desktop (Compatible with Raspberry Pi 3/4/400)です。
$ cat /proc/cpuinfo | grep Revision Revision : c03112 $ uname -a Linux raspberrypi 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr 3 17:24:16 BST 2023 aarch64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Debian Description: Debian GNU/Linux 11 (bullseye) Release: 11 Codename: bullseye
また、下記を参考にDockerをインストールしました。
Raspberry Pi 4 に Docker と Docker Compose をインストールする
$ curl -fsSL https://get.docker.com -o get-docker.sh $ sudo sh get-docker.sh $ sudo usermod -aG docker pi $ docker -v Docker version 24.0.4, build 3713ee1
Dockerイメージを作成するために、以下のようにファイルを配置しています。
1.1.0.tar.gzは、「(1)ダウンロード」で取得したファイルで、同ディレクトリで解凍しています。 certsは、「(3)モノ作成」でダウンロードした証明書等です。
$ tree . . ├── 1.1.0 │ ├── al2 │ └── ubuntu │ ├── 18.04 │ │ └── arm │ │ ├── kvs-edge-agent.tar.gz │ │ └── sha256.sum │ └── 22.04 ├── 1.1.0.tar.gz ├── certs │ ├── AmazonRootCA1.pem │ ├── certificate.crt │ └── private.key └── Dockerfile
Dockerfile
FROM ubuntu:18.04 ENV EDGE_AGENT_VERSION 1.1.0 ENV CERT_DIR /certs ENV AWS_REGION ap-northeast-1 ENV AWS_IOT_CA_CERT $CERT_DIR/AmazonRootCA1.pem ENV AWS_IOT_CORE_CERT $CERT_DIR/certificate.crt ENV AWS_IOT_CORE_PRIVATE_KEY $CERT_DIR/private.key ENV AWS_IOT_CORE_CREDENTIAL_ENDPOINT xxxxxxxxxxxx.credentials.iot.ap-northeast-1.amazonaws.com ENV AWS_IOT_CORE_DATA_ATS_ENDPOINT xxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com ENV AWS_IOT_CORE_ROLE_ALIAS kvs-edge-agent-role-alias ENV AWS_IOT_CORE_THING_NAME kvs-edge-agent ENV GST_PLUGIN_PATH /kvs-edge-agent/KvsEdgeComponent/artifacts/aws.kinesisvideo.KvsEdgeComponent/$EDGE_AGENT_VERSION/ ENV LD_LIBRARY_PATH /kvs-edge-agent/KvsEdgeComponent/artifacts/aws.kinesisvideo.KvsEdgeComponent/$EDGE_AGENT_VERSION/lib/ COPY certs $CERT_DIR RUN apt-get update RUN apt-get install -y gcc libssl-dev libcurl4-openssl-dev liblog4cplus-dev \ libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ gstreamer1.0-plugins-base-apps gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-good gstreamer1.0-tools RUN apt-get install -y wget gnupg software-properties-common RUN wget -O- https://apt.corretto.aws/corretto.key | apt-key add - RUN add-apt-repository 'deb https://apt.corretto.aws stable main' RUN apt-get update; apt-get install -y java-11-amazon-corretto-jdk #RUN apt-get install unzip;unzip java-11-amazon-corretto-jdk maven # GLIBCXX_3.4.29 is required RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test RUN apt-get install -y g++-11 COPY 1.1.0/ubuntu/18.04/arm/kvs-edge-agent.tar.gz . RUN tar -xvf kvs-edge-agent.tar.gz RUN apt-get install -y maven RUN cd kvs-edge-agent;mvn clean package; \ mv ./target/libs.jar ./KvsEdgeComponent/artifacts/aws.kinesisvideo.KvsEdgeComponent/$EDGE_AGENT_VERSION CMD cd /kvs-edge-agent/KvsEdgeComponent/artifacts/aws.kinesisvideo.KvsEdgeComponent/1.1.0; \ java -Djava.library.path=/kvs-edge-agent/KvsEdgeComponent/artifacts/aws.kinesisvideo.KvsEdgeComponent/1.1.0 \ --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \ -Dio.netty.tryReflectionSetAccessible=true \ -cp kvs-edge-agent.jar:libs.jar \ com.amazonaws.kinesisvideo.edge.controller.ControllerApp
※ libstdc++.so.6: version `GLIBCXX_3.4.29' not found となるので、 g++-11をinstallしています
※ AWS_IOT_CORE_CREDENTIAL_ENDPOINT は、IoT Coreの認証情報エンドポイントを設定しています
例: credential-account-specific-prefix.credentials.iot.aws-region.amazonaws.com
※ AWS_IOT_CORE_DATA_ATS_ENDPOINT には、IoT Coreのデータプレーンエンドポイントを設定しています
例: data-account-specific-prefix.iot.aws-region.amazon
ビルドして実行することで、Edge Agentとして動作を開始します。
% docker build -t kvs-adge-agent:latest . % docker run kvs-adge-agent:latest
(5) エージェントの設定
録画の時間帯、送信の時間帯、データの保持期間などは、JSONファイルで定義して、start-edge-configuration-updateで設定します。
% aws kinesisvideo start-edge-configuration-update --cli-input-json "file://example-edge-configuration.json"
jsonファイルでは、下記について、編集が必要です。
- StreamARN (Kinesis Video Staream に作成したストリームのARN) 「(2) リソースの作成(CDK)」
- MediaUriSecretArn (SecretManagerに作成したシークレットのARN)「(2) リソースの作成(CDK)」
- HubDeviceArn (Iot Coreで作成したモノのARN)「(3) モノの作成」
また、ScheduleExpression に設定されている Cron式のような指定は、先頭が「秒」になっっていることに注意が必要です。例では、動作確認がすぐにできるように、5分毎に録画が開始するようになっています。
example-edge-configuration.json
{ "StreamARN": "arn:aws:kinesisvideo:ap-northeast-1:xxxxxxxxxxxx:stream/kvs-edge-agent-stream/1689011376458", "EdgeConfig": { "HubDeviceArn": "arn:aws:iot:ap-northeast-1:xxxxxxxxxxxx:thing/kvs-edge-agent", "RecorderConfig": { "MediaSourceConfig": { "MediaUriSecretArn": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:kvs-edge-agent-secret-UUWmql", "MediaUriType": "RTSP_URI" }, "ScheduleConfig": { "ScheduleExpression": "0 /5 * ? * * *", "DurationInSeconds": 299 } }, "UploaderConfig": { "ScheduleConfig": { "ScheduleExpression": "0 /5 * ? * * *", "DurationInSeconds": 299 } }, "DeletionConfig": { "EdgeRetentionInHours": 2, "LocalSizeConfig": { "MaxLocalMediaSizeInMB": 2800, "StrategyOnFullSize": "DELETE_OLDEST_MEDIA" }, "DeleteAfterUpload": true } } }
Kinesis Video Streamsのコンソールで、「メディア再生」を使用して、録画されたものを確認しています。(右上は、VNCによるRTSPのモニタです)
4 最後に
今回は、Kinesis Video Streams Edge Agent を RaspberryPIにデプロイして、ローカル環境にあるIPカメラの映像を Kinesis Video Streamsに送信してみました。
Edge Agentは、RTSPサーバから取得したデータを、特にエンコード・デコードすることなく、そのまま送信しているので、RaspberryPIのような非力な端末でも特に問題なく利用できそうです。
また、IPカメラやRaspberryPIに、特に実装は必要なく、これまでの、Producer SDKを利用した形態よりも更に簡単に扱えるのも魅力だと思います。