コンテナランタイムとしての AWS Lambda

2024-02-01
デベロッパーのためのクラウド活用方法

Author : 井口 奏大 (MIERUNE Inc.)

2023 年 11 月に誕生から 9 周年を迎えてなお、AWS Lambda は進化を続けています。最近の進化を見ると、Lambda は「関数」の枠を超え「コンテナ」との親和性が高まっているように思います。本記事では、コンテナランタイムとしての AWS Lambda の利用可能性を提示します。

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


AWS Lambda とコンテナの関係

Lambda は 2014 年から存在しますが、コンテナイメージをサポートしたのは 2020 年 12 月のことで (参考 : AWS Lambda の新機能 – コンテナイメージのサポート)、その歴史からするとごく最近のことと言えます。① 10 GB までのサイズのイメージをデプロイできる ② 依存関係の解決が容易という点で、Lambda の利便性が大きく向上しました。

ただしコンテナイメージであっても Lambda のエントリーポイントーいわゆる handler 関数が必要です。つまり Lambda 専用 = Lambda 環境外では動かないイメージとしなければならず、コンテナが提供する価値のひとつ「ポータビリティ」を享受出来ません。

ところがこの状況は AWS Lambda Web Adapter の登場により一変しました。Lambda Web Adapter を利用すると、HTTP を話す任意のコンテナイメージを Lambda で動作させることが出来ます。この点で、Lambda はもはや「関数」にとどまらない領域に到達したと言えるのではないでしょうか。

AWS のコンテナ環境といえば Amazon Elastic Container Service (Amazon ECS) / Amazon Elastic Kubernetes Service (Amazon EKS)、新しいもので AWS App Runner という選択肢がありますが、Lambda Web Adapter の登場により Lambda が選択肢に加わったと言えます。以降、コンテナランタイムとしての Lambda を深堀していきます。

なお Lambda Web Adapter の使用感については Lambda Web Adapter でウェブアプリを (ほぼ) そのままサーバーレス化する で詳しく解説されていますので割愛します。


AWS Lambda でコンテナ開発をはじめよう

関数の作成時に「コンテナイメージ」を選択することで、コンテナを動かす Lambda を作成することが出来ます。

しかし関数作成時にコンテナイメージを指定する必要があるため、先に Amazon Elastic Container Registry (Amazon ECR) にイメージをプッシュしておく必要があります。

クリックすると拡大します

コンテナイメージの作成

ここで作成するイメージは、HTTP 通信を行ういわゆる WebAPI ならなんでも構わないのですが、hello world だと味気なく前述の例から進歩がないので、今回は筆者の関心を踏まえ、OSSの 経路検索サーバー Valhalla を動かしてみます。

Valhalla は自由に使える地図「OpenStreetMap (OSM)」の道路データを利用した経路検索ールーティングエンジンです。REST-API として利用でき、経路検索にまつわるいくつかのエンドポイントが提供されています。

Valhalla は公式のコンテナイメージが公開されています。Valhalla | docker image を build し、日本全域の地図を読み込む - Qiita では公式イメージを拡張して、経路データを内包したコンテナイメージが示されています。

このイメージを参考に、Web Adapter を組み込みます。テストのため北海道のデータを利用しています。OSM には全世界のデータがありますがイメージサイズに影響するため留意が必要です。

FROM valhalla/valhalla:run-latest

# Install Web Adapter
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.7.0 /lambda-adapter /opt/extensions/lambda-adapter
ENV PORT=8002
ENV READINESS_CHECK_PATH=/status

# build valhalla tiles
WORKDIR /app
RUN wget http://download.geofabrik.de/asia/japan/hokkaido-latest.osm.pbf
RUN mkdir -p valhalla_tiles
RUN valhalla_build_config --mjolnir-tile-dir ${PWD}/valhalla_tiles --mjolnir-tile-extract ${PWD}/valhalla_tiles.tar --mjolnir-timezone ${PWD}/valhalla_tiles/timezones.sqlite --mjolnir-admin ${PWD}/valhalla_tiles/admins.sqlite > valhalla.json
RUN valhalla_build_tiles -c valhalla.json hokkaido-latest.osm.pbf
RUN valhalla_build_extract -c valhalla.json -v
RUN rm hokkaido-latest.osm.pbf

EXPOSE 8002

CMD ["valhalla_service", "valhalla.json", "1"]

ここで、Lambda Web Adapter を利用する際の留意点がふたつあります:

  1. コンテナが listen するポートを環境変数 PORT で指定する
  2. ヘルスチェック用のエンドポイントを環境変数 READINESS_CHECK_PATH で指定する

