AWS LambdaのCustom RuntimeでElixirを動かす【Windows環境】

Windows10環境にてAWS LambdaでElixirを動かした手順の記録です。

# 概要
・alertlogic社が公開しているAWS LambdaでErlang/Elixirを動かすためのライブラリ(erllambda)を用いる
・Windows環境だとビルドできないのでDocker環境で作業を行う

# 事前準備
Docker for Windowsをインストールし、Docker環境を構築しておく
https://docs.docker.com/docker-for-windows/

# Dockerイメージの取得・起動
以降、cmd.exeで作業

```bat
docker pull alertlogic/erllambda:20.3-elixir
docker run -it alertlogic/erllambda:20.3-elixir bash

```

# プロジェクト作成
とりえあえず/tmpで作業する

```bat
bash-4.2# cd /tmp
bash-4.2# mix new lambda_ex
bash-4.2# cd lambda_ex
```

# 依存ライブラリの取得・初期化
mix_erllambdaとerllambdaをmix.exsに追加する。

```elixir
defmodule LambdaEx.MixProject do
  use Mix.Project

  def project do
    [
      app: :lambda_ex,
      version: "0.1.0",
      elixir: "~> 1.7",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      {:mix_erllambda, "~> 1.0"},
      {:erllambda, "~> 2.0"},
      {:jiffy, "~> 1.0"}
    ]
  end
end
```

依存ライブラリの取得とreleaseモジュールの初期化を行う

```bat
bash-4.2# mix deps.get
bash-4.2# mix release.init
```

###  == 追記１ ==
distillery ver.2.1以降、リリース構成の初期化コマンドが`mix release.init`から`mix distillery.init`に変更になったようです。
参考：https://github.com/gigalixir/gigalixir-cli/issues/40

###  == 追記２ ==
Elixir ver.1.9.0からconfig/config.exsが`mix new`で自動生成されなくなっています。
とりあえず動かすためには以下コマンドで生成する必要があります。

```bat
bash-4.2# mkdir config
bash-4.2# echo use Mix.Config > config/config.exs
```



# 本体処理の実装
https://github.com/alertlogic/erllambda_elixir_example/blob/master/lib/erllambda_elixir_example.ex
上記ソースを参考に、eventとcontextの内容を出力し、200を返す処理をlib/lambda_ex.exに記述する

```elixir
defmodule LambdaEx do

  def handle(event, context) do
    :erllambda.message("event: ~p", [event])
    :erllambda.message("context: ~p", [context])

    {:ok, response({:ok, [[{"result", "OK"}]]})}
  end

  defp items_to_json(items) do
    items
    |> Enum.map(&:maps.from_list/1)
    |> :jiffy.encode
  end

  defp response({:ok, response}) do
    %{
      statusCode: "200",
      body: items_to_json(response),
      headers: %{
        "Content-Type": "application/json"
      }
    }
  end

  defp response({:error, response}) do
    %{
      statusCode: "400",
      body: response,
      headers: %{
        "Content-Type": "application/json"
      }
    }
  end
end
```

# ビルド
コンパイルエラーが起きないことをiexで確認する

```bat
bash-4.2# iex -S mix
........
iex(2)> LambdaEx.handle("aaa", "bbb")
event: <<"aaa">>

08:01:30.928 [info]  event: "aaa"
context: <<"bbb">>

08:01:30.928 [info]  context: "bbb"
{:ok,
 %{
   body: "[{\"result\":\"OK\"}]",
   headers: %{"Content-Type": "application/json"},
   statusCode: "200"
 }}
```

mix erllambda.releaseでビルドを行う

```bat
bash-4.2# MIX_ENV=prod mix erllambda.release
........
==> Assembling release..
==> Building release lambda_ex:0.1.0 using environment prod
==> Including ERTS 9.3.3.5 from /usr/local/lib/erlang/erts-9.3.3.5
==> Applying lambda specific overlays..
==> Packaging release..
```

# ビルドした結果出力されるzipファイルをWindows環境にコピーする
ビルド出力結果のzipを/tmpにコピー

```bat
bash-4.2# cp _build/prod/rel/lambda_ex/releases/0.1.0/lambda_ex.zip /tmp
```

もう１つcmd.exeを起動し、起動しているDockerコンテナのIDを取得

```bat
docker ps

CONTAINER ID        IMAGE                              COMMAND             CREATED             STATUS              PORTS               NAMES
13b21bb246f0        alertlogic/erllambda:20.3-elixir   "bash"              5 minutes ago       Up 5 minutes                            pensive_williamson
```

Windows環境へzipファイルをコピー

```bat
docker cp 13b21bb246f0:/tmp/lambda_ex.zip E:\WORK\zip
```

# Lambda関数の作成・設定
ランタイムを「独自のランタイムを使用する」としてLambda関数を作成する。
名前とロールは適当に設定する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/48472/e53ec90f-8ad0-20eb-ea36-9a0a4f57e542.png)

ハンドラには「Elixir.作成したプロジェクトのモジュール名」を設定する。ここでは「Elixir.LambdaEx」を設定
ビルドしたzipファイルをアップロードする。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/48472/9a6de9ea-70f7-a277-d2b0-dfa6d72322db.png)

初回起動にやや時間がかかるため、タイムアウトにはとりあえず10秒を設定した。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/48472/9a4eca81-dbe9-9330-6656-85f6450a7bde.png)

# Lambda関数の実行
テストイベントを作成し、テスト実行する。
パラメータはとりあえずデフォルトのまま。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/48472/79ebcbc1-174f-570f-24c1-d9b3e1af6e26.png)

テスト実行を行うと正常終了することを確認。
CloudWatchでeventとcontextの内容が出力されていることを確認した。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/48472/ef89b241-e0ab-03f5-eea5-deb4eeca85f3.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/48472/502334a9-7458-55fe-5924-8ef44d554e59.png)

# 所感
環境構築回りで試行錯誤が必要でしたが、なんとか動かすことができました。
erllambda_elixir_exampleにはDynamoDBへアクセスするサンプルコードが記載されているので、
次はAWSの各サービスを利用する処理を試してみたいと思います。

# 参考
[alertlogic/mix_erllambda](https://github.com/alertlogic/mix_erllambda)
[alertlogic/erllambda_elixir_example](https://github.com/alertlogic/erllambda_elixir_example)