20200604のAWSに関する記事は25件です。

ラズパイからLTE回線で送信した動画をAmazon Rekognitionに分析させる

 前回の記事ではラズパイに装着したウエブカメラの動画をLTE回線(4G通信モジュール「4GPi」)経由でKinesis Video Streamに送信しました。4G通信モジュールの詳細はこちら

 今回は画像分析サービスのAmazon Rekognitionを使用してKinesis Video Streamが受信した動画の中からAmazon S3にアップロードした顔画像を検知させてみました。下記の記事を参考にしています。

 ・ Amazon Kinesis Video Streamsの映像をAmazon Rekognition Videoで解析する #reinvent

概要

    gaiyou02.png

環境

前回の記事の環境をそのまま使用しました。

作業の流れ

  1. AWSマネジメントコンソールの設定
  2. コレクションに顔画像を蓄積
  3. Kinesis video streamの作成
  4. Kinesis data stream の作成
  5. ストリームプロセッサの開始
  6. ウエブカメラの動画をKinesis Video Streamに送信する
  7. 分析結果の確認

1. AWSマネジメントコンソールの設定

作業PCのブラウザからAWSマネジメントコンソールにログインして以下の作業を実施します。
ブラウザはGoogle Chrome推奨です。

1.1. IAMロールの作成

  • マネジメントコンソールのサービスメニューからIAMのロール画面を開き、下表のロールを作成します。
項目 設定内容
ロール名 testRekognitionRole01
サービス Rekognition
ポリシー AmazonRekognitionServiceRole
  • 作成したロールのロールARNの値をメモ帳にコピペします。

1.2. 顔画像のS3アップロード

Rekognitionで検知させる顔画像をAmazon S3のバケットにアップロードします。

  • マネジメントコンソールのサービスメニューから「s3」を開き、新規バケットを作成します。リージョンは「アジアパシフィック(東京) ap-northeast-1」を選択。
  • 作成したS3バケットをクリックしてRekognitionで検知させる顔画像のファイルをアップロードします。顔画像は”両目が開いている”や解像度等がAWSの推奨条件を満たしてないとRekognitionでの検知率が低くなります。
    face02.png

2. コレクションに顔画像を蓄積

S3にアップロードした顔画像をRekognitionのコレクションに蓄積します。
※以下の作業はラズパイのLXTerminalを使用します。

  • Rekognitionに顔画像を蓄積するためのコレクションを作成します。
$ aws --profile awsconfigure01 rekognition create-collection --collection-id testcollection01

{
    "StatusCode": 200,
    "CollectionArn": "aws:rekognition:ap-northeast-1:xxxxxxxxxxxx:collection/testcollection01",
    "FaceModelVersion": "4.0"
}
  • external-image-idに顔の識別名を指定してS3の顔画像ファイルをコレクションに蓄積します。蓄積に成功すると顔の情報が返されます。
    ※profileオプションで指定したawsconfigure01は前回の記事の中で設定しています。
$ aws --profile awsconfigure01 rekognition index-faces --image '{"S3Object":{"Bucket":"【S3バケット名】","Name":"【S3ファイル名】"}}' --collection-id "testcollection01" --detection-attributes "ALL" --external-image-id "【顔の識別名】"