ポートはもちろんですが、ヘルスチェックが出来ないと「関数」を実行する事が出来ません。このことを知らないとハマることがあるので留意してください。

ここで、イメージをビルドしてみましょう。OSM データのダウンロード・経路データの作成を含むため、ある程度時間がかかります。

docker build -t lambda-container-sample .

ビルドが完了したら、ローカルで動作確認をしてみます。

docker run -p 8002:8002 lambda-container-sample

http://localhost:8002/status にアクセスして、200 でレスポンスが帰ってくれば正常に動作しています。

他のエンドポイント、例えば特定の地点からの到達圏を計算する ./isochrone を利用してみます。次のようにリクエストすると、何かしら結果が返ってくると思います。

curl http://localhost:8002/isochrone?json=%7B%22locations%22%3A%5B%7B%22lat%22%3A43.052668%2C%22lon%22%3A141.320872%7D%5D%2C%22costing%22%3A%22pedestrian%22%2C%22contours%22%3A%5B%7B%22time%22%3A15.0%2C%22color%22%3A%22ff0000%22%7D%5D%7D

# response as GeoJSON
{"features":[...],"type":"FeatureCollection"}

確認できたらコンテナは停止しておきましょう。

Amazon ECR へのプッシュ

続いて、Amazon ECR にイメージをプッシュしていきます。まず Amazon ECR にリポジトリを作成します。

クリックすると拡大します

以下のコマンドで、Docker クライアントに対して ECR の認証を受けます (要credential)。

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <AWSのユーザーアカウントIDの12桁>.dkr.ecr.ap-northeast-1.amazonaws.com

Amazon ECR に先ほど作成したイメージをプッシュします。

docker tag lambda-container-sample:latest <AWSのユーザーアカウントIDの12桁>.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container-sample:latest
docker push <AWSのユーザーアカウントIDの12桁>.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container-sample:latest

コンソールでプッシュされたイメージを確認出来ます。

クリックすると拡大します

Lambda 関数の作成・デプロイ

ここで Lambda に戻り、関数を作成していきます。「コンテナイメージ」を選択し、先ほどプッシュしたイメージを指定します。

他に特別な操作はなく、これだけで Lambda 関数の作成は完了です。

クリックすると拡大します

Lambda 関数で HTTP リクエストを受ける

関数の作成は完了しましたがこれだけでは処理を実行することが出来ません、Lambda 関数はなんらかの「トリガー」で動作するのでした。

Amazon API Gateway を利用すれば HTTP リクエストを Lambda のトリガーとすることが出来ますね。しかしここでは **Function URLs(関数URL)** を利用し、Lambda 単体で HTTP リクエストを受け付けてみます。

Lambda 関数 URL は 2022 年 4 月にリリースされた Lambda の機能です。この機能を利用すると Lambda 関数に URL を発行され、この URL に対するリクエストが Lambda 関数のトリガーとなります。

関数 URL を作成する

Lambda のコンソール画面の「設定」から作成できます。関数 URL には AWS IAM 認証を利用することが出来ますが、ここでは認証なしで作成します。

クリックすると拡大します

クリックすると拡大します

関数 URL を作成すると、URL が発行されます。

クリックすると拡大します

この URL へのリクエストが Lambda 関数のトリガーとなり、すなわち Valhalla サーバーへのリクエストとなります。先ほどローカルでテストしたときと同様に、いくつかのエンドポイントにリクエストしてみましょう。

curl https://<ランダム文字列>.lambda-url.ap-northeast-1.on.aws/status

curl https://<ランダム文字列>.lambda-url.ap-northeast-1.on.aws/isochrone?json=%7B%22locations%22%3A%5B%7B%22lat%22%3A43.052668%2C%22lon%22%3A141.320872%7D%5D%2C%22costing%22%3A%22pedestrian%22%2C%22contours%22%3A%5B%7B%22time%22%3A15.0%2C%22color%22%3A%22ff0000%22%7D%5D%7D

localhost でテストした際と同じ結果が帰ってくると思います。なお少しレスポンスが遅いですが、割り当てメモリを少し増やせば十分実用的な速度になります。

このように、Lambda Web Adapter と関数 URL を組み合わせることで、Lambda 単体で非常に手軽にコンテナをデプロイ出来ます。


他のコンテナランタイムとの比較

他のコンテナランタイムーここでは Amazon ECS と AWS App Runner と比較したメリット・デメリットを述べます。

メリット

  • 高いコストパフォーマンス:充実の無料枠・実行時間のみ課金
  • 最高のスケーラビリティ
  • デプロイ容易性

