【re:Invent】AWS Lambda コンテナ試して見た

AWS Lambda Container Support が発表されました。最大 **10GB** のサイズのコンテナイメージがデポロイできます。現時点サポートされている、全てのランタイム（Python、Node.js、Java、.NET、Go、Ruby）のベースイメージを提供します。

## 全体像
従来は Lambda コンソールからソース編集かアップロードできますが、コンテナイメージ使う場合、一旦 `Amazon ECR` に保存し、Lambda コンソールからデポロイを行います。

![Lambda (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/b00ae1fa-23e7-64a6-1ade-24442fb673be.png)

## コンテナイメージ

### Amazon ECR (Amazon Elastic Container Registry)
コンテナイメージを AWS に保管しますので、まず `ECR` 作ります。

```sh
aws ecr create-repository \
  --repository-name lambda-repo \
  --region ap-northeast-1
```

下記結果が返ってきます、`repositoryUri` をメモしておきましょう。

```sh:Output
{
  "repository": {
    "repositoryArn": "arn:aws:ecr:ap-northeast-1:[ACCOUNT_ID]:repository/lambda-repo",
    "registryId": "[ACCOUNT_ID]",
    "repositoryName": "lambda-repo1",
    "repositoryUri": "[ACCOUNT_ID].dkr.ecr.ap-northeast-1.amazonaws.com/lambda-repo",
    "createdAt": "2020-12-04T08:03:18+00:00",
    "imageTagMutability": "MUTABLE",
    "imageScanningConfiguration": {
      "scanOnPush": false
    },
    "encryptionConfiguration": {
      "encryptionType": "AES256"
    }
  }
}
```

### Dockerfile
イメージビルド用の `Dockerfile`を準備します。テストコードも含めて作ります。
Base image は AWS が提供する `amazon/aws-lambda-nodejs:12` を使用します。

```dockerfile:Dockerfile
# AWS Docker Image
FROM amazon/aws-lambda-nodejs:12

WORKDIR /usr/local/app

# Port
EXPOSE 8000

# Application
RUN echo $'\n\
  exports.handler = async (event) => { \n\
    const response = { \n\
      statusCode: 200, \n\
      body: JSON.stringify(\'Hello from Lambda!\'), \n\
    }; \n\
    return response; \n\
  }; \n\
  ' > index.js

CMD [ "/usr/local/app/index.handler" ]
```

最終的に **ECR** に保存して使うなので、`${repositoryUri}:${tag}` のフォーマットでタグを付けます。

```sh:ACCOUNT_IDは環境に合わせて修正する
# docker build
docker build -t [ACCOUNT_ID].dkr.ecr.ap-northeast-1.amazonaws.com/lambda-repo:latest .

# ECR login (Linux)
aws ecr get-login-password | docker login --username AWS --password-stdin [ACCOUNT_ID].dkr.ecr.ap-northeast-1.amazonaws.com

# docker push
docker push [ACCOUNT_ID].dkr.ecr.ap-northeast-1.amazonaws.com/lambda-repo:latest
```

## AWS Lambda デポロイ
AWS Lambda のコンソールで **[Create Function]** をクリックします。 **[Container image]** を選択し、**[Browse images]** をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/e79cf67e-dde3-6a66-f7d2-a30856eafb86.png)

先ほど作った **ECR Repository** から、 `latest` タグ付けたコンテナイメージを選択し、**[Select image]** をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/3be6c9bc-460b-6db1-6d02-fc953d25b3ba.png)

最後は **[Function name]** を入れて、他の設定は全部デフォルトのままで、**[Create function]** をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/3756eabd-d7c7-5f04-376a-d4b7196eb65d.png)

## テスト
Lambda コンソールでテストしましょう。想定通りの結果が返ってきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/7ada168c-e491-86a7-a9dc-4da0372140f6.png)

## パフォーマンス

コンテナイメージ大きいため、やはりコードスタート気になりますね。

イメージサイズ (MB) | Lambdaメモリ (MB) | コードスタート | 正常コール (５回平均）
---|---|---|---
146.71 | 128 | Duration (11.20 ms) <br>Billed duration (**619 ms**) | Duration (7.6ms) <br>Billed duration (8 ms)
146.71 | 640 | Duration (2.28 ms) <br>Billed duration (**584 ms**) | Duration (1.84ms) <br>Billed duration (2 ms)
146.71 | 1280 | Duration (1.98ms) <br>Billed duration (**459 ms**) | Duration (0.95ms) <br>Billed duration (1 ms)

結果から見ると、メモリを積めば、ある程度改善できます。

## おまけに
Lambda コンテナベースイメージの自作方法は、公式ドキュメントに Python のみの記載があります。
日本語の翻訳またなので、英語のみとなります。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images-create.html