要約
- AWS IoTを使用したソリューションの数は日々増加している。
- デバイスの数が増えるにつれて、AWSを利用したDevOps担当者は、デバイスとAWS IoTの間で障害が発生した際にログを調査する時間が増えている。
- DevOps担当者は、予め最適かつ自動化されたログ出力を用意し、極力開発時間に専念できるようにしていきたい。
- そこで今回、AWS IoTソリューション用の自動ログ出力スキームを提案する。
AsIs
- AWS CLIを手動で使用して、S3からログ出力を実行している状態。
- Slackでの問い合わせにより開発作業が停止してしまう。
- PC利用しない限りログを取得ができず、ログファイルも大量にあるため調査時間がかかる。
ToBe
- サーバーレスアーキテクチャを利用して、可能な限り低コストで自動ログ出力を実現させる。
- Slackでのコミュニケーション時間を最小限に減らして開発に専念できるようにする。
- PCや携帯にSlackをインストールしていれば、誰でもどこからでもログ出力を実行可能にさせる。
シーケンス
- 大量のログファイルを一つのZipファイルにまとめるためにAWS Batchを採用。
- Slackのスラッシュコマンドは3秒以内に応答が必要であることに注意。
AWS構成
コマンド仕様
指針
/iot-log [識別子] [カテゴリ] [日付(UTC)]
識別子例:
- ThingName
- 証明書ID
- etc…
カテゴリ:
スラッシュコマンドとAWS Batchの仕様に応じてカテゴリのパラメーター指定は上限を設けること
- telemetry
- command
- lifecycle
- etc…
日付:
- 例: 2023/01/01
- ここに関してはAWS S3使用上UTCとなるので注意
Slackスラッシュコマンドの例
# 2023/10/01のTHING00001のテレメトリーを取得したい場合 /iot-log THING00001 telemetry 2023/10/01
# 2023/10/01のTHING00001のテレメトリーとコマンドを取得したい場合 /iot-log THING00001 telemetry,command 2023/10/01
# 2023年10月1日にAWS IoT Coreに接続/切断時の、すべてのデバイスのログを取得したい場合 /iot-log client_id lifecycle 2023/10/01
Slack上での表示イメージ図
ポストしたユーザーのスレッド上にて返信させる
Slackのchat.postMessageにthread_ts(timestamp)があるのでこちらを利用。
S3上の圧縮されたオブジェクトに対して、署名付きURLを発行し、有効期限の適切な値を指定。
ここでは、2023年10月1日のモノ名 THING00001 のテレメトリとコマンドログのzipファイルを生成する際に、Slackのスラッシュコマンドがどのように表示されるかの例を説明。
本間 12:21 PM /iot-log THING00001 telemetry,command 2023/10/01 dev ----------------------------------------------- IoTログ出力アプリ 12:21 PM 対象識別子: THING00001 ログカテゴリ: telemetry,command 指定ログ日付: 2023/10/01 ログファイルを生成中... ----------------------------------------------- IoTログ出力アプリ 12:22 PM 対象識別子: THING00001 ログカテゴリ: telemetry,command 指定ログ日付: 2023/10/01 出力進捗状況: xxx% ----------------------------------------------- IoTログ出力アプリ 12:23 PM 出力進捗状況: 100% 対象識別子: THING00001 ログカテゴリ: telemetry,command 指定ログ日付: 2023/10/01 ログファイル生成完了!! 下記からアクセスしてログファイルをダウンロードしてください ダウンロード可能な有効期限は60分までです。 https://xxxxx.s3.ap-northeast-1.amazonaws.com/slack/iot-logs/YYYYMMMDDhhmmss/20231001_THING00001.zip??X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxx&X-Amz-Date=xxxxx&X-Amz-Expires=xxxx&X-Amz-SignedHeaders=host&X-Amz-Signature=xxxxxx -----------------------------------------------
ログ出力生成の進捗状況の仕様
進捗状況を%
にするか文字列
定義するかは実装時に考えて確定してください。
想定進捗(例):
- starting: 10%
- progress: 10~99%
- <カテゴリ名> is starting
- <カテゴリ名> is done
- completed: 100%
zipファイルのディレクトリ構成
zipファイルをダウンロードした後に解凍後した時のディレクトリ構成を記載します。
スラッシュコマンドのパラメーターに応じてディレクトリ構成は変わります。
#例: ディレクトリ構造 root ├── telemetry_20231001.log └── command_20231001.log
構築の流れ
- Slack Appの作成
- Slack APIのYour Appsページで新しいAppを作成。
- スラッシュコマンドを作成し、リクエストURLを指定。このURLは後でAWS Lambda関数のエンドポイントとなる。
- AWS Lambda関数の作成
- Lambda関数を作成し、Slackからのリクエストを受け取るように実装。
- この関数内で、AWS Batchのジョブを起動するコードを実装。
- AWS Batchの構築&実装
- AWS Batchのジョブ定義、ジョブキューを構築。
- ジョブのDockerコンテナ内で、S3から複数のログファイルをダウンロードし、一つのログファイルに集約して再度S3にアップロードする処理を行う。
- 処理に応じて、進捗状況をSlackに通知。
- S3にアップロードしたZipファイルに署名付きURLを生成。
- LambdaからBatchジョブの起動
- Lambda関数内で、Batchジョブを起動するAPIを呼び出す。
- ログファイルのSlackへの通知
- Batchジョブが完了したら、S3のログファイル署名付きURLをSlackに通知。
- セキュリティ
- Slackの署名を検証して、リクエストが本当にSlackからのものであることを確認。
- S3のバケットポリシーやIAMロールを適切に設定して、不正なアクセスを防ぐ。
- テスト
- Slackでスラッシュコマンドを実行し、AWS Batchが起動し、Zipファイルが生成されてSlackに通知されることを確認。
- 署名付きURLへアクセスしてZipファイルがダウンロードできることを確認。
AWS Lambda仕様
- SlackのスラッシュコマンドによってトリガーされるAWS Lambdaは一つだけ用意。
- 最小実装を実現するために、API Gateway + Lambdaの代わりにLambda HTTPSエンドポイントを使用。
- インフラ構築にはCDK、SAMなどの便利なツールを利用。
- 今回はPythonで実装。
- 一つのAWS Lambdaから複数のAWS Batchにジョブを提出する際には、IAMロールにAssumeRoleを定義すること。
サンプルソースコード
AWS LambdaからAWS Batchジョブをトリガーするためには、以下の手順でPythonのAWS SDK(boto3)を使用。
- IAMロールの設定
- AWS Lambda関数に適切なIAMロールを割り当てることが重要。これには、batch:SubmitJob権限を含む必要な他の権限も含まれる。
- AWS Lambda関数の作成:
- LambdaコンソールまたはAWS CLIを使用して新しいLambda関数を作成。
- 依存関係のインストール
- 必要に応じてboto3ライブラリなどの依存関係をインストール。
- コードの実装
- 以下のPythonコードスニペットは、AWS BatchジョブをトリガーするAWS Lambda関数の例を提示。
import boto3 def lambda_handler(event, context): # Create AWS Batch client batch_client = boto3.client('batch') # Specify job queue and job definition job_queue = 'your-job-queue-name' job_definition = 'your-job-definition-name' # Specify job name and priority job_name = 'example-job-name' job_priority = 1 # Priority can take a value between 1 and 99 # Submit the job response = batch_client.submit_job( jobName=job_name, jobQueue=job_queue, jobDefinition=job_definition, priority=job_priority ) # Log the Job ID print(f'Job ID: {response["jobId"]}') return { 'statusCode': 200, 'body': f'Job {response["jobId"]} submitted successfully.' }
このコードスニペットでは、boto3を使用してAWS Batchクライアントを作成し、submit_jobメソッドを使用して新しいジョブを送信している。
ジョブキュー、ジョブ定義、ジョブ名、およびジョブの優先順位を指定する必要がある。
AWS Lambda関数のハンドラーとして使用される場合、このコードスニペットは関数がトリガーされるたびに新しいAWS Batchジョブを送信。
さらにこの関数はジョブIDをログに記録し、レスポンスでジョブIDを返却する。
AWS S3仕様
以下のバケット管理設定は例です。必要に応じて最適に設計してください。
デバイスとAWS IoTの間のログは、dev-iot-logsバケットに出力。
ログ出力の出力先もdev-iot-logsバケットで管理。
バケット名 | インプットディレクトリ名 | MQTT Topic |
dev-iot-logs | lifecycle | $aws/events/presence/connected/+ $aws/events/presence/disconnected/+ |
dev-iot-logs | telemetry | iot/telemetry/# |
dev-iot-logs | commands | iot/commands/# |
#例: インプットディレクトリ構造 dev-iot-logs ├── lifecycle ├── telemetry └── commands
#例: アウトプットディレクトリ構造 dev-iot-logs └── slack └── iot-logs └── Request Time (e.g., YYYYMMMDDhhmmss) └── 20231001_THING00001.zip
S3 ライフサイクルルールの設定
ライフサイクル設定の詳細です。
以下の設定は例です。必要に応じて最適に設計してください。
設定項目 | 設定値 |
ライフサイクルルール名 | Slack2IoTLogs |
ルールスコープ選択 | 1 つ以上のフィルターを使用してこのルールのスコープを制限する |
フィルタータイプ プレフィックス | slack |
ライフサイクルルールのアクション | オブジェクトの現行バージョンを有効期限切れにする, オブジェクトの非現行バージョンを完全に削除 |
オブジェクトの現行バージョンの有効期限が切れる: オブジェクト作成後の日数 | 1日 |
オブジェクトの非現行バージョンを完全に削除: オブジェクトが現行バージョンでなくなってからの日数 | 1日 |
AWS Batch仕様
以下の設定は例のため、必要に応じて最適に設計してください。
サーバーレスアーキテクチャが採用し、コンピューティングはFargateで用意。
実装内容
- 対象のS3バケットからログをすべてAWS CLIを利用して保存
- 指定されたパラメーターに応じて、対象ログをピックアップしフォーマット化してZIPファイル生成
- S3署名付きURLを発行
- Slackへ通知
ECRの設定
- プライベートリポジトリで作成
- ECR リポジトリ名: slack
- スキャン頻度: push時
ジョブキューの設定
項目 | 値 |
ジョブキュー名 | queue-sample |
優先度 | 1 |
スケジュールポリシー ARN – オプション | 指定なし |
オーケストレーションタイプ | Fargate |
ジョブキューを有効にする | 有効 |
コンピューティング環境を選択 | FARGATE_SPOT |
ジョブ定義の設定
項目 | 値 |
ジョブタイプ | 単一ノード |
名前 | Job_Slack |
実行タイムアウト | 3600(1時間) |
スケジュールの優先度 | 無効 |
プラットフォームタイプ | Fargate |
Fargate プラットフォームのバージョン | default値 |
パブリック IP を割り当て | 有効 |
イメージ | |
コマンド (JSON) | [“python3″,”main.py”,”generate-ziplog”,”–identifier”,”Ref::Identifier”,”–category”,”Ref::Category”,”–date”,”Ref::Date”] |
vCPU | 1.0 |
メモリ | 2 GB (2048MB) |
ジョブロール設定 | arn:aws:iam:: |
実行ロール | arn:aws:iam:: |
ログ設定 | awslogs: /batch/slack |
CloudWatch Log Groupの作成
項目 | 値 |
ロググループ名 | /batch/slack |
保持期間の設定 | 30日 |
運用時
SlackチャンネルのCanvasに使用方法とドキュメンテーションを記述
よく使われるスラッシュコマンド(テレメトリやコマンドなど)をリストアップ
結論
IoTソリューションでのトラブルシューティングには、リアルタイムな調査と根本原因の分析が必要。
今回のスキームをもとに必要要件に応じてカスタマイズし、迅速なDevOpsを実現してください。