デメリット

  • コールドスタート : Provisioned Concurrency を利用することで緩和可能ではある
  • スケールアップ・ダウンがあまり柔軟ではない (設定可能なのが vRAM のみ)
  • VPC との相性 : 悪くはないが、回避策が必要なことがある (後述)

VPC リソースと連携する必要がある場合は多少検討が必要ですが (後述)、Lambda がもたらすメリットは非常に大きいと考えます。


実践的構成へ

利用者が限られた PoC や単機能サーバーなら前述の Lambda 単体の構成で十分だと思いますが、現実のアプリケーション開発ではより実践的な構成が必要になるでしょう。とはいえ Lambda で任意のコンテナが動くようになっただけで、根本的に何かが変わるということはありません。

ここでは、筆者が業務内外で実践している構成を紹介します。

この構成で重要なことは:

  1. Amazon CloudFront のオリジンに Lambda (関数 URL) を指定している
  2. Amazon VPC 内の Lambda にも関数 URL を発行している
  3. AWS 外でも同等の構成を再現して開発できる

という点です。

1 点目については、CloudFront に関数 URL を紐つけることで、キャッシュやリバースプロキシの恩恵が受けられるようになります。この点と Lambda のコストパフォーマンスなどからマイクロサービス構成と相性がよいと考えています。

2 点目、Lambda は VPC 内に配置することが出来ますが、その場合にも関数 URL は利用可能です。ただし、関数 URL はたとえプライベートサブネット内であってもパブリックにアクセス可能なので、セキュリティホールとならないよう注意が必要です。

3 点目は、API Gateway や Lambda 環境依存のコードが存在しないことで、AWS 外でも動作する構成であるということです。別のクラウドへ移行するというケースはあまりないでしょうが、ローカル環境でも同じように動作することは、開発体験が向上し・テストしやすいという点で良いことです (Amazon S3・Amazon DynamoDB は minio や DynamoDB local で代替可能)。

以上から、コンテナランタイムとしての Lambda も十分に実践的な構成に耐え、そのうえで Lambda の恩恵 - コストパフォーマンス・スケーラビリティ・・・を享受出来ると考えます。Amazon ECS に代わる選択肢として検討する価値があるでしょう。

筆者が所属している MIERUNE でも複数の開発でこの構成を活用しています。それまでは主に ECS を利用していましたが、コスト・デプロイ容易性の点で開発効率・体験が大きく向上しました。

ネットワーク周りの VPC と Lambda の相性について

VPC に配置した Lambda はそのままでは外部 (インターネット) 方向への通信が出来ません。一般には、NAT ゲートウェイを設置する必要がありますが、小さくないコストが発生しますし構成が複雑化します。これに対する回避策を 2 つ示します。

第一に、VPC Lambda の Elastic Network Interface (ENI) に静的 IP アドレスを割り当てるという方法があります。詳しくは筆者の別記事 Lambda を VPC に配置する・インターネット通信を可能にする・RDS と接続する - Qiita をご覧ください。

第二に、2023 年 10 月に追加された、IPv6 に限り VPC Lambda のアウトバウンド通信を可能とする機能を利用する方法です (参考 : AWS Lambda が VPC でのアウトバウンド接続において Internet Protocol Version 6 (IPv6) のサポートを発表。この機能を用いると、IPv6 に対応している通信先なら NAT ゲートウェイを必要とせずに済みます。

通信先が全て IPv6 に対応しているなら、後者の方法が簡単です。そうでない場合は前者が利用出来ます。


まとめ

Web Adapter と関数 URL により Lambda が非常に利用しやすいコンテナランタイムとなり、実践的な構成でも制限が少ないことを示しました。いずれの機能もここ 1, 2 年にリリースされたものであり、今後も進化は続いていくでしょう。この観点で、今後解決されたらうれしい課題には:

  1. VPC Lambda の ENI に静的 IP アドレスを割り当てる手順の簡略化
  2. 関数 URL へのアクセスを CloudFront 経由に限定

というものが挙げられます。前者は先に述べたとおりです (IPv6 ではすでに解決していると言えますが)。後者は現状の機能でも実現出来ますが、あまりシンプルではなく回避策に見えます (参考 : Protecting an AWS Lambda function URL with Amazon CloudFront and Lambda@Edge)。

今後も Lambda の進化から目が離せませんね !


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます


筆者プロフィール

井口 奏大
MIERUNE Inc. 執行役員 CTO

位置情報技術に関する OSS コミュニティ「FOSS4G (フォスフォージー)」へ傾倒しているエンジニア。オープンソース開発の傍ら、技術系イベントにも多く出没。位置情報技術と AWS の組み合わせを日々研究中。「位置情報エンジニア養成講座 (秀和システム)」の著者。MapLibre User Group Japan の運営メンバー。

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する