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を利用した形態よりも更に簡単に扱えるのも魅力だと思います。