{
    "FaceRecords": [
        {
            "Face": {
                "FaceId": "f10ea79b-0d7c-4856-b283-59f4cbf274b4",
                "BoundingBox": {
                    "Width": 0.4545164704322815,
                    "Height": 0.6655027866363525,
                    "Left": 0.29065603017807007,
                    "Top": 0.2575848400592804
                },
                "ImageId": "e4286175-7f03-3706-842d-d075cbfdec7e",
                "ExternalImageId": "xxxxxxxx",
                "Confidence": 99.99993896484375
            },
            "FaceDetail": {
                "BoundingBox": {
         ・
         ・

3. Kinesis video streamの作成

  • Kinesis Video Streamに動画受信用のビデオストリームを作成し、表示されたStreamARNの値をメモ帳にコピペします。
$ aws --profile awsconfigure01 kinesisvideo create-stream --stream-name "testKinesisVideoStreams02" --data-retention-in-hours "24"

{
StreamARN": "arn:aws:kinesisvideo:ap-northeast-1:xxxxxxxxxxxx:stream/testKinesisVideoStreams02/1589094308184
}

4. Kinesis data stream の作成

  • Kinesis data streamにRekognitionの分析結果を格納するためのオブジェクトを作成します。
$ aws kinesis create-stream --stream-name AmazonRekognitionDataStream01 --shard-count 1
  • ストリームのStreamStatusが「ACTIVE」であること確認し、ShardIdとStreamARNの値をメモ帳にコピペします。
$ aws kinesis describe-stream --stream-name AmazonRekognitionDataStream01

{
    "StreamDescription": {
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "StartingHashKey": "0",
                    "EndingHashKey": "340282366920938463463374607431768211455"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49606866093651011850216802195303327451901325541455691778"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:xxxxxxxxxxxx:stream/AmazonRekognitionDataStream01",
        "StreamName": "AmazonRekognitionDataStream01",
        "StreamStatus": "ACTIVE",
        "RetentionPeriodHours": 24,
          ・
          ・

5. ストリームプロセッサの開始

ストリームプロセッサを起動して動画の分析を開始します。

  • ストリームプロセッサを作成し、表示されるStreamProcessorArnの値をメモ帳にコピペします。
$ aws --profile awsconfigure01 rekognition create-stream-processor --name "testStreamProcessor01" --input '{"KinesisVideoStream": {"Arn": "【3節のStreamARN】"}}' --stream-processor-output '{"KinesisDataStream": {"Arn": "【4節のStreamARN】"}}' --role-arn "【1.1節のロールARN】" --settings '{"FaceSearch": {"CollectionId": "testcollection01","FaceMatchThreshold": 85.5}}' 

{
    "StreamProcessorArn": "arn:aws:rekognition:ap-northeast-1:xxxxxxxxxxxx:streamprocessor/testStreamProcessor01"
}
  • ストリームプロセッサを開始します。
$ aws rekognition start-stream-processor --name testStreamProcessor01 --region ap-northeast-1
  • ストリームプロセッサのStatusが「RUNNING」であることを確認します。
$ aws rekognition describe-stream-processor --name testStreamProcessor01 --region ap-northeast-1

{
    "Name": "testStreamProcessor01",
    "StreamProcessorArn": "arn:aws:rekognition:ap-northeast-1:690626763451:streamprocessor/testStreamProcessor01",
    "Status": "RUNNING",
    "CreationTimestamp": 1589097878.314,
        ・
        ・

6. ウエブカメラの動画をKinesis Video Streamに送信する

前回の記事等を参考に、ラズパイに装着したウエブカメラの動画を4GPi経由でKinesis Video Streamに送信します。
ウエブカメラにコレクションに蓄積した顔が入るように撮影してください。

7. 分析結果の確認

  • データの位置情報を示すシャードイテレーターの値を取得します。シャードイテレーターはストリームからレコードを抽出するために必要です。
$ aws kinesis get-shard-iterator --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --stream-name AmazonRekognitionDataStream01

{
    "ShardIterator": "AAAAAAAAAAGAFu7MmT50YkF9N2pvMOhaeE9ymzGILJklzKUuj8M1SG9OKHGKxyfF6wGrN/vnuEyPFbw5AXreN73AVVkR2/fif6vyP77/K6WzXxIn3mG1HVE4GChWIjSOqKitLpeJ4S0U2KgqtVgVaDtQETlxALuoSYONedyQeEKAXlH2s7Vrs6hCulLmipXGb9jEQd2rtL28BSFMHfpEvko310weiZfAtBENUys6Vfs6/aCD+tyiog=="
}
  • シャードイテレーターの値を指定してストリームからレコードを抽出します。
    ※シャードイテレーターの有効期間は300秒なので、300秒以内に下記コマンドを実行します。
$ aws kinesis get-records --shard-iterator AAAAAAAAAAGAFu7MmT50YkF9N2pvMOhaeE9ymzGILJklzKUuj8M1SG9OKHGKxyfF6wGrN/vnuEyPFbw5AXreN73AVVkR2/fif6vyP77/K6WzXxIn3mG1HVE4GChWIjSOqKitLpeJ4S0U2KgqtVgVaDtQETlxALuoSYONedyQeEKAXlH2s7Vrs6hCulLmipXGb9jEQd2rtL28BSFMHfpEvko310weiZfAtBENUys6Vfs6/aCD+tyiog==

        },
        {
            "SequenceNumber": "49606866093651011850216802195524560876891002654104223746",
            "ApproximateArrivalTimestamp": 1589099992.482,
            "Data": "eyJJbnB1dEluZm9ybWF0aW9uIjp7IktpbmVzaX  ・・(省略)・・mU3NGY4MjU2ZjIifX1dfV19",
            "PartitionKey": "7b459149-bcf0-47d4-a5a9-71ca55a9d65b"
        },
        {
         ・
         ・

上の実行結果は顔に検出に成功している例です。
逆に下の実行結果はDataの文字数が少なく顔の検出に失敗しています。この時はストリームプロセッサの起動に失敗する事象が発生していたのですが、Data Streamとストリームプロセッサの再作成で事象が改善しました。

        {
            "SequenceNumber": "49604526190993957371583841525857201473854060749047988226",
            "ApproximateArrivalTimestamp": 1582539544.113,
            "Data": "dGVzdDE=",
            "PartitionKey": "1"
        }
  • Base64デコーダを使用してDataの値をデコードします。
    デコード結果に目や鼻の位置が返されており、ストリーミングデータからコレクションに蓄積した顔が検出されていること分かります。
    encode1.png

補足

下記のコマンドで設定を削除できます。

  • ストリームプロセッサの削除
$ aws --profile awsconfigure01 rekognition delete-stream-processor --name testStreamProcessor01
  • Data Streamの削除
$ aws kinesis delete-stream --stream-name AmazonRekognitionDataStream01
  • Video Streamの削除
$ aws --profile awsconfigure01 kinesisvideo delete-stream --stream-arn "arn:aws:kinesisvideo:ap-northeast-1:xxxxxxxxxxxx:stream/testKinesisVideoStreams02/1589094308184"

最後に

今回はラズパイ側で撮影した動画をRekognitionで分析させてみました。
カメラやセンサーの情報をAWS側で処理させる際は、特に検証用途として安価なラズパイはおすすめです。

また、4G通信モジュールを使用すればネットワーク環境が整っていない場所でもAWSと通信できるので
検証用途や単発の現地調査等でかなり活用できそうです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FlutterとAWSで始めるサービス開発 (3)AWS Cognito連携

はじめに

AWSでモバイルアプリ開発といえば、Amplifyというのが今のAWSの押しであることは以前にも述べました。Amplifyを選択するとJavaScriptベースなのでReact Nativeを使ったモバイルアプリ開発に進むのが王道になります。
Flutterでモバイルアプリを作りたいという要求がベースにあって、そこからスタートしていない限りはなかなかこの組み合わせにたどり着くことはないのかなという気がします。また、AWSの公式にはDart版のAWS SDKがないので、その部分も敷居が高く、レアな組み合わせになってしまうのかなと思います。

公式ではなくても、https://pub.dev/packages?q=cognito で見たところ、いくつか十分実用的なAWS用パッケージが公開されており、それらパッケージを活用すればそこまで苦労せずにアプリケーションの構築は進められそうです。
以下、パッケージを探して気になったの2個のライブラリになります。
Amazon Cognito Identity SDK for Dart
flutterAmplify

前者はdartで実装されていてCognitoに特化したライブラリ、後者はFlutter版Amplifyを実現しようとしていて、iOS、Androidそれぞれのネイティブ実装で作りこんでいるライブラリです。シンプルにFlutterで色々なAWSサービスを使ってアプリケーションを開発していくなら前者のSDKはとても扱いやすそうです。さらには、AWSのsigv4実装も切り出されており、各種AWSサービスを使っていく上でも非常に便利に使えそうです。

前振りがながくなりましたが、Amazon Cognito Identity SDK for Dartを使ってCognito連携のアプリケーションを実装していこうと思います。

ユーザー管理とCognito

単なるユーティリティ的なモバイルアプリケーションであれば必要ないと思いますが、永続的なデータを管理する場合や、ビジネス目的で開発するようなアプリケーションの場合、ユーザーにアカウントを作ってもらい、アカウントに関連付けてサーバー側で様々なデータ管理やサービスを行うのが理想的です。それを簡単に実現してくれるのがAmazon Cognitoです。Cognitoは大きくいくつかの機能に分かれますが、ユーザー管理を行いたい場合は、ユーザープールという機能を使います。ユーザープールは、公式から引用するとAmazon Cognito ユーザープールは、何億人ものユーザーにスケールするセキュアなユーザーディレクトリを作成できます。フルマネージドサービスのユーザープールは、サーバーインフラストラクチャの立ち上げを気にすることなく、簡単にセットアップできます。です。ユーザーIDの管理、認証等々の基本的な機能がすべて実装されており、月間5万アクティブユーザーまでは無料という至れり尽くせりなサービスです。

アプリケーションの要件

アプリケーションの要件としては、以下を満たすようなものを作ってみたいと思います。

  • 新規のID登録機能
    • メールアドレスを使った独自IDで登録
    • 別のSNSのID(Googleなど)を使ったIDで登録
  • 登録したIDでのログイン機能
  • 独自IDでパスワード忘れた場合のリセット機能

Cognito ユーザープールの準備

まずは、AWSにアカウントを作りましょう。アカウントの作り方は公式ページを参考に作成してください。今回の流れの中では無料枠に収まる範囲でしか使わないのでお金もかかりません。

ユーザープール作成

公式の手順ステップ 1.ユーザープールを作成する通りに作れば問題ありません。
ユーザープール作成画面に入り以下手順で進めました

  1. ユーザープール名を自由に入力してください。アプリの利用者に目に入るわけではないので自分の管理したい名前で命名してかまいません。入力後、デフォルトを確認するを選択します

    Cognito1.png

  2. 左側のナビゲーションメニューで属性 を選択し、Eメールアドレスおよび電話番号Eメールアドレスを許可を選択します
    Cognito2.png

  3. 左側のナビゲーションメニューで確認を選択し、プールの作成を押下します。
    Cognito3.png

  4. ユーザープールの作成が完了したら、プールIDを取得しましょう。後ほどモバイルアプリ側でIDを利用します。

Cognito6.png

アプリクライアントの作成

引き続きアプリケーションがCognitoユーザープールにアクセスするためアプリクライアントの作成を行います。
全体設定アプリクライアントを選択します。
アプリクライアント名は自由につけてください。利用時に使うことはありません。今回は、クライアントシークレットを作成Lmabdaトリガのカスタム認証を有効にするをOFFにし、その他はデフォルトで設定しています。

Cognito4.png

作成が完了したら、アプリクライアントIDを取得しましょう。後ほどモバイルアプリ側でIDを利用します。

Cognito5.png

モバイルアプリの実装準備

まず、Amazon Cognito Identity SDK for Dartをプロジェクトに組み込みます。pubspec.yamlファイルのdependenciesセクションに以下のようにパッケージを追記します。Visual Studio Codeのpliuginにて自動でパッケージの取得処理が実行されます。

dependencies:
  amazon_cognito_identity_dart_2: ^0.1.12+3

次にlib/main.dartamazon_cognito_identity_dart_2パッケージをimportし、CognitoUserPoolクラスのインスタンスを作成します。CognitoUserPoolクラスのコンストラクタ第一引数は先ほど作成したプールのプールID、第二引数は先ほど作成したアプリクライアントのアプリクライアントIDになります。

import 'package:amazon_cognito_identity_dart_2/cognito.dart';

final userPool = new CognitoUserPool(
    '[プールID ex. ap-northeast-1_XXXXXXXX]', '[アプリクライアントID]');

まとめ

ここまでの準備で、Cognito連携をしたモバイルアプリ開発の準備ができました。次回は、実際にモバイルアプリにユーザー登録機能を実装していきたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSで遊んでみたいときにかかる費用

AWS使ってみたい

自作のポートフォリオなどでWebアプリケーションをHerokuにデプロイしたことはあるけど、
AWSは敷居が高い気がして使ったことがないという方は多いのではないでしょうか。
しかもそこそこ料金がかかるらしいし、一見すると料金がわかりにくいので躊躇してしまいますよね。

私も使ってみるまではそう思っていたのですが、
結果的にはネットワークの勉強にもなるし、汎用性の観点からも早く使ってみれば良かったなと思っています。

とはいえ、構成次第では稼働させっぱなしにすると多少費用がかかってしまいますので、
2020年6月現在の費用をお伝えします。

WordPressが動くようにするといくらかかるのか

AWS初学者のために心底丁寧に解説されているこちらの本では、

Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版

AWSを使ってWordPressを動かすまでがハンズオン形式で書かれています。
ただし、実際に構築した場合のAWSに支払う費用までは書かれていませんでした。

この本の通りにWEBサーバー、DBサーバー、NATゲートウェイという構成でWordPressを動かし、
上記を約1ヶ月稼働させっぱなしにした場合、以下のような請求額になりました。(東京リージョン)

スクリーンショット 2020-06-01 8.07.58.png

1ヶ月(31日間)だと大体6,900円くらい!?

上記の画像はいろいろ弄っていたため若干の誤差があるのですが、
各製品の単価から正確に計算してみると、

  • WEBサーバー(EC2 Linux t2.micro)
    0.0152USD/時間 × 24時間 × 31日 = 11.309USD

  • DBサーバー(EC2 Linux t2.micro)
    0.0152USD/時間 × 24時間 × 31日 = 11.309USD※

※ただし、EC2は最初の12ヶ月だけ750時間/月の無料枠があるので、上記のうち1インスタンスは起動しっぱなしでも料金は発生しません。

  • NATゲートウェイ(稼働時間) 0.062USD/時間 × 24時間 × 31日 = 46.128USD
  • NATゲートウェイ(転送量)  0.062USD/GB × 0.147GB = 0.01USD
  • ストレージ(EBS) は最初の12ヶ月は30GBまで無料

となり、110円/USDとすると税込みで大体6,900円の費用がかかります。

NATゲートウェイがそれなりにかかる

NATゲートウェイの時間単価がそれなりにするため、24時間を31日放置しているとそれだけで5,500円/月位かかります。
NATゲートウェイ自体はAmazonが運用管理をしているので、ある程度の規模であれば費用は見合うと思います。

とはいえポートフォリオ用など個人利用の範疇だと財布には優しくないかもしれません。
また、2020年5月の時点ではNATゲートウェイには停止・起動の操作がないため、
課金を止めるには削除するしかありません。

NATゲートウェイはなくても動く

本の中ではDBサーバーにインターネットからMariaDBをインストールするためにNATゲートウェイを構築しているので、必要なソフトウェアをインストールしてしまったら、NATゲートウェイを削除しても良いかもしれません。

DBサーバー自体はWEBサーバーと接続されていれば機能するので、常時NATがなくてはいけないと言うわけではありません。
ただし、DBサーバーのアップデートなどの際は改めて構築する必要があります。

運用管理の手間は増えますが、NATゲートウェイの代わりにNATインスタンスを構築することで費用を抑えることはできます。

公式ドキュメント AWS NAT インスタンスの設定方法
公式ドキュメント AWS NAT インスタンスと NAT ゲートウェイの比較

EC2のLinux t2.micro1インスタンスだけなら1,400円程度

ポートフォリオ用としてEC2だけを稼働させるということはないかもしれませんが、
本の中と同じ構成でNATゲートウェイをさっさと削除してしまった場合、
最初の12ヶ月はt2.micro1インスタンス分の費用だけなので、

(EC2 Linux t2.micro)
0.0152USD/時間 × 24時間 × 31日 = 11.309USD

税込み約1,400円/月 程度ということになります。

AWSを触ってみたいという方におすすめの良書

ということで、各製品の単価をしっかり把握して必要なものだけを稼働させていればそれほど怖いものではないので、AWS食わず嫌いの方も是非チャレンジしてみてください。
今回参考にさせていただいた大澤 文孝さんの以下の書籍はとても丁寧に書かれていますのでおすすめです。
素敵なAWSライフを!

【Kindle版】 Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版
【単行本版】 Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】ECSで使用するECRのURLをマルチステージ対応にする

ECRのImage URLにアカウントIDを直接ハードコーディングしてしまうと
本番環境とステージング環境でアカウントIDが別れている場合などにdocker-compose.ymlが共通にできません。
この問題を環境変数で解決します。

docker-composeファイル

docker-compose.yml
image: ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/xxx:latest

アカウントIDを環境変数から参照するようにします。

参考URL
Compose における環境変数 | Docker Documentation
https://matsuand.github.io/docs.docker.jp.onthefly/compose/environment-variables/

シェル上からの実行

プロファイル、アカウントID指定版(面倒)

AWS_PROFILE=xxx AWS_ACCOUNT_ID=xxx ecs-cli compose up --create-log-groups --cluster-config xxx

プロファイル名以外にアカウントIDも指定が必要になるため書き換えミスが発生しそうです。

プロファイルのみ版(簡単)

AWS_PROFILE=xxx AWS_ACCOUNT_ID=`aws sts get-caller-identity | jq -r .Account` ecs-cli compose up --create-log-groups --cluster-config xxx

プロファイル名をもとにアカウントIDを補完するようにしました。
一時環境変数としてAWS_PROFILE, AWS_ACCOUNT_IDを渡す時にAWS_ACCOUNT_IDの評価時にAWS_PROFILEを参照しているところがミソです。

標準でアカウントID解決するやりかたあるのではと探したんですが見つけらなかったのでシェル芸に逃げました。

参考URL
【小ネタ】AWS CLIでAWS Account IDが取れるようになりました! | Developers.IO
https://dev.classmethod.jp/articles/get-aws-account-id-with-get-caller-identity/
jq コマンドを使う日常のご紹介 - Qiita
https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS: アプリケーションサービス

アプリケーションサービス

AWSのアプリケーションサービス

アプリケーションサービスに共通する基本的な考え方

AWSのアプリケーションサービスはAWSのサーバーリソース上に構築されており、サーバーとアプリケーションのメンテナンスはAWSにまかせている。
そのため、コスト面でも安定性の面でも、自身で構築するより優れていることが多い。

SQS(Simple Queue Service)

AWSが提供するフルマネージドなメッセージキューイングサービス。

  • キュー
    • メッセージを管理するための入れ物
    • 利用開始時に作成すれば管理する必要なく、エンドポイントと呼ばれるURLを介して利用する
  • キューの管理機能
    • キューの作成・削除・動作属性などの詳細な設定もあり
  • メッセージ機能
    • キューに対するメッセージの送信・取得と処理済みのメッセージの削除がある
    • 複数のキューをまとめて処理するバッチ用のAPI
    • 処理中に他のプロセスから取得できなくするための可視性制御のAPI

StandardキューとFIFOキュー

  • Standardキュー
    • メッセージの配信順序を保証せず、同一のメッセージが2回配信される可能性がある
  • FIFOキュー
    • メッセージの配信順序を保証する。秒あたりの処理件数はStandardキューに劣る

ロングポーリングとショートポーリング

  • ロングポーリング
    • メッセージがある場合に、即レスポンスを返すが、メッセージがない場合、設定されたタイムアウトギリギリまでレスポンスを返さない
  • ショートポーリング
    • リクエストを受けるとメッセージの有無に関わらず即レスポンスを返す

遅延キューとメッセージタイマー

  • 遅延キュー
    • キューに送られたメッセージを一定の時間見えなくする機能
  • メッセージタイマー
    • 個別のメッセージに対して一定時間見えなくする機能

SNS(Simple Notification Service) & SES(Simple Email Service)

  • SNS
    • プッシュ型の通知サービスで、システムのイベント通知の中核を担う
  • SES
    • Eメール送信サービスで、SMTPプロトコルを利用する

SNSの利用について

  • トピック
    • 情報を管理する単位
  • Publisher
    • 通知する人。
  • Subscriber
    • 通知される人。利用するトピック及び受け取るプロトコルを指定

SNSを使ったイベント通知

  • リソースの設定・状態を評価するAWS Configでルールに違反している使われ方が発見された
  • CloudWatchでEC2のCPU・ネットワークなどのメトリクスを監視しているときにしきい値を超えた

などといったケースで利用される

SES

Eメール送信サービス。SMTPプロトコルやAPIを通じたメール送信の他に、Eメールを受信し、S3に保存することも可能

  • 送信時にウイルスやマルウェアを検出理sてブロックする機能
  • 送信の成功工数や拒否された数を統計的に処理し、配信不能や苦情を管理する機能
  • Sender Policy Framework(SPF)やDomainKeys Identified Mail(DKIM)といった認証機能
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS] Amazon Redshift クラスターがわからないから調べた

Amazon Redshiftとは

クラウド内のフルマネージド、ペタバイト規模のデータウェアハウスサービス
Amazon Redshiftクラスターと呼ばれる一連のノードを起動することで作成できる。

クラスターって?

リーダーノードと、1つ以上のコンピューティングノードから構成される一連のノードのこと(AWS公式サイトより)。

コンピューティングノードって言葉は要はコンピュータのことで、そのコンピュータ同士が連携してつながっている時にノードって言葉がつきます。
リーダーノードは読んで字の如く、そのコンピューターたちの親玉です。図で見るとこんなかんじ
image.png
図で見るとわかりやすいですね。

まとめるとクラスターは、ノード(コンピュータ)が集まった集合体のことです。

最後に

学習始めたばかりなので間違っていたり、意見があればコメントお願いします!

参考
https://docs.aws.amazon.com/redshift/index.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クラウドのVMインスタンスを定期的に停止させる方法(AWS&GCP)

業務で夜間に開発系のサーバを停止させて翌朝起動させたかったり、GPUインスタンスの停止漏れを防ぐために毎日夜間に停止させたりと、ニーズが高まったので方法を調べた結果を残しておきます。

この記事に画面キャプチャを載せて一から手順を書くよりも公式のヘルプページの方が確実ですので、概要は以下を御覧ください。そこまで難しい手順は無く、特にGCPについてはgcloudコマンドをコピペで実行していくだけで、ほぼほぼできあがります。

AWSはこちら
GCPはこちら

ただし、AWSについてはインスタンスIDを直接指定ではなく、GCPのようにタグを使った方式にしたかったのと、PythonではなくRubyで実装したかったので、上記手順とはやや違うことをやりました。

こちらについては後日アップデート予定です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS SAP】S3エトセトラ【頻出】

S3にまつわるエトセトラ

AWS SAP取得にあたり、憶えて良かったエトセトラをまとめる。

EC2とS3とCloudFrontと

例えば、
WEBサーバとしてEC2を利用。
静的コンテンツをS3で提供。
静的コンテンツへのアクセスが集中するたびにHTTPエラーが発生。
といったケースがあるとする。

そんな時に回避策として利用すると良いのが、CloudFront。(CDN)
CloudFrontで静的コンテンツをキャッシュすることでS3の負荷を軽減し、アクセス集中に対応。

S3に個人情報を保存する

S3に個人情報を保存するのはいいが、安全性が不安。通信は暗号化したい場合にどうするか。

大丈夫です。S3の通信はデフォルトでSSL暗号化されます。

S3の保存期間

S3のライフサイクルで、有効期限を決めることで保存したデータを任意の期間保管したら削除といったことができる。

追加で、任意の期間経過したらデータをGLACIERに移行するといったこともできる。

利用イメージとしては、
・ログ保存のためにS3を利用する。
・半年間のログは頻繁に利用するが、半年以上経過したログはほとんど利用しない。
・ただ、半年以上経過したログも保管しておきたい。
・コストは最小限に抑えたい。

そんなときは、S3のライフサイクルを利用して、半年経過したらGLACIERに移行する。

こめGLACIERはS3に比べると安価だが、データ取り出しに時間がかかる。

すぐに使わないよーというデータを保管しておく分には問題ない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アウトプット勉強始めます。第0回

自己紹介

初めまして!
未経験から第二新卒(当時23歳)でこの業界に飛び込み現在インフラエンジニアとして3年目に突入しました。
現在はネットワークのオンプレ運用を中心にエンジニアとして揉まれる日々を過ごしています。

保有する資格
CCNP
LinuC 2
VBA basic
ITパスポート
TOEIC 780
AWS SAA(6月に頑張って取得予定)

この二年間の経歴

未経験でこの業界に入り、最初は24H365Dの監視現場に配属されました。そこでITエンジニアの洗礼とでもいうのでしょうか?
職人気質な先輩に怒られ、なじられ、かつこのままずっとここにいるのは嫌だと思い、必死にLinuC201を取得し、CCENT(※1)を勉強し、前向きな姿勢が認められて、日勤のNW運用現場へ異動となりました。そこから約1年半、日々勉強し資格を取得し"とにかく早く構築へ"このマインド一本でがむしゃらに頑張りました。その頑張りが実を結び入社して1年半後、構築現場へキャリアアップを果たしました!!と
ここまでは順調だったのですが。。。。。

※1 CCENT
現在のCCNAより前に存在した資格。旧CCNAはCCENT(100-105J)とCCNA(200-105J)の2つを取得するか、範囲がとてつもなく広いCCNA(200-125J)試験を突破しなければ、正式にCCNAホルダーとして認定されませんでした。
初めて黒本を購入した人は、英単語ターゲットよりも分厚い、あの試験範囲の広さに絶望感を味わった方も多いはず。。

なぜブログを始めようと思ったのか??

今までの考え方(資格=実力)
資格も持ってるし、知識もあるんだから構築でもすぐに戦力になるだろうと自信をもって現場に配属されましたが、何故か知識はあっても仕事に活かすことができず
挙げ句の果て、知っているはずの知識もリーダーに怒られて思い出す羽目に、、
  
あれ、、、あんなに勉強したのになんで俺こんなに仕事できないのかな。。。?
   
そもそもネットワークって実機なきゃ勉強できないしな、オンプレで新規のお客様がなかなか来なく、経験できる事も少なくなってきているよな。
それならいつでもどこでも勉強できて、かつ現在主流なクラウドで勝負しよう!
教材も多いし!
よしこれからはクラウドに切り替えよう!!

気が付いたらまた資格取得に走り、同じ過ちをすると気が付いた

"Amazon Web Services パターン別構築・運用ガイド "(通称オレンジ本)を購入し、早速クラムメディアを契約し、2ヶ月でAWS SAA取ろう!と意気込みました。。   
しかし問題の答えや知識が増えていくにつれて思いました。
あ、、、俺また目先の資格に頼ってるかも、、そもそも苦労して暗記してCCNPとってそこから切り替えてクラウドやろって決めたのにこれじゃまた同じこと引き起こすかも、、、

再発防止として暗記中心でなくアウトプット勉強法に切り替える

と、そこで初めて気が付きました。

持っている資格数や保有資格の難易度=市場価値じゃないんだな。。

でも、今までping-tを覚えて乗り切る勉強が中心だったし、どうすればいいのかな、、と
その時、会社にエンジニアメンター制度がありブログを発信してアウトプットしている方がメンターとして支援する制度を見つけました。
勉強したことを発信することで、自分の言葉で理解し、かつ他人にも情報を提示するからこそ責任が伴う。
このアウトプット勉強法を今後は取り込んで、ネットワークでの教訓を絶対に活かすぞ!と誓いました。

今後どのような感じで情報発信していくのか

週一回を目標にAWSの内容でブログをアップしていきます。

次回予告

記念すべき技術ブログの第一回目は現在ネットワークの現場にいるので関連した技術のVPCを中心に記事をアップする予定です

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS SAP】ELBの3タイプ【頻出】

AWS SAP取得に向けて勉強する中で覚えてよかったもの 第19弾

以下の違いについて覚えておいて損はありません。

ELBの3つのタイプ
・Classic Load Balancer
・Application Load balancer
・Network Load Balancer

Classic Load Balancerとは

トランスポートレイヤー (TCP/SSL) またはアプリケーションレイヤー (HTTP/HTTPS) のいずれかでルーティングを決定する。

リバースプロキシのため、行きも帰りもロードバランサを経由する。

Application Load balancerとは

HTTP / HTTPS トラフィックの負荷分散を行う。アプリケーションレイヤーでルーティングを決定する。

リバースプロキシのため、行きも帰りもロードバランサを経由する。

Network Load Balancerとは

TCPトラフィックなどネットワーク系の負荷分散
を行う。トランスポートレイヤー (TCP/SSL) でルーティングを決定する。
行きだけロードバランサーを経由する。帰りは経由しない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS SAP】EC2のインスタンス課金タイプ【頻出】

AWS SAP取得に向けて勉強する中で覚えてよかったもの 第18弾

以下の違いについて覚えておいて損はありません。

・オンデマンドインスタンス
・リザーブドインスタンス
・スポットインスタンス

オンデマンドインスタンスとは

従量課金。使った分だけ支払うタイプ。

リザーブドインスタンスとは

事前に予約して利用。(1年契約か3年契約)
オンデマンドインスタンスに比べて、最大72%安くなる。
当分使うことが想定される場合などはリザーブドインスタンスを利用することでコスト削減が可能。ただ、一度購入すると途中で利用しなくなってもコストは同じ。

スポットインスタンスとは

AWSで使われていないEC2を入札制で利用する。
サーバー価格が入札金額を上回ると、サーバーを利用できなくなる。
突然停止するリスクを許容しても安く使いたい!という場合に利用する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS SAP】S3における暗号化【頻出】

AWS SAP取得に向けて勉強する中で覚えてよかったもの 第17弾

・SSE-C
・SSE-KMS
・SSE-S3

SSE-C

Server-Side Encryption with Customer-Provided Keys (SSE-C)の略称。
ユーザー側でキーを準備し管理する。

SSE-KMS

Server-Side Encryption with AWS KMS-Managed Keys (SSE-KMS)の略称。
ユーザー側でKMSでキーを生成して管理する。

SSE-S3

Server-Side Encryption with Amazon S3-Managed Keys (SSE-S3)の略称。

Amazon S3 がキーを管理。キー自体を定期的に更新することで安全性を担保。

ポイント

会社のポリシーによっては、暗号化キーを自社で管理したいといったケースがある。
その場合は、SSE-Cを利用。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Glue コンソールを使用してワークフローのジョブを変更する

はじめに

以下のようなワークフローがあります
Screenshot_2020-06-04 AWS Glue Console.png
このうち、job02job22に変更してみます。

ジョブの変更

1)変更対象となる旧ジョブ(job02)のトリガー元(trigger01)を選択、表示された点線の矩形をクリック
Screenshot_2020-06-04 AWS Glue Console(1).png
2)ダイアログが起動されるので、変更後の新ジョブ(job22)を選択して「追加」ボタンを押下
Screenshot_2020-06-04 AWS Glue Console(2).png
これでtrigger01からjob22への処理フローが新たに追加されました
Screenshot_2020-06-04 AWS Glue Console(3).png
3)続いて旧ジョブ(job02)の呼び出し先となるトリガー(trigger02)を選択し、「アクション」>「監視するジョブ/クローラを追加」をクリック
Screenshot_2020-06-04 AWS Glue Console(5).png
4)ダイアログが起動されるので、新ジョブ(job22)を選択して「追加」ボタンを押下
Screenshot_2020-06-04 AWS Glue Console(6).png
これでjob22からtrigger02への処理フローが新たに追加されました
Screenshot_2020-06-04 AWS Glue Console(7).png
5)あとは不要となるjob02からtrigger02への処理(矢印)を選択して「削除」ボタンを押下
Screenshot_2020-06-04 AWS Glue Console(8).png
6)同様にtrigger01からjob02への処理(矢印)を選択して「削除」ボタンを押下
Screenshot_2020-06-04 AWS Glue Console(9).png
これで無事job02job22に変更したワークフローが完成しました
Screenshot_2020-06-04 AWS Glue Console(10).png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSで割とトレンドの技術使う大学生日記

環境構築を雑に設計

現在(2020/06/04)で公開しているサイトではAWS EC2のみを使用した設計となっているため、
それをよりトレンド風に修正していく記事です。
ちなみに作成したサイトは
http://ec2-18-180-131-224.ap-northeast-1.compute.amazonaws.com/
です。なるべくお金を掛けたくなかったのでドメインも取得せず、ロードバランサーも通信の暗号化もしておりません。
Dockerすらも使用していないので、そのあたりからやっていくつもりです。
あと、日記ですのであまり期待しないでください、よわよわなエンジニアの卵ですので。笑

サービス内容

GitHubのレポジトリはhttps://github.com/maaaaakoto35/UniFood
ですのでよければスターつけてください笑

ReadMeも雑に作成したのでサービス内容を記述していきます。
当初、京都産業大学の口コミサイト等は調べても出てこなかったので
当サイトの目的は、学食に対してレビューができる、ということです。

この記事が完成する頃には拡張機能も追加していくつもりです。
中身のロジックはものすごく簡単なんですが、ご要望があれば
当サイトを作成した際のつまづいた点なども投稿しようかなと思っております。

参考にしているサイト

当記事は下記のサイトを参考にしております。
https://dev.classmethod.jp/articles/aws-eaws-ecs-fetch-run-shell/
これから記事の追加していくつもりです。(2020/06/04)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSで割とモダンな技術使う大学生日記

環境構築を雑に設計

現在(2020/06/04)で公開しているサイトではAWS EC2のみを使用した設計となっているため、
それをよりトレンド風に修正していく記事です。
ちなみに作成したサイトは
http://ec2-18-180-131-224.ap-northeast-1.compute.amazonaws.com/
です。なるべくお金を掛けたくなかったのでドメインも取得せず、ロードバランサーも通信の暗号化もしておりません。
Dockerすらも使用していないので、そのあたりからやっていくつもりです。
あと、日記ですのであまり期待しないでください、よわよわなエンジニアの卵ですので。笑

サービス内容

GitHubのレポジトリはhttps://github.com/maaaaakoto35/UniFood
ですのでよければスターつけてください笑

ReadMeも雑に作成したのでサービス内容を記述していきます。
当初、京都産業大学の口コミサイト等は調べても出てこなかったので
当サイトの目的は、学食に対してレビューができる、ということです。
また、UI設計がスマートフォン向けになっております。

この記事が完成する頃には拡張機能も追加していくつもりです。
中身のロジックはものすごく簡単なんですが、ご要望があれば
当サイトを作成した際のつまづいた点なども投稿しようかなと思っております。

参考にしているサイト

当記事は下記のサイトを参考にしております。
https://dev.classmethod.jp/articles/aws-eaws-ecs-fetch-run-shell/
これから記事の追加していくつもりです。(2020/06/04)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VM Import/Export

VM Import/Export

VM Import/Export を使用すると、仮想マシン (VM) イメージを既存の仮想化環境から Amazon EC2 にインポートし、それを元の環境にエクスポートすることができます。この方法を使うと、アプリケーションおよびワークロードを Amazon EC2 へ移行したり、VM イメージカタログを Amazon EC2 にコピーしたり、バックアップと災害対策のために VM イメージのリポジトリを作成することができます。

ほとんどの VM Import ニーズには、AWS Server Migration Service の使用をお勧めします。AWS SMS はインポートプロセスを自動化し (大きな VM インフラストラクチャの移行ワークロードを軽減)、変化する VM の増分更新のサポートを追加して、インポートされた VM をすぐに使用できる Amazon マシンイメージ (AMI) に変換します。

VM Import/Export の機能

仮想化環境から Amazon EC2 に VM を Amazon Machine Image (AMI) としてインポートする機能。AMI から EC2 インスタンスをいつでも起動できます。

仮想化環境から Amazon EC2 に VM を EC2 インスタンスとしてインポートする機能。インスタンスの最初の状態は stopped です。インスタンスから AMI を作成できます。

仮想化環境から以前にインポートした VM をエクスポートする機能。

ディスクを Amazon EBS スナップショットとしてインポートする機能。

VM Import は Linux 用 ENA ドライバをサポートしています。ENA のサポートは、元の VM に ENA ドライバまたは NVMe ドライバ、あるいはその両方がインストールされている場合にのみ有効になります。最新のドライバをインストールすることをお勧めします。

VM Import/Export の使用を開始する方法

最初に、VM を AMI としてインポートするか、またはインスタンスとしてインポートするかを決定する必要があります。

VM Import/Export の仕組み

Amazon EC2 で VM を使用するには、最初に仮想化環境からエクスポートしてから、Amazon Machine Image (AMI) またはインスタンスとして、Amazon EC2 にインポートする必要があります。

イメージのインポートとインスタンスのインポートの違い

スクリーンショット 2020-06-04 16.16.08.png

イメージのインポート

まず、エクスポート用に仮想マシンを準備して、サポートされているイメージ形式の 1 つを使用してエクスポートします。次に、VM イメージを Amazon S3 にアップロードし、イメージのインポートタスクを開始します。インポートタスクが完了したら、AMI からインスタンスを起動することができます。他のリージョンに AMI をコピーすると、それらのリージョンでインスタンスを起動できます。

スクリーンショット 2020-06-04 16.17.34.png

インスタンスのインポート

まず、エクスポート用に仮想マシンを準備して、サポートされているイメージ形式の 1 つを使用してエクスポートします。次に、VM イメージを Amazon S3 にアップロードし、インスタンスのインポートタスクを開始します。インポートタスクが完了したら、停止したインスタンスから AMI を作成できます。他のリージョンに AMI をコピーすると、それらのリージョンでインスタンスを起動できます。以前インポートしたインスタンスを仮想化環境にエクスポートすることもできます。

スクリーンショット 2020-06-04 16.18.52.png

VM Import/Export を使用して VM としてインスタンスをエクスポート

VM としてのエクスポートは、Amazon EC2 インスタンスのコピーをオンサイト仮想化環境にデプロイする場合に便利です。ほとんどの EC2 インスタンスは、Citrix Xen、Microsoft Hyper-V、および VMware vSphere にエクスポートできます。

Amazon Machine Image (AMI) から VM を直接エクスポートする

Amazon Machine Image (AMI) に基づく VM ファイルのエクスポートは、標準化された新しいインスタンスをオンサイトの仮想化環境にデプロイする場合に役立ちます。通常 AMI は、Citrix Xen、Microsoft Hyper-V、および VMware vSphere にエクスポートできます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Service Catalog

AWS Service Catalog

AWS Service Catalog では、AWS での使用が承認された IT サービスのカタログを作成および管理できます。この IT サービスには、仮想マシンイメージ、サーバー、ソフトウェア、データベースから包括的な多層アプリケーションアーキテクチャまで、あらゆるものが含まれます。AWS Service Catalog により、組織は一般的にデプロイされる IT サービスを集中管理でき、一貫性のあるガバナンスを達成し、コンプライアンス要件を満たすうえで役立ちます。エンドユーザーは、組織によって設定された制約に従って、必要な承認済みの IT サービスのみをすばやくデプロイできます。

ユーザー

  • カタログ管理者 (管理者)
    • 製品 (アプリケーションおよびサービス) のカタログを管理し、ポートフォリオに整理してエンドユーザーにアクセス権限を付与します。カタログ管理者は、AWS CloudFormation テンプレートの準備や制約の設定を行い、製品に割り当てられた IAM ロールを管理して、高度なリソース管理を提供
  • エンドユーザー
    • IT 部門またはマネージャーから AWS 認証情報を受け取り、AWS マネジメントコンソールを使用して、アクセス権限を付与されている製品を起動します。単純にユーザーと呼ばれることもあるエンドユーザーには、操作要件によって異なるアクセス許可を付与できます。たとえば、ユーザーに (使用する製品によって求められるすべてのリソースを起動および管理できるように) 最大限のアクセス許可レベルを付与することも、特定のサービス機能の使用に対するアクセス許可のみを付与することもできます。

プロビジョニングされた製品

AWS CloudFormation スタックにより、製品インスタンスを単一のユニットとしてプロビジョニング、タグ付け、更新、および終了できるので、製品のライフサイクルを管理しやすくなります。AWS CloudFormation スタックには、JSON 形式または YAML 形式で記述された AWS CloudFormation テンプレートとそれに関連するリソースのコレクションが含まれます。プロビジョニングされた製品はスタックです。エンドユーザーが製品を起動すると、AWS Service Catalog によってプロビジョニングされる製品のインスタンスは、製品の実行に必要なリソースを伴うスタックになります。

ポートフォリオ

ポートフォリオとは、製品の集合で、設定情報も組み込まれています。ポートフォリオは、特定の製品を使用できるユーザー、そのユーザーに許可される製品の使用方法の管理に役立ちます。AWS Service Catalog では、組織のユーザータイプごとにカスタマイズしたポートフォリオを作成し、適切なポートフォリオへのアクセス権を選択的に付与できます。製品の新しいバージョンをポートフォリオに追加すると、そのバージョンは、現在のすべてのユーザーに対して自動的に利用可能になります。また、自分のポートフォリオを他の AWS アカウントと共有して、そのアカウントの管理者がそのポートフォリオに制約 (ユーザーが作成できる EC2 インスタンスの制限など) を加えて配布できるようにすることができます。ポートフォリオ、アクセス権限、共有、制約を使用することで、組織のニーズおよび標準に合わせて適切に設定された製品をユーザーが起動するよう制御できます。

バージョニング

AWS Service Catalog では、カタログで複数のバージョンの製品を管理できます。これにより、ソフトウェアの更新または設定の変更に基づいて新しいバージョンのテンプレートと関連するリソースを追加できます。新しいバージョンの製品を作成すると、その製品にアクセスできるすべてのユーザーに更新が自動的に配信されるので、ユーザーは使用する製品のバージョンを選択できます。ユーザーは、製品の実行中のインスタンスを新しいバージョンにすばやく簡単に更新できます。

アクセス許可

ポートフォリオへのアクセス権をユーザーに付与すると、ユーザーはポートフォリオを閲覧して、それに含まれる製品を起動できます。AWS Identity and Access Management (IAM) アクセス許可を適用して、カタログを表示および変更できるユーザーを制御できます。IAM アクセス許可は IAM ユーザー、グループ、およびロールに割り当てることができます。ユーザーが IAM ロールが割り当てられている製品を起動すると、AWS Service Catalog では、そのロールで、AWS CloudFormation を使用して製品のクラウドリソースを起動します。IAM ロールを各製品に割り当てると、承認されていない操作を実行できるアクセス権限がユーザーに割り当てられないようにすることができます。また、ユーザーは、カタログを使用してリソースをプロビジョニングできます。

制約

制約によって、特定の AWS リソースを製品に対してデプロイできる方法を制御します。制約を使用して、製品に制限を適用し、ガバナンスまたはコスト管理を実現できます。AWS Service Catalog の制約にはさまざまなタイプがあります。起動の制約、通知の制約、テンプレートの制約です。

起動の制約では、ポートフォリオ内の製品に対してロールを指定します。このロールは、起動時にリソースをプロビジョニングするときに使用されるので、ユーザーがカタログから製品をプロビジョニングする機能に影響を与えずに、ユーザーのアクセス許可を制限できます。

通知の制約は、Amazon SNS トピックを使用してスタックのイベントに関する通知を受けることができます。

テンプレート制約では、製品を起動したときにユーザーが使用できる設定パラメータ (EC2 インスタンスタイプ、IP アドレス範囲など) を制限します。テンプレート制約では、汎用 AWS CloudFormation テンプレートを製品に再利用して、製品単位またはポートフォリオ単位でテンプレートに制限を適用します。

AWS Service Catalog でタグを管理する

AutoTags は、AWS Service Catalog のプロビジョニングされたリソースのオリジンに関する情報を識別するタグであり、AWS Service Catalog によってプロビジョニングされたリソースに自動的に適用されます。

TagOptions は、AWS Service Catalog で管理されるキーと値のペアであり、AWS タグを作成するためのテンプレートとして機能します。

AWS Service Catalog AutoTags

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VyOS 1.1系から1.3に移行する際の注意点

きっかけ

公式のVyOSバージョンがしばらく1.1.8のままで、Kernelバージョンが古かったりセキュリティアップデートもされていないので、最新の1.3.xをクリーンインストールして設定したところ細々とした変更が見られたので、移行する際にハマりやすい変更点を自分用備忘録として。

構成

WAN側GW:172.16.1.1
WAN側IP:172.16.1.10
LAN側IP:192.168.1.1

デフォルトゲートウェイの設定

1.1系まで使えてた「set system gateway-address "Address"」が使えなくなったので、スタティックルートで0.0.0.0の宛先をGWのIPに向けてあげる。

# 1.1.x系
set system gateway-address '172.16.1.1'
# 1.2以降
set protocols static route 0.0.0.0/0 next-hop 172.16.1.1

DNSの設定

基本的に同じだが、1.3からはDNSリフレクション攻撃の対策としてallow-fromでDNSの応答を許可するIPレンジを設定する必要がある。それに伴い「forwarding listen-on "Interface"」もサポート外となり、明示的に許可するLAN側アドレスを指定する仕様に変更された。

# 1.1.x系
set service dns forwarding listen-on 'eth1'
# 1.3以降
set service dns forwarding listen-address '192.168.1.1'
set service dns forwarding allow-from '192.168.1.0/24'

参考

Default Gateway/Route
https://docs.vyos.io/en/latest/system/default-route.html

DNS Forwarding
https://docs.vyos.io/en/latest/services/dns-forwarding.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon SESの通知結果をAmazon SNS、Lambdaを使用してDynamoDBに保存する

AmazonSESの送信結果を取得するために、今回はAmazonSNSをトリガーとして、LambdaからDyanamoDBに保存する仕組みを作っていきたいと思います。

この方法はAWSのサポートでもありましたので、今回はそれを試してみます。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/lambda-sns-ses-dynamodb/

前提として、AmazonSESに関しては既に設定済としています。

こちら、ブログでも公開しております。

DynamoDBの設定

まずは、DynamoDBのコンソールからテーブルを「SESNotifiations」という名前で作成します。

  • テーブル名に「SESNotifications
  • パーティションキーに「SESMessageId
  • ソートキーに「SESMailSendTime」

LambdaのIAMロールを設定

IAMロールの作成

次にLambda関数に付与する権限を作成するために、IAMコンソールからロールを作成していきます。

  • 信頼されたエンティティの種類から「AWSサービス」を選択
  • ユースケースの選択から「Lambda」を選択

Attachアクセス権限ポリシー

ロールにアタッチするポリシーを選択します。

  • 「AWSLambdaBasicExecutionRole」を選択

タグの追加

今回はタグ無しで次へ

確認

ロール名を「lambda-ses-execution」としてロールを作成します。

インラインポリシーの追加

作成したロールを選択して、DynamoDBへアクセスできるようにインラインポリシーを追加していきます。

ロールの一覧から「lambda-ses-execution」を選択して、「インラインポリシーの追加」をクリックします。

ポリシーの作成

DynamoDBへの書き込み権限を与えるために「ビジュアルエディタ」から権限を設定していきます。

  • サービスから「DyanamoDB」を選択
  • アクションから「書き込み」の「PutItem」を選択します
  • リソースの「ARNの追加」をクリックします。
  • 「ARNの追加」から先程作成したDynamoDBの「ARN」を設定します。

Lambda関数

それでは、実際に関数を作成していきます。ここでは、先程IAMで作成したロールを選択します。

  • 関数名に「sesnotificationscode」
  • ランタイムは「Node.js 12.x」を選択
  • 実行ロールは、先程作成した「lambda-ses-execution」を選択する

コード

SES通知の内容には「mailオブジェクト」「bonceオブジェクト」「deliveryオブジェクト」「complaintオブジェクト」があります。
その中身を解析してDynamoDBに保存していきます。

SES通知の内容についてもこちらを参照にして下さい。

https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/notification-contents.html

console.log('Loading event');
var aws = require('aws-sdk');
var ddb = new aws.DynamoDB({params: {TableName: 'SESNotifications'}});
exports.handler = function(event, context)
{
  console.log('Received event:', JSON.stringify(event, null, 2));

  var SESMessage = event.Records[0].Sns.Message
  SESMessage = JSON.parse(SESMessage);
  
  var SESMessageId = SESMessage.mail.messageId;
  var SESMailSendTime = SESMessage.mail.timestamp;
  var SESMessageType = SESMessage.notificationType;
  var SESMailObject = JSON.stringify(SESMessage.mail);
  var SESMailAddress = SESMessage.mail.destination.toString();
  
  var LambdaReceiveTime = new Date().toString();
  if (SESMessageType == 'Bounce')
  {
    var SESBounceObject = JSON.stringify(SESMessage.bounce);
    var SESbounceType = SESMessage.bounce.bounceType;
    var SESbounceSubType = SESMessage.bounce.bounceSubType;
    var SESBounceFeedbackId = SESMessage.bounce.feedbackId;
    
    var itemParams = {
      Item: {
        SESMessageId: {S: SESMessageId}, 
        SESMailSendTime: {S: SESMailSendTime},
        SESMailAddress: {S: SESMailAddress}, 
        SESMessageType: {S: SESMessageType},
        
        SESBounceObject: {S: SESBounceObject},
        SESbounceType: {S: SESbounceType},
        SESbounceSubType: {S: SESbounceSubType},
        SESBounceFeedbackId: {S: SESBounceFeedbackId}
      }};
    ddb.putItem(itemParams, function(err, data)
    {
      if(err) { context.fail(err)}
      else {
           console.log(data);
           context.succeed();
      }
    });
  }
  else if (SESMessageType == 'Delivery')
  {
    var SESDeliveryObject = JSON.stringify(SESMessage.delivery);
    var SESDeliveryTime = SESMessage.delivery.timestamp;
    var SESProcessingTimeMillis = SESMessage.delivery.processingTimeMillis.toString();
    
    var itemParamsdel = {
      Item: {
        SESMessageId: {S: SESMessageId}, 
        SESMailSendTime: {S: SESMailSendTime}, 
        SESMailAddress: {S: SESMailAddress }, 
        SESMessageType: {S: SESMessageType},
        
        SESDeliveryObject: {S: SESDeliveryObject},
        SESProcessingTimeMillis: {N: SESProcessingTimeMillis},
        SESDeliveryTime: {S: SESDeliveryTime}
    }};
    ddb.putItem(itemParamsdel, function(err, data)
    {
      if(err) { context.fail(err)}
      else {
          console.log(data);
          context.succeed();
      }
    });
  }
  else if (SESMessageType == 'Complaint')
  {
    var SESComplaintObject = JSON.stringify(SESMessage.complaint);
    
    var SESComplaintFeedbackType = SESMessage.complaint.complaintFeedbackType;
    var SESComplaintFeedbackId = SESMessage.complaint.feedbackId;
    var itemParamscomp = {
      Item: {
        SESMessageId: {S: SESMessageId}, 
        SESMailSendTime: {S: SESMailSendTime}, 
        SESComplaintFeedbackType: {S: SESComplaintFeedbackType},
        SESComplaintFeedbackId: {S: SESComplaintFeedbackId},
        SESMailAddress: {S: SESMailAddress }, 
        SESMessageType: {S: SESMessageType},
        
        SESComplaintObject: {S: SESComplaintObject}
      }};
    ddb.putItem(itemParamscomp, function(err, data)
    {
      if(err) { context.fail(err)}
      else {
          console.log(data);
          context.succeed();
      }
    });
  }
};

SNSトピック

SNSトピックの作成

続いて、Lambda関数のトリガーとなるSNSトピックを「ses_notifications_repo」という名称で作成していきます。

トリガーの設定

Lambdaコンソールの「トリガーを追加」から、先程作成したSNSのトピックを選択すると簡単に設定がされます。

SES Notificationの設定

最後にSESからSNSのトピックを設定していきます。

SESコンソールのEamail Addressで今回対象となるメール選択して、NotificationsからSNSトピックの「ses_notifications_repo」を選択します。Bounes、Complaints、Deliveriesのそれぞれで設定します。

これで、SESから送信したメールの通知結果を、SNSがトリガーとなってLambda関数を実行して、DynamoDBに保存する仕組みができました。

テスト

「Send Test Email」からテスト配信をして、DynamoDBに保存されるか確認していきます。

toに宛先を指定すると確認することができます。

  • 正常な配信の確認・・・success@simulator.amazonses.com
  • バウンス    ・・・bounce@simulator.amazonses.com
  • 苦情      ・・・complaint@simulator.amazonses.com

https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-email-simulator.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Serverless Frameworkでカスタムドメインを設定する

はじめに

ここではServerless Frameworkおいて、カスタムドメインを使用して
特定のドメインからServerless Frameworkでデプロイしたモジュールにアクセスできるようにします。

カスタムドメインを使用する前:
Serverless Frameworkから発行される適当なドメインにアクセスしてアプリケーションを表示
カスタムドメインを使用した後:
自ら指定したドメインにアクセスしてアプリケーションを表示

所要時間

証明書の発行などあるため、60分ほどかかる想定です。

手順

Route53にてホストゾーンを登録

Route53のコンソールから簡単に登録できるので詳細な手順は割愛します。
作成したホストゾーンのホストゾーンIDは後ほど使うのでメモしておきます。

Certificate ManagerよりSSL証明書の発行

Certificate ManagerからSSL証明書(ACM)を発行します。
ここも詳細な手順は割愛します。以下が注意するポイントです。
今回はドメイン検証で証明書を作成しましたが、AWSはドメイン作成まで30分ほどかかる場合があるとアナウンスしていました。
私の場合は5分ほどで完了しました。

  • 注意点
    • ワイルドカード証明書として発行しておいたほうが良いです。
    • US-east1(バージニア北部)リージョンで発行します。
    • Nameタグを設定します。「*.xxxxx.com」に対して証明書を発行したなら、Nameタグの値は「xxxxx.com」とします。

serverless-domain-managerをインストール

$ npm install serverless-domain-manager --save-dev

カスタムドメイン作成

  • serverless.ymlを編集

Customの部分に以下を追加します。また、プラグインにserverless-domain-managerも追加します。

plugins:
  - serverless-domain-manager

custom:
  customDomain:
    hostsZoneId: '<ホストゾーンID>'
    domainName: '${self:provider.stage}.xxxxx.com'
    certificateName: '*.xxxxx.com'
    certificateArn: '<SSL証明書のarn>'
    basePath: ''
    stage: ${self:provider.stage}
    createRoute53Record: true

例えばFlaskアプリ用のserverless.ymlだと、以下のようになります。

service: 
  name: <サービス名>

plugins:
  - serverless-python-requirements
  - serverless-wsgi
  - serverless-domain-manager

provider:
  name: aws
  runtime: python3.6
  stage: ${opt:stage, 'dev'}
  region: ap-northeast-1
  timeout: 300
  memorySize: 2048 # Overwrite the default memory size. Default is 1024
  deploymentBucket: ${self:service}-deployment

custom:
  name: ${self:service.name}
  wsgi:
    app: main.app
    packRequirements: false
  stage: ${opt:stage, self:provider.stage}
  logRetentionInDays:
    dev: "30"
    stg: "60"
    prod: "90"
  pythonRequirements:
    dockerizePip: non-linux
  customDomain:
    hostsZoneId: '<ホストゾーンID>'
    domainName: '${self:provider.stage}.xxxxx.com'
    certificateName: '*.xxxxx.com'
    certificateArn: '<SSL証明書のarn>'
    basePath: ''
    stage: ${self:provider.stage}
    createRoute53Record: true

functions:
  app:
    handler: wsgi.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'

  • カスタムドメイン作成

下記コマンドからカスタムドメインを作成します。

$ sls create_domain --aws-profile <プロファイル名>

ymlの記載上、デフォルトのstageはdevとしています。
stage名を指定したい場合は以下のようにコマンドを打ちます。

$ sls create_domain --aws-profile <プロファイル名> --stage <ステージ名>

(例)
$ sls create_domain --aws-profile sls-adm --stage prod

この時、Route53やACMに対して権限があるので、
Serverless Framework用にIAMユーザを発行している場合は権限の付与が必要です。

私はこのコマンドの実行の際にはAWS管理者権限を持った認証情報(アクセスキー/シークレットアクセスキー)を使用して行いました。
新しいプロファイルの作成は以下のコマンドから行えます。

$ serverless config credentials --profile <プロファイル名> --provider aws --key <アクセスキー> --secret <シークレットアクセスキー>

また、通常使用しているServerless FrameworkのIAMポリシーは下記URLに記載しています。
https://qiita.com/htanaka/items/631e11c1f69f128079f9

なにか問題がある場合は、下記コマンドを実行してから再度行うことで、
エラーをトラッキングできます。

export SLS_DEBUG=*

以下のような文言が表示されれば成功しています。40分ほどで設定完了するとのことなので少し待ちますが、
私の場合15分くらいで出来ているようでした。

Serverless: Custom domain xxxxx.com was created.
                        New domains may take up to 40 minutes to be initialized.

serverlessアプリケーションのデプロイ

アプリケーションをデプロイし、カスタムドメインでアクセスできるか確認します。
デプロイ時は管理者権限は必要ありません。

$ sls deploy --profile <プロファイル名>

下記のようにドメイン名がカスタムドメインで設定したものに変わっています。

Distribution Domain Name
  Domain Name: dev.xxxxx.com
  Target Domain: xxxxxxxx.cloudfront.net
  Hosted Zone Id: XXXXXXXXXXX

参考

同じ手順が公式にも載っているのでそちらも参照してみてください。
https://www.serverless.com/blog/serverless-api-gateway-domain/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

お名前メールライトとRoute53を連携する

お名前メールライトとRoute53の連携をするときに、ちょっとハマったので、メモ。

前提

  • お名前ドットコムでドメインを取得した
  • WebアプリケーションはAWSのS3に静的ホスティング
  • DNSはRoute53を使用
  • 同じドメインで、お名前メールライトを使用している

現象

お名前ドットコムのDNS設定で、Route53のNSを設定。
Webサイトは見れるが、メールの受信ができない。送信ができる。

解決方法

Route53にMXレコードを追加して、mx〇〇.gmoserver.jpに転送するようにする。
mx〇〇.gmoserver.jpという情報が全く見当たらず、苦労した。。

参考

Route53のMXレコード登録

この記事に助けられました。
お名前メールライトと、Route53の連携

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaでAWS S3オブジェクトの削除

AWS SDK for Javaを利用して、S3オブジェクトの削除ができます。

1つのオブジェクトの削除

bucket名とオブジェクトキーを指定すれば、指定オブジェクトの削除ができます。

try {
    final AmazonS3 s3 = new AmazonS3Client();
    s3.deleteObject(bucket_name, object_key);
} catch (AmazonServiceException e) {
    e.printStackTrace();
}

指定フォルダーにある全てのオブジェクトの削除

bucket名とフォルダー名を指定すれば、指定フォルダーにある全てのオブジェクトの削除ができます。

try {
    final AmazonS3 s3 = new AmazonS3Client();
  ObjectListing objListing = s3.listObjects(bucket_name,folder_nm);
    List<S3ObjectSummary> objList = objListing.getObjectSummaries();
    for (S3ObjectSummary obj : objList) {
         s3.deleteObject(bucket_name, obj.getKey());
    }
} catch (AmazonServiceException e) {
    e.printStackTrace();
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSに手動でデプロイする

AWSに入って手動でデプロイしたときのコマンドです。

前提
- EC2インスタンス作成済
- RDS DB(mysql)作成済

# updateして必要なものを入れる
sudo yum -y update
sudo yum install -y git curl unzip gcc openssl-devel readline-devel mysql-devel

# git config
git config --global user.name "xxxxxx"
git config --global user.email "xxxxxxxx@email.com"

# timezone
sudo timedatectl set-timezone Asia/Tokyo

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
~/.rbenv/bin/rbenv init

mkdir -p "$(rbenv root)"/plugins
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

rbenv install 2.6.6
rbenv global 2.6.6

gem install bundler

sudo curl -sL https://rpm.nodesource.com/setup_12.x | sudo bash -
sudo yum install -y nodejs

git clone https://github.com/branch_name/xxx.git
bundle install --without test development

bin/rails db:migrate RAILS_ENV=production
bundle exec rake assets:precompile RAILS_ENV=production

bin/rails s -e production
bin/rails db -e production

vi Gemfile # uniron gem 追加
bundle install

vi config/unicorn.conf.rb
# ==========================================
  # set lets
  $worker  = 2
  $timeout = 30
  $app_dir = "/home/ec2-user/branch_name" <= edit
  $listen  = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir
  $pid     = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
  $std_log = File.expand_path 'log/unicorn.log', $app_dir
  # set config
  worker_processes  $worker
  working_directory $app_dir
  stderr_path $std_log
  stdout_path $std_log
  timeout $timeout
  listen  $listen
  pid $pid
  # loading booster
  preload_app true
  # before starting processes
  before_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
    old_pid = "#{server.config[:pid]}.oldbin"
    if old_pid != server.pid
      begin
        Process.kill "QUIT", File.read(old_pid).to_i
      rescue Errno::ENOENT, Errno::ESRCH
      end
    end
  end
  # after finishing processes
  after_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
  end
# ==========================================

sudo amazon-linux-extras install nginx1.12
nginx -v
cd /etc/nginx/conf.d/
cd /var/lib
sudo chmod -R 775 nginx
sudo service nginx start
cd /etc/nginx/conf.d/
sudo vi default.conf

# ==========================================
error_log  /home/ec2-user/branch_name/log/nginx.error.log; <= edit
access_log /home/ec2-user/branch_name/log/nginx.access.log; <= edit
# max body size
client_max_body_size 2G;
upstream app_server {
  # for UNIX domain socket setups
  server unix:/home/ec2-user/branch_name/tmp/sockets/.unicorn.sock fail_timeout=0; <= edit
}
server {
  listen 80;
  server_name IPアドレス; <= edit
  # nginx so increasing this is generally safe...
  keepalive_timeout 5;
  # path for static files
  root /home/ec2-user/branch_name/public;
  # page cache loading
  try_files $uri/index.html $uri.html $uri @app;
  location @app {
    # HTTP headers
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }
  # Rails error pages
  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root /home/ec2-user/branch_name/public; <= edit
  }
}
# ==========================================

# 構文検査
nginx -t
sudo service nginx start
sudo nginx -s reload
sudo chmod -R +r /home/ec2-user/branch_name/public
sudo chmod -R +rwx /home/ec2-user/branch_name/tmp
sudo nginx -s reload
bundle exec unicorn_rails -c /home/ec2-user/circleci_study/config/unicorn.conf.rb -D -E production
ps -ef | grep unicorn | grep -v grep
chmod 701 /home/ec2-user

最後の方でずっと「forbidden 403」権限エラーが出ていて、すぐにはわかりませんでした。
権限つけたら見ることができるようになりました。

参考文献
個人開発のための Webサービス公開マニュアル - 秀和システム あなたの学びをサポート
難波 聖一 著
秀和システム (2019/12/25)
415ページ

参考ページ
(デプロイ編②)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで - Qiita

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VPCフローログのカスタム形式をCloudWatch Logs Insightでフィールド抽出してみた

はじめに

つい先日、久しぶりにAWSのVPCでフローログの作成をしました。
するとなんと、、CloudWatch Logsへの送信でCustom format(カスタム形式)にチェックを入れられるではないですか!!( ゚д゚)/
image.png

ということで、クラスメソッドさんのDevelopers.IOを検索してみると、GW中にアップデートされていました。

【参考】
VPCフローログのカスタム形式でCloudwatch Logsがサポートされました

カスタム形式とは

2019年9月までは、AWS default format(デフォルト形式)と呼ばれる決まったログフォーマットを採用していました。

デフォルト形式
<version> <account-id> <interface-id> <srcaddr> <dstaddr> <srcport> <dstport> <protocol> <packets> <bytes> <start> <end> <action> <log-status>

2019年9月に以下の7個のフィールドをカスタム形式のログフォーマットとして、選択式で指定することができるようになりました。
この時点では、送信先にAmazon S3のバケットしか指定することができませんでした。

vpc-id
subnet-id
instance-id
tcp-flags
type
pkt-srcaddr
pkt-dstaddr

2020年5月には、さらに4個のフィールドが追加され、CloudWatch Logsに対しても送信することができるようになりました。

region
az-id
sublocation-type
sublocation-id

カスタム形式(25フィールド全部入り)
<account-id> <action> <az-id> <bytes> <dstaddr> <dstport> <end> <instance-id> <interface-id> <log-status> <packets> <pkt-dstaddr> <pkt-srcaddr> <protocol> <region> <srcaddr> <srcport> <start> <sublocation-id> <sublocation-type> <subnet-id> <tcp-flags> <type> <version> <vpc-id>

※公式の日本語ドキュメントは古く、英語に切り替えないと新しい情報が表示されないという罠にやられて見逃しました(´;ω;`)

【参考】
Amazon VPC フローログにメタデータを追加
Flow log records(英語サイト)
フローログレコード(日本語サイト)

CloudWatch Logs Insightでクエリしてみよう

トラブルシューティングで通信フローを見たく、VPCフローログをCloudWatch Logsに入れて
Insightからクエリをしようとしましたが、デフォル形式のログフォーマットでないと
フィールド抽出されないという罠にハマりました。

【カスタム形式の場合】
image.png

【デフォルト形式の場合】
image.png

2020年6月時点において、自動検出されるフィールドは下記の参考URLの通りなっています。
ということでparseコマンドを用いて、@messageの内のフィールドをエフェメラルフィールドとして
抽出してクエリに利用することにしました。

【参考】
サポートされるログと検出されるフィールド

parseコマンドでパースする

まず、なにも変更せずにデフォルトのままクエリすると@messageにゴリっとログが出力されてしまいます。

デフォルト設定
fields @timestamp, @message
| sort @timestamp desc
| limit 20

image.png

次にparseコマンドでフィールド抽出してみます。

parseコマンドでのフィールド抽出
fields @timestamp
| parse '* * * * * * * * * * * * * * * * * * * * * * * * *' as `account-id`, action, `az-id`, bytes, dstaddr, dstport, end, `instance-id`, `interface-id`, logstatus, packets, pktdstaddr, pktsrcaddr, protocol, region, srcaddr, srcport, start, sublocationid, sublocationtype, `subnet-id`, tcpflags, type, version, `vpc-id`
| sort @timestamp desc

parseコマンドは、glob式を使用する方式と正規表現を使用する方式の2通りの記述が可能です。
今回は、前者のglob式でのフィールド抽出を行いました。フィールド数は25個ありますので
*(アスタリスク)を25個、半角スペースを空けて記述し、as以降、フィールド名を指定しています。

※エフェメラルフィールド名に英数字以外が含まれる場合は、`(アクサングラーブ)で囲わないとエラーになります。

いい感じにフィールド抽出されましたね。
image.png

これでIPアドレスやポート番号などの抽出されたフィールドを条件にクエリを作成することができます。
以下では、元のパケットの送信元IPアドレスが10.1.1.199となっているフローだけを検索することができます。

filterコマンドで条件指定
fields @timestamp
| parse '* * * * * * * * * * * * * * * * * * * * * * * * *' as `account-id`, action, `az-id`, bytes, dstaddr, dstport, end, `instance-id`, `interface-id`, logstatus, packets, pktdstaddr, pktsrcaddr, protocol, region, srcaddr, srcport, start, sublocationid, sublocationtype, `subnet-id`, tcpflags, type, version, `vpc-id`
| filter pktsrcaddr = '10.1.1.199'
| sort @timestamp desc

※filter条件に利用する値は、数値以外は'(シングルクォーテーション)で囲わないとエラーになります。

クエリ構文は、以下の公式ドキュメントも参考にしてみてください。

【参考】
CloudWatch Logs Insights クエリ構文

まとめ

いかがでしたでしょうか。
そのうち、CloudWatch Logs Insightの機能として、カスタム形式のログフォーマットも
自動検出フィールドでもっと便利にできるようになると思いましたが、小ネタとして記事にしてみました^^

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DynamoDBで条件に一致するレコードをまとめて削除する。

GUIでは一覧表示から全件チェックして削除できるが1度に実施するコマンドはない。
おそらくget-itemし表示しているデータを片っ端からdelete-itemしているのではなかろうか。
前方一致したレコードを全て削除する機会があり手でぽちぽちするのも面倒なので調べてみた。

そもそものputとdelete(CLI)

put-item

  • 数字もクオーテーションでくくる。
  • jsonも入れられる。ただ、クオートをエスケープする必要はある。
$ aws dynamodb put-item --table-name test --item '{"part":{"S":"hoge"}, "num":{"N":"1"}, "obj":{"S":"{\"test\": \"aaa\"}"}}'
  • 同じパーティションキーで叩くとエラーはしないで勝手に上書きされる。
  • そもそもレスポンスは何もない。
  • 返値が欲しいときはオプションで色々指定できる。
$ aws dynamodb put-item --table-name test --item '{"part":{"S":"hoge2"}, "num":{"N":"2"}, "obj":{"S":"{\"test\": \"aaa\"}"}}' --return-consumed-capacity TOTAL
{
    "ConsumedCapacity": {
        "TableName": "test",
        "CapacityUnits": 1.0
    }
}

delete-item

  • --keyは必須。削除対象に該当するキーを一つ書いておけばいい?削除対象を指定
  • --keyがそもそも条件に当てはまっていないとエラーする → あとからわかったが当然
  • このコマンドの条件は期待した条件に一致するものをずべて削除するものではない。
  • --expression-attribute-valuesではファイルを指定しても直接書いてもいい
  • --condition-expressionにダイレクトに書くと怒られる
  • 条件にbegins_withなどを指定する場合これらは関数としての記法を取る → https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html
OK
$ aws dynamodb delete-item --table-name test --key '{"part":{"S":"hoge"}}' --condition-expression "part = :part" --expression-attribute-values file://values.json

$ aws dynamodb delete-item --table-name test --key '{"part":{"S":"hoge"}}' --condition-expression "part = :part" --expression-attribute-values '{":part": {"S": "hoge"}}'

$ aws dynamodb delete-item --table-name test --key '{"part":{"S":"hoge"}}' --condition-expression "begins_with (part, :part)" --expression-attribute-values '{":part": {"S": "hoge"}}'
./values.json
{
    ":part": {"S": "hoge"}
}
NG
$ aws dynamodb delete-item --table-name test --key '{"part":{"S":"hoge"}}' --condition-expression "part = '{\"S\": \"hoge\"}'"
An error occurred (ValidationException) when calling the DeleteItem operation: Invalid ConditionExpression: Syntax error; token: "'", near: "= '{"

$ aws dynamodb delete-item --table-name test --key '{"part":{"S":"fuga"}}' --condition-expression "part = :part" --expression-attribute-values '{":part": {"S": "hoge"}}'
An error occurred (ConditionalCheckFailedException) when calling the DeleteItem operation: The conditional request failed

→ やりたいことはできないらしいので自分で組む必要があるっぽい。

条件に合致するデータを全件削除(boto3+lambda)

この記事を参考

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr

TABLENAME='test'
dynamodb = boto3.client('dynamodb')

# 条件に一致するレコードを全て取得
def getRecords(flt, val):
    records = []
    ExclusiveStartKey = None
    while True:
        if ExclusiveStartKey == None:
            response = dynamodb.scan(
                TableName=TABLENAME, 
                FilterExpression=flt,
                ExpressionAttributeValues=val,
                Limit=2 # テストとして上限を超えるケースを起こしてみるため2を設定
                )
        else:
            response = dynamodb.scan(
                TableName=TABLENAME, 
                FilterExpression=flt,
                ExpressionAttributeValues=val,
                Limit=2, # テストとして上限を超えるケースを起こしてみるため2を設定
                ExclusiveStartKey=ExclusiveStartKey
                )
        for res in response["Items"]:
            records.append(res)
        if "LastEvaluatedKey" in response:
            ExclusiveStartKey = response["LastEvaluatedKey"]
        else:
            break
    return records

# 指定条件のレコードを削除    
def deleteRecords(flt):
    dynamodb.delete_item(
        TableName=TABLENAME,
        Key=flt
        )
    return 0 # エラーハンドリングしたい

def lambda_handler(event, context):
    targets = getRecords(
        'begins_with(part, :part)',
        {":part": {"S": "hoge"}}, # eventでパラメータを受け取るなどしたら汎用性上がりそう
        )
    print("get records")
    print(targets)

    for target in targets:
        print(target["part"]["S"])
        res = deleteRecords(
            {'part': target["part"]}
            )

    return 0

ただ、この方法では削除1回1回にリクエストが発生するので一括してできる方法を検討したい。
なおbegins_withはqueryでは指定できなそうなのでscanを使用した。

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr

d = boto3.resource('dynamodb')
table = d.Table('test')
def lambda_handler(event, context):
    g = []
    ExclusiveStartKey = None
    while True:
        if ExclusiveStartKey == None:
            response = table.query(
                KeyConditionExpression=Key("part").begins_with("hoge"),
                Limit=2
            )
        else:
            response =  table.query(KeyConditionExpression="part",Limit=2, ExclusiveStartKey=ExclusiveStartKey)
        g.extend(response["Items"])
        if ("LastEvaluatedKey" in response) == True:
            ExclusiveStartKey = response["LastEvaluatedKey"]
        else:
            break
    print(g)

"errorMessage": "An error occurred (ValidationException) when calling the Query operation: Query key condition not supported"

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む