Serverless FrameworkでLambdaにDockerコンテナをデプロイしてみた

## 概要

この記事は Serverless Advent Calendar 2020 の24日目の投稿となります。

[Serverless Advent Calendar 2020 - Qiita](https://qiita.com/advent-calendar/2020/serverless)

先日、AWS LambdaでDockerコンテナが実行できるようになりました。

[AWS Lambda now supports container images as a packaging format](https://aws.amazon.com/jp/about-aws/whats-new/2020/12/aws-lambda-now-supports-container-images-as-a-packaging-format/)

また、Serverless Frameworkがこれに対応し、以下のような記述で、デプロイできるようになりました。

```yaml
service: example-service

provider:
  name: aws

functions:
  someFunction:
    image: <account>.dkr.ecr.<region>.amazonaws.com/<repository>@<digest>
```

[Container Image Support for AWS Lambda](https://www.serverless.com/blog/container-support-for-lambda)

今回は、この機能を試してみました。

## Serverless Frameworkのセットアップ

以下のコマンドで、Serverless Frameworkをインストールします。

```bash
$ npm install -g serverless
```

今回は、以下のバージョンで動作確認をしています。

```bash
$ serverless version
Framework Core: 2.15.0
Plugin: 4.2.0
SDK: 2.3.2
Components: 3.4.3
```

## Serverless Frameworkのサイトにログインする

アカウントがない場合は、 以下のURLからアカウントを作成してください。

[https://app.serverless.com/](https://app.serverless.com/)

アカウントを作成したら、以下のコマンドでログインします。

```bash
$ serverless login
```

## AWS ECRのセットアップ

本記事では、Serverless Frameworkで指定するDockerイメージは、AWS ECRのリポジトリにあることを前提としています。

AWS ECRにDockerイメージをアップロードする手順を記載しています。

### AWS ECRにログインする

以下のコマンドで、AWS ECRにログインします。

```bash
$ aws ecr get-login-password --region <region> \
  | docker login --username AWS \
    --password-stdin <account>.dkr.ecr.<region>.amazonaws.com
```

<region> <account> を各自の環境に合わせて、置き換えて実行してください。

必要であれば、`aws`コマンドの`—profile` オプションなどで認証情報も設定してください。

### Dockerイメージをビルドする

以下のようなDockerfileを用意します。

```docker
FROM public.ecr.aws/lambda/nodejs:12
ARG FUNCTION_DIR="/var/task"

# Create function directory
RUN mkdir -p ${FUNCTION_DIR}

# Copy handler function and package.json
COPY index.js ${FUNCTION_DIR}
COPY package.json ${FUNCTION_DIR}

# Install NPM dependencies for function
RUN npm install

# Set the CMD to your handler
CMD [ "index.handler" ]
```

このビルドでは、 `package.json` と `index.js` が必要です。

以下のコマンドで、 `package.json` を生成します。

```bash
$ npm init
```

以下の内容の `index.js` を作成します。

```jsx
exports.handler =  async function(event, context) {
  console.log("EVENT: \n" + JSON.stringify(event, null, 2))
  return context.logStreamName
};
```

準備が整いましたので、推奨されている`<service>-<stage>-<functionName>` の形式のイメージ名を指定し、ビルドします。

```bash
$ docker build -t slssample-d-sample .
```

### AWS ECRリポジトリを作成し、イメージをプッシュする

下記のコマンドを実行して、AWS ECRにリポジトリを作成します。

```bash
$ aws ecr create-repository --repository-name slssample-d-sample --image-scanning-configuration scanOnPush=true
```

下記のコマンドで、先ほど作成したリポジトリにイメージをプッシュします。

```bash
$ docker tag slssample-d-sample:latest \
  <account>.dkr.ecr.<region>.amazonaws.com/slssample-d-sample:latest
$ docker push <account>.dkr.ecr.<region>.amazonaws.com/slssample-d-sample:latest
```

コマンドを実行すると、以下のような情報が出力されると思います。

```bash
latest: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 2201
```

ダイジェストである`sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` の部分はメモしておいてください。

## Serverless Frameworkでデプロイする。

Dockerイメージの準備ができたので、Lambda関数をデプロイします。

以下の内容の `serverless.yml` ふぁいるを作成します。

```yaml
service: sls-docker-image

provider:
  name: aws
  region: ap-northeast-1

functions:
  someFunction:
    image: <account>.dkr.ecr.<region>.amazonaws.com/slssample-d-sample@sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

functions.someFunction.imageの部分で、Dockerイメージの参照情報を記述しています。

先ほどメモしたダイジェストを `@sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`のように記述します。

以下のコマンドを実行すると、Serverless Frameworkのデプロイ処理が走ります。

```bash
$ sls deploy
```

デプロイされたLambdaが正常に走ることが確認できると思います。

## 

## 参考

[https://www.serverless.com/blog/container-support-for-lambda/](https://www.serverless.com/blog/container-support-for-lambda/)