Lambdaで取得した画像をKinesis Firehose経由でS3にアップロードする

Firehoseの動作確認のため、Lambdaから画像を流した時の個人メモ

[（参考）Firehose — Boto 3 Docs 1.9.42 documentation - Amazon AWS](https://boto3.amazonaws.com/v1/documentation/api/1.9.42/reference/services/firehose.html#Firehose.Client.put_record)
[（参考）BufferingHints](https://docs.aws.amazon.com/firehose/latest/APIReference/API_BufferingHints.html)

---

# Kinesis Firehose
- 「Create delivery stream」を押下

![000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/30c1c40f-110a-5440-7b90-c86b7a83d8dc.jpeg)

- Kinesisから転送はしないので「Direct PUT」とし、流す先としてS3を選択

![001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/376b007c-3f55-8940-a3da-e33c593adaa6.jpeg)

- S3バケット名を指定
    - ここで指定したバケットへのアクセスを含めたIAMロールが自動生成される

![015.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/703c10b8-721a-9ac4-ea50-617b65e33930.jpeg)

- 他はデフォルトのまま、作成

![004.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/1a5f8d19-3e58-2180-ddb9-a34a6cd5bf4f.jpeg)

- 数分後、作成されたことを確認

![005.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/afcc9046-51e5-020a-435f-05de7268b0cf.jpeg)



# Lambda
- Python3.9にて作成

![000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/96f5e451-bc7a-e5cb-f58a-fd8bf1c8d4a8.jpeg)

- 自動生成されたロールを選択

![001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/2bae0024-a575-ab22-909d-6c9f3e5b38d2.jpeg)

- ロールにアタッチされているポリシーを以下のように修正
    - 画像の取得元であるS3へのGetObjectを付与
        - 今回は取得したバケットの別フォルダにアップロードする
    - FirehoseへのPutRecordを付与
    - logsはデフォルトのまま

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "firehose:PutRecord",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:（リージョン名）:（AWSアカウント）:*",
                "arn:aws:s3:::（バケット名）/*",
                "arn:aws:firehose:（リージョン名）:（AWSアカウント）:deliverystream/（ストリーム名）"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:（リージョン名）:（AWSアカウント）:log-group:/aws/lambda/testingKinesisFirehose:*"
        }
    ]
}
```

- ソース修正

```lambda_function.py
import os
import logging
import boto3
import json

# ログ設定
logger = logging.getLogger(__name__)
logger.setLevel(os.environ['LOG_LEVEL'])

# 環境変数から取得
BACKET_NAME = os.environ['BACKET_NAME']
FILE_PATH = os.environ['FILE_PATH']
DELIVERY_STREAM = os.environ['DELIVERY_STREAM']


# S3から指定したバケット、フォルダ、ファイル名の画像を取得する
# 取得できる画像サイズはLambdaのメモリーに依存
# return:画像のバイナリデータ
def get_img_from_s3():
    logger.debug('start get_img_from_s3()')

    s3 = boto3.client('s3')
    response = s3.get_object(Bucket=BACKET_NAME, Key=FILE_PATH)
    body = response['Body'].read()

    logger.debug('end get_img_from_s3()')

    return body


# 画像をFirehoseに流す
# img:画像のバイナリデータ
# return:プットした結果
def put_to_firehose(img):
    logger.debug('start put_to_firehose()')
    
    firehose = boto3.client('firehose')
    response = firehose.put_record(
        DeliveryStreamName=DELIVERY_STREAM,
        Record={
            'Data': img
        }
    )

    logger.debug('end put_to_firehose()')

    return response


def lambda_handler(event, context):
    logger.debug('start lambda_handler()')

    img = get_img_from_s3()
    result = put_to_firehose(img)

    logger.debug('end lambda_handler()')

    return result

```

- 環境変数設定

![019.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/8ca07d3a-fae4-f15e-d09e-977d117ff45e.jpeg)


# 動作確認
- 流す画像をS3に配置

![020.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/64c891f2-b985-1973-0155-e123b65a1bdf.jpeg)


- 任意のテストイベントJSONを設定し、実行

![021.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/ca866113-3139-cfee-b84b-50ae37bd61cb.jpeg)

- Lambda実行後、**5分後**にS3を確認し、ファイルをダウンロード

![022.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/0ec7ee5d-85f2-5bed-e2f0-0e4fd6796c71.jpeg)

![023.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/46bd87d2-d6a0-ddf1-bb1b-32fad912f3ff.jpeg)

- 取得したファイルに拡張子をつけ、pngファイルとして開く

![024.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/90fb729c-d1d6-b330-f1cd-22f7cf84d981.jpeg)

# 感想
- 仕様的に流れてきたログ等をいったん溜めてS3にアップロードしている
    - S3へのアップロードが5MBか300秒に達したときになっているため  
      連続して流した場合1つのファイルに2つ分の画像が含まれる
    - ファイル名がFirehoseによってリネームされる
        - ログ等をまとめてS3に流すのであれば  
          一意のファイル名をつけてくれるので助かるが……

![026.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/caa0e1f4-8eb9-dbb0-0efb-efa2be01972b.jpeg)

![029.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/52ba4013-330d-4872-f8cc-690afaca782c.jpeg)