LWA(Lambda Web Adapter)を使うためには
LWA(Lambda Web Adapter)
LWAのモチベーション
自作したサーバーをコンテナ化してlambdaにデプロイするためにはコードベースにおいて、最上位の処理をlambda handler化しないといけないという認識があり、若干不都合に感じていました。
ローカルで当該サーバーを実行するときと、クラウド環境で当該サーバーを実行するときに処理の中身を分岐させないといけず、また、コードベースがlambdaにロックインされてしまい柔軟性に欠けるというところに違和感を覚えていました。
例:
package main
import (
...
)
func main() {
appEnv := os.Getenv("APP_ENV")
// 分岐が発生
if appEnv == "local" {
startHTTPServer()
} else {
startLambda()
}
}
func handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
...
return resp, err
}
func startHTTPServer() {
...
logger.Info("Server running on %s, health check at /api/health", port)
...
}
func startLambda() {
lambda.Start(handler)
}
LWAの導入
このlambda用の方便を用意しなくても普通にサーバーを定義してエントリポイントに処理を書いてもlambdaにいい感じにデプロイできるようになるのがLWAです。
これを使うことで上記の処理でいうところのstartHTTPServerさえmain関数で実行していればlambdaでもいい感じにhttpサーバーがたてられます。
func main() {
startHTTPServer()
}
func startHTTPServer() {
...
logger.Info("Server running on %s, health check at /api/health", port)
...
}
使い方は簡単で、Dokcerfileに以下の一行を追加するだけです(と公式が書いています)
COPY /lambda-adapter /opt/extensions/lambda-adapter
落とし穴
しかし、このままLWAを利用することにしてCI/CD上でデプロイを試みようとするとrate limitの問題に引っかかってしまいます。
実際にgithub actions上でdocker buildしようとして吐き出されたエラー
Error: buildx failed with: ERROR: failed to solve: public.ecr.aws/awsguru/aws-lambda-adapter:0.9.0: failed to resolve source metadata for public.ecr.aws/awsguru/aws-lambda-adapter:0.9.0: failed to copy: httpReadSeeker: failed open: unexpected status code https://public.ecr.aws/v2/awsguru/aws-lambda-adapter/manifests/sha256:1c31bf4102ca63ef2082534d7139c0bc5fbd36ea6648e4756e9b475ef3ed829c: 429 Too Many Requests - Server message: toomanyrequests: Data limit exceeded
publicなECRからのpullって制限なくできないと意味ないやんと思いましたが、よく考えればwebサーバー同様ddos攻撃とかを考慮すれば一般的な対応なのかもなと勝手に納得しました。
解決策
そこでAWSの人にissueを通じて相談した(その時点ではpublicなECRのrate limitってバグじゃね?みたいな浅い思考だったので気軽にissueをあげてしまいましたmm)ところ、下記のようにアドバイスをいただくことができました。
For image pull, the maximum number of unauthenticated image pulls per second is 1 per region. You can get 10 tims image pull per second if you authenticate to Amazon ECR. Details are on this page.
So if you pull from public ECR repo anonymously, you can transfer 500 GB of data per month with 1 image pull per second. You can get 5 TB of data transfer by login to Amazon ECR or ulimited data transfer by pulling from AWS compute resources in any AWS region.
つまりAWSアカウントにログイン状態でbase imageをpullしようとすればrate limitに引っかかる確率はグッと下がるのでデプロイの安定性を上げることができるかもよ、とのことでした。
なので例えばgithub actionsのCI/CDでビルドするときなどは、docker loginするステップの次にdocker buildするステップを定義することでLWAのbase imageをより安全にpullできるようになると思われます。
Dockerfile内でbase imageをpullするときにAWSアカウントにログインしておくってどういうこと?awsに認証されたことをどうやってDockerfileのビルドプロセスに伝えるの?と思いましたが、やはり[1]Dockerfile内でdocker loginはできなさそうです
余談
一連のissueを通じてAWSのアーキテクトの方とコミュニケーションを取る機会を得られましたが、github mcp serverによって簡単にissue作成することができました。自然言語で自分がいだいている違和感や疑問を抽象的にLLMに投げかけ具体的なネットワーク越しの操作まで一気通貫して行える。しかも言語の差異も吸収される。AIすげえ。
-
明示的にそのような記述を見つけたわけではありませんが、https://docs.docker.com/reference/dockerfile/#from を見ている感じそのようなsyntax?はなさそうなのと、issue内で次のように指南していただいたためこの結論になりました→
So the simplist solution to your problem is login to Amazon ECR before using LWA images. You can do it with the command below. aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
↩︎
Discussion