AWS Lambda の Custom Runtimes を利用して Erlang を実行してみる #reinvent

この記事は AWS Lambda Custom Runtimes芸人 Advent Calendar 2018 の 4日目 です。

はじめに

keynoteの二日目で AWS Lambda でカスタムランタイムが利用できる発表があり、 AWS Lambda での言語選択の幅に選択肢が増えたことで、多くのアプリケーション開発者を熱狂させました。

【アップデート】 もう言語で悩まない!AWS LambdaでCustom Runtimeが利用できるようになりました! #reinvent

早速ですが、 Alert Logic から Erlang と Elixir の AWS Lambda についての記事が上がってました。

ErlangとElixirは、多くの開発者に人気のある言語ですが、これまでAWS Lambdaではサポートされていませんでした。 これらの言語は、独自の賛否両論があります。 Alert Logic は、 Erlang ネイティブランタイムと rebar3 を使用したビルドとパッケージングの統合サポート、およびElixirネイティブランタイムによるAWS Lambda機能のサポート、およびMixを使用した統合ビルド/パッケージサポートのサポートを含むAWSラムダ機能のサポートをリリースしました。

今回は、この記事を参考に AWS Lambda で Erlang を実行するところまでやってみたいと思います。

AWS Lambda で Erlang を実行

rebar3_erllambda の手順に沿って、やって見たいと思います。

Erlang build用のdocker imageを取得

AWS Lambda のカスタムランタイムとして、BEAM Runtimeを使用することで、Erlangを AWS Lambda で実行させることができます。

ビルド用の docker image、 AWS Lambda Erlang docker が提供されていますので、こちらを使用します。

$ docker pull alertlogic/erllambda:20.3

pull してきたら、以下のコマンドで run します。

$ docker run -it --rm -v `pwd`:/buildroot -w /buildroot alertlogic/erllambda:20.3 bash

スケルトンの作成

まずはHelloWorld用のスケルトンを準備しましょう。以下のコマンドでサンプルプロジェクトが作成されます。

$ rebar3 new erllambda name=eltest
===> Writing eltest/.edts
===> Writing eltest/.gitignore
===> Writing eltest/README.md
===> Writing eltest/rebar.config
===> Writing eltest/config/sys.config
===> Writing eltest/config/shell.config
===> Writing eltest/config/vm.args
===> Writing eltest/etc/eltest.template
===> Writing eltest/src/eltest.erl
===> Writing eltest/src/eltest.app.src
===> Writing eltest/test/.dummy

作成されたプロジェクトへ移動します。

$ cd eltest

スケルトンの生成が完了したら、gitリポジトリとしてプロジェクトディレクトリを初期化し、最初のスケルトンをチェックインしてタグ付けする必要があります。これは、プラグインがgit describeの出力をラムダ関数のバージョン番号として使用するために必要です。

git init
git add -A
git commit -m "Initial Skeleton"
git tag -m "Initial Skeleton" -a 0.0.0

プロジェクトのビルド

ビルド用に erlang のライブラリを tmp ディレクトリにコピーしておきます。

cp -r /usr/local/lib/erlang /tmp/20.3-lambda

コピーした先をビルド用の設定ファイルで指定します。

$ vi rebar.config

relx の項目に以下の値を追加します。

%% ...
{include_erts, "/tmp/20.3-lambda"},
{system_libs, "/tmp/20.3-lambda"},
%% ...

relx の項目はこのようになります。

%% Build a release from this project
{relx,
[
{release, { eltest, semver }, [eltest, erllambda]},

{sys_config, "./config/sys.config"},
{vm_args, "./config/vm.args"},

%% ...
{include_erts, "/tmp/20.3-lambda"},
{system_libs, "/tmp/20.3-lambda"},
%% ...

%% {dev_mode, true},
{include_src, false},

{extended_start_script, true}]
}.

以下のコマンドで順番にビルドし、 AWS Lambda にアップロードする zip ファイルを生成します。

$ rebar3 get-deps
$ rebar3 compile
$ rebar3 release
$ rebar3 erllambda zip

問題がなければ、 _build/default/ の配下に eltest-0.0.0.zip という、 AWS Lambda 用のパッケージファイルが生成されます。

AWS Lambda のデプロイ

CloudFormation テンプレートでのデプロイ方法も提供されていますが、まずは愚直に create-function コマンドで AWS Lambda を作成してみましょう。

--role に指定する AWS Lambda の実行ロールは任意のものにしてください。

aws lambda create-function \
--function-name eltest-function \
--memory-size 1024 \
--handler eltest \
--zip-file fileb://_build/default/eltest-0.0.0.zip \
--runtime provided \
--role arn:aws:iam::${YOUR_ACCOUNT_ID}:role/service-role/invokelambda

コマンドを実行すると、ランタイムに 「独自のランタイム」 が指定された AWS Lambda がデプロイされます。

AWS Lambda の実行

テストイベントを設定して、 AWS Lambda を実行してみましょう。テストイベントの値はデフォルトのもので問題ありません。

「テスト」で実行してみましょう。

動きました!

「Hello World!」が出力されました。

-module(eltest).
-behavior(erllambda).

-export([handle/2]).

%%---------------------------------------------------------------------------
-spec handle( Event :: map(), Context :: map() ) ->
ok | {ok, iolist() | map()} | {error, iolist()}.
%%%---------------------------------------------------------------------------
%% @doc Handle lambda invocation
%%
handle( _Event, _Context ) ->
erllambda:message( "Hello World!" ),
ok.

こちらはサンプルプロジェクトの erllambda:message で出力した結果が表示されています。

まとめ

提供されているサンプルプロジェクトを動かしただけですが、カスタムランタイム対応によって、アプリケーション開発の幅が広がっていくのを感じました。

次は Elixir も試してみたいと思います!

参考文献

AWS Lambda Custom Runtimes芸人 Advent Calendar 2018

AWS Lambda Custom Runtimes芸人 Advent Calendar 2018 という企画の元、すでに何名もの方が AWS Lambda で色々な言語を動かしてみることを試されています。

どこまでできるのか、楽しみですね!