概要

2020年12月にLambdaのコンテナ実行に対応(リンク)しているが、任意のプログラムを実行するために Lambda ランタイム APIに準拠して実装する必要がある。 (カスタムランタイムは2020年8月にAmazon Linux2に対応(リンク

このページでは、公式チュートリアルにあるbashをコンテナ経由で実行する。

既存のzipファイル化する方法とさほど変わらないがECRにdockerイメージを置いとくだけなのでデプロイが若干楽になる気がする。

以下の作業を行う。

  1. カスタムランタイムのためファイル用意
  2. Dockerfile作成
  3. ECRにdockerイメージをpush
  4. pushしたdockerイメージを使ったLambda関数を作成
  5. イメージの更新

CDKも対応済みだったので試してみた。

手動による作業

カスタムランタイムのためファイル用意

適当なディレクトリに bootstrapfunction.sh を作成。 両方とも公式チュートリアルと同じコードを使用。このコードでは受け渡したEventをそのまま返している。

コメントにあるようにLambdaからのイベントデータは function.sh では、ShellScriptの引数として渡されるので、もしbash以外の環境で実行するならコマンドライン引数やファイルに一時保存するなどして引き渡せそう。

また、結果はRESPONSEに代入しcurlでAWS Lambdaに渡している。

#!/bin/sh

set -euo pipefail

# Initialization - load function handler
source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh"

# Processing
while true
do
  HEADERS="$(mktemp)"
  # Get an event. The HTTP request will block until one is received
  EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")

  # Extract request ID by scraping response headers received above
  REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)

  # Run the handler function from the script
  RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA")

  # Send the response
  curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
done
function handler () {
  EVENT_DATA=$1
  echo "$EVENT_DATA" 1>&2;
  RESPONSE="Echoing request: '$EVENT_DATA'"

  echo $RESPONSE
}

Dockerfile作成

DockerHubのリポジトリ のUsageを参考に作成。以下ではDockfileで実行権限をつけているが、最初から実行権限をつけたファイルをCOPYすればいいと思う。


FROM public.ecr.aws/lambda/provided:al2

COPY bootstrap ${LAMBDA_RUNTIME_DIR}
COPY function.sh ${LAMBDA_TASK_ROOT}

RUN chmod +x ${LAMBDA_RUNTIME_DIR}/bootstrap \
&& chmod +x ${LAMBDA_TASK_ROOT}/*.sh

CMD [ "function.handler" ]

ECRにdockerイメージをpush

ECRレポジトリを作り、「プッシュコマンドの表示」の通りビルドしてプッシュする。

pushしたdockerイメージを使ったLambda関数を作成

コンテナイメージURIを指定して、Lambdaを作成する。

テストデータを作成する。

テストデータを実行する。Eventで渡したデータがそのまま返ってきていることを確認する。

イメージの更新

Lambdaのページで「新しいイメージをデプロイ」をクリックすれば最新のイメージをpullして反映してくれた。

CDKによる作業

ドキュメントを見る限りすでに使えそうだったので試してみる。

先程のDockerfilebootstrapfunction.sh を cdkプロジェクト下の images ディレクトリに移した。 stackを以下のように定義した(Pythonを使用)。

from aws_cdk import (
    core,
    aws_lambda,
)

class AwsLambdaContainerTestStack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Lambdaを作成
        aws_lambda.DockerImageFunction(
            self,
            "AssetFunction",
            code=aws_lambda.DockerImageCode.from_image_asset("./images")
        )

勝手にビルドしてECRリポジトリを作ってプッシュしてLambda関数を作ってくれた。 ECRを別に作成して指定することも可能のようだった(ドキュメント参照)。