はじめに
本記事は、Lambda Web Adapterの(自分の)理解促進を目的としています。
記載している内容はgithubのreadmeをベースとしています。
Lambda Web Adapter (LWA)とは
Lambda Web Adapter(LWA)とは、一般的な HTTP ベースの Web アプリケーションをそのまま AWS Lambda へデプロイする際に直面する問題を解決するためのツールです。
通常、HTTP を扱う Web アプリケーションを Lambda に移行しようとすると、Lambda のハンドラーが期待するインターフェースと、一般的な Web フレームワークで使用されるインターフェースに違いがあるため、上手く動作しないことがあります。LWA は、このインターフェースの違いを意識することなく、アプリケーションを構築できるようにするための仕組みを提供します。
これにより、開発者は Lambda 上で Web アプリケーションを簡単に実行でき、従来の Web フレームワークと Lambda の間での調整に煩わされることなく、効率的に開発が進められるようになります。
LWAにできること
以下、GitHub の README より抜粋
- Run web applications on AWS Lambda
- Supports Amazon API Gateway Rest API and Http API endpoints, Lambda Function URLs, and Application Load Balancer
- Supports Lambda managed runtimes, custom runtimes and docker OCI images
- Supports any web frameworks and languages, no new code dependency to include
- Automatic encode binary response
- Enables graceful shutdown
- Supports response payload compression
- Supports response streaming
- Supports non-http event triggers
最も大きいメリットは、「ウェブアプリケーションがLambdaを意識する必要がない」点です。
WebアプリケーションとLambdaでのインターフェースの違いは全てLWAが吸収してくれるため、ローカルで作成したwebアプリケーションをLambda用に加工する必要がないため、スムーズに開発を進めることが可能です。
API GatewayやHTTP API endpoints, Lambda Function URLsとの統合をサポートしています。
ただ、LWA は単に Web アプリケーションを Lambda 上で実行するだけではなく、バイナリレスポンスの自動変換や、レスポンスの圧縮、ストリーミング対応など、より高度な機能も提供します。
また、HTTPイベント以外のトリガーにも対応しているので、S3イベントやSQSとのコラボレーションも実現が可能です。
ストリーミングレスポンスは関数URLでのみ利用可能です。
API Gateway経由では利用できないことに注意が必要です。
リクエストからレスポンスまでのフロー
※ 点線はレスポンス
実装方法(AWS Lambda Web Adapter)
LWA はDockerイメージとZipパッケージの両方に対応しています。
Docker イメージでの実装
Docker イメージで LWA を使う場合は、LWA の実行ファイルを /opt/extensions/
配下に置くだけで、Lambda の外部拡張(External Extension)として自動起動されます。
手順
- アプリのベースイメージ(例:
public.ecr.aws/lambda/nodejs:18
など)でコンテナを構築 - 次の 1 行を Dockerfile に追加して、LWA バイナリを拡張として配置
# Lambda Web Adapter を拡張として追加
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.3 /lambda-adapter /opt/extensions/lambda-adapter
仕組み(なぜこれで動く?)
- Lambda は起動時に
/opt/extensions/
配下の実行ファイルを検出して拡張として起動します - LWA は Lambda Runtime API とコンテナ内の Web アプリの間に立ち、イベント⇔HTTP を相互変換してプロキシします
- 既定ではアプリは
127.0.0.1:8080
をリッスン(AWS_LWA_PORT
で変更可能)
よく使う環境変数(任意)
AWS_LWA_PORT=8080
AWS_LWA_READINESS_CHECK_PATH=/healthz
/opt/extensions/
に置くだけで起動連携できるため、ENTRYPOINT の上書きは不要です(通常はそのままでOK)。
Zip パッケージでの実装
Zip パッケージ(AWS マネージドランタイム)でも LWA は利用できます。必要なのは次の 3 点です。
手順(最小)
- LWA の Lambda レイヤーを関数にアタッチ
arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerX86:25
- 環境変数
AWS_LAMBDA_EXEC_WRAPPER=/opt/bootstrap
を設定 - ハンドラー を Web アプリの起動スクリプト(例:
run.sh
)に設定
run.sh(例:Node.js)
#!/bin/sh
export AWS_LWA_PORT="${AWS_LWA_PORT:-8080}"
export AWS_LWA_READINESS_CHECK_PATH="${AWS_LWA_READINESS_CHECK_PATH:-/healthz}"
# ここであなたのWebアプリ(HTTPサーバ)を起動
node server.js &
# すぐに復帰(LWA が以後プロキシ)
echo "started"
server.js(最小サンプル)
const http = require('http');
const port = process.env.AWS_LWA_PORT || 8080;
const ready = process.env.AWS_LWA_READINESS_CHECK_PATH || '/healthz';
http.createServer((req, res) => {
if (req.url === ready) { res.writeHead(200); return res.end('ok'); }
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('hello from LWA + Node');
}).listen(port, '127.0.0.1', () => {
console.log('listening on', port);
});
Zip の場合は レイヤー+AWS_LAMBDA_EXEC_WRAPPER
+起動スクリプトの 3 点セット。
LWA がランタイム起動をラップし、HTTP サーバにプロキシします。
参考資料