[AWS re:Invent 2018]LambdaのCustom RuntimeでHelloしてみる

# 概要
re:Invent2018に参加しています。
Keynote2日目でLambdaのCustom Runtimeが発表されました。

https://aws.amazon.com/blogs/aws/new-for-aws-lambda-use-any-programming-language-and-share-common-components/

![CustomRuntime.png](https://qiita-image-store.s3.amazonaws.com/0/317676/cb1e30bb-2475-2c85-d354-fbb4acecf9c9.png)

試してみたいと思います。

# Custom Runtimeを触ってみる
ドキュメントやチュートリアルが公開されているので、それらを参考にBashのスクリプトを実行してみます。

**ドキュメント**
https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html

**チュートリアル**
https://docs.aws.amazon.com/lambda/latest/dg/runtimes-walkthrough.html

## 事前準備
2つの関数ファイルを用意します。

- Runtime Bootstrap file
    ファイル名を*bootstrap*とした実行可能なファイルです。Custom Runtimeの場合、Lambdaはデプロイメントパッケージ内の *bootstrap* という名前のファイルを実行します。そのため、エントリーポイントとして利用します。

- Function file
    *bootstrap*から呼び出す関数です。処理の中身はこちらに記載します。

Custom Runtimeでは、関数実行時に下記の環境変数が提供されます。

|環境変数|概要|
|---|---|
|LAMBDA_TASK_ROOT|ハンドラ関数の場所|
|LAMBDA_TASK_ROOT|関数コードが格納されているディレクトリ|
|AWS_LAMBDA_RUNTIME_API|ランタイムAPIのホストとポート|

またイベントで受け取ったjsonファイルを扱うため、作業用のディレクトリを用意し、jqをダウンロードします。

```shell
$ mkdir lambda-custom-tutorial
$ cd lambda-custom-tutorial
$ curl -o ./jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
```

### Runtime Bootstrap fileの作成
エントリーポイントとなるBashスクリプトを作成します。

**bootstrap**

```shell
#!/bin/sh

# ハンドラ関数の読み込み
source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh"

# 処理
while true
do
  HEADERS="$(mktemp)"
  # イベントの取得
  EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
  REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)

  # ハンドラ関数の実行
  RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA")

  # 結果を返却
  curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
done
```

Bootstrap file内の処理では、専用のエンドポイントをポーリングしてイベントを取得するようです。またレスポンスもイベントごとに専用のエンドポイントが用意されるようで、そちらに返却をします。

### ハンドラー関数の作成
続いてハンドラー関数を作成します。
ここでは*name*キーで指定された値を取得し、"Hello xxxxx !"とレスポンスするハンドラー関数を作成します。

**handler.sh**

```shell
function handler () {
  EVENT_DATA=$1
  echo "$EVENT_DATA" 1>&2;
  NAME=$(echo $EVENT_DATA | $LAMBDA_TASK_ROOT/jq -r .name)
  RESPONSE="Hello, $NAME !"

  echo $RESPONSE
}
```

## デプロイメントパッケージの作成
作成したファイルとjqに実行権限を付与し、Zipで固めてパッケージ化します。

```shell
$ ls
bootstrap	handler.sh	jq
$ chmod 755 handler.sh bootstrap jq
$ zip handler.zip handler.sh bootstrap jq
  adding: bootstrap (deflated 30%)
  adding: handler.sh (deflated 20%)
  adding: jq (deflated 57%)
```
## Lambda関数の作成
作成したデプロイメントパッケージを利用してLambda関数を作成します。

```shell
$ aws lambda create-function \ 
> --function-name bash-runtime --zip-file fileb://handler.zip \ 
> --handler handler.handler --runtime provided \
> --role arn:aws:iam::<account-id>:role/lambda_basic_execution
{
    "FunctionName": "bash-runtime",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:<account-id>:function:bash-runtime",
    "Runtime": "provided",
    "Role": "arn:aws:iam::<account-id>:role/lambda_basic_execution",
    "Handler": "handler.handler",
    "CodeSize": 1710535,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2018-11-29T23:10:14.287+0000",
    "CodeSha256": "KgI7A7F4V3DurbrDLzB+faSld9Hdp7uocsDHdnthn7I=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "9eafbc9f-9e3f-4a2b-9c37-07384671da97"
}
```
Custom RuntimeでLambda関数を作成するときは、--runtimeを*provided*にします。
これでLambda関数の作成は完了です。

## Lambda関数をInvokeする
作成したLambda関数をInvokeして動作確認します。

```shell
$ aws lambda invoke --function-name bash-runtime --payload '{"name":"re:Invent2018"}' response.txt
$ cat response.txt
Hello, re:Invent2018 !
```

Custom RuntimeでLambda関数が実行され、レスポンスが返ってきているのが確認できました。

# まとめ
Lambdaのアップデートとしては、いくつかの言語追加程度かなと期待していたら、Custom Runtimeが追加されたことで一気に多くの言語でLambda関数を動作させることができるようになりました。触ってみた所感としては、デプロイパッケージの作成など少し慣れないといけない部分もありそうですが、自由度が高いので、これからいろいろな活用ノウハウが共有されるようになるのではないかと期待が膨らみました。楽しみですね。