ASP.NET Core MVCアプリケーションをLambda Web Adapterを使ってLambda上で動かす
blogger方面から引っ越してきました。Zenn上では初記事です。
社内の勉強会用に小粒なネタができたので記事にまとめました。
きっかけ
Lambdaがコンテナイメージをサポートしたことは風の便りには聞いていたのですが、これまで実際に使う機会がありませんでした。10GBのイメージサイズまでサポートしているとのことですが、「Serverlessなんてサイズの小さなプログラムを動かすためのもの。250MBもあれば十分だぜ。」などと思っておりました。ところが、ちょっとしたWebフレームワークにパッケージを追加すると250MBの制限を超えそうになり、サイズを減らすために四苦八苦するケースが出てきました。他に抱えていた課題としては、ローカルの開発環境上でLambdaをデバッグするのはちょっとダルいんですよね。Lambdaに慣れていないチームで開発するときはなおさらです。
そんな中見つけたのが今回のネタであるLambda Web Adapterです。個人開発のアプリケーションでは利用し始めたところで、NestJSで実装したAPIサーバーをLambda上で動かしています。で、今回は伝統的なWebアプリケーションであるASP.NET Core MVCをLambda上で動かすのに挑戦してみました。(挑戦と言っても10分くらいで動いてしまったので、とてもお手軽です。)
やってみた
まずは最短距離でアプリケーションをLambda上で動かすまでの手順を説明します。
前提条件
以下を用意します。ちなみに、私の開発環境はMacですが、Windowsな方はWSLを使えば同じようなことができると思います。
ソースコードのクローン
今回Lambda上で動かすアプリケーションはASP.NET Core MVCの公式ドキュメントで紹介されているサンプル「MvcMovie」です。アプリケーション自体は変更しておらず、これにDockerfileを追加してGitHub上に公開しておいたので、これを使って手順を進めます。まずは、リポジトリをcloneします。
git clone https://github.com/awwa/dotnet-mvc-lambda.git
cd dotnet-mvc-lambda
ECR リポジトリの作成
環境変数ACCOUNT_ID
にご自身のAWSアカウントのIDを設定します。その後、ECR にログインし、mvcmovie
という名前でリポジトリを作成します。リージョンは東京(ap-northeast-1
)を使っていますがお好きな場所で。
export ACCOUNT_ID=xxxxxxxxxxxxx
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com
aws ecr create-repository --repository-name mvcmovie --region ap-northeast-1 --image-scanning-configuration scanOnPush=true
Docker イメージのビルド
ローカル環境環境上でDocker イメージをビルドします。今回の記事のポイントであるDockerfileの中身は後で解説します。
docker build -f ./Dockerfile -t mvcmovie:latest .
ローカル環境での動作確認
Docker イメージをローカルで実行して動作確認します。
以下のコマンド実行後、ブラウザで http://localhost:8080
にアクセスします。
それっぽい画面(Welcome)が表示されれば成功です。
プロセスを停止するには Ctrl + C
を押します。
docker run -p 8080:8080 mvcmovie:latest
ECR へプッシュ
ローカル環境でビルドした Docker イメージを ECR にプッシュします。
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com
docker tag mvcmovie:latest $ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/mvcmovie:latest
docker push $ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/mvcmovie:latest
Lambda 関数用の IAM ロールの作成
Lambda 関数用の IAM ロールを作成します。この IAM ロールには、Lambda 関数が他の AWS サービスを呼び出すための権限が付与されます。IAMロールの内容はAWS公式ドキュメントを参考にしました。
aws iam create-role --role-name lambda-ex --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'
Lambda 関数の作成
AWS Lambda に関数を作成します。関数名=mvcmovie、タイプ=イメージ、イメージ=先ほど作成したECR上のイメージ、IAMロール=先ほど作成したロールを指定しています。
aws lambda create-function \
--function-name mvcmovie \
--package-type Image \
--code ImageUri=$ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/mvcmovie:latest \
--role arn:aws:iam::$ACCOUNT_ID:role/lambda-ex
Lambda 関数 URL の追加
Lambda 関数 URL を使用して動作確認するため関数 URL を作成します。
今回は認証なしでアクセスできるように設定します。プロダクション環境であればAPI Gatewayなどを経由するんでしょうね。
aws lambda add-permission \
--function-name mvcmovie \
--action lambda:InvokeFunctionUrl \
--principal "*" \
--function-url-auth-type "NONE" \
--statement-id url
aws lambda create-function-url-config \
--function-name mvcmovie \
--auth-type NONE
作成に成功したら、以下のようなレスポンスが返るはずです。ブラウザを開いてFunctionURL
の URL にアクセスしてください。それっぽい画面(Welcome)が表示されたら成功です。
{
"FunctionUrl": "https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/",
"FunctionArn": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxx:function:mvcmovie",
"AuthType": "NONE",
"CreationTime": "2024-03-31T13:11:24.319546Z"
}
解説
Dockerfile
今回作成したDockerfileは.NETの公式ドキュメントで公開されていたものに、以下の変更を加えたものです。
-
Lambda Web Adapterの記事で紹介されていた
aws-lambda-webadapter
をCOPY
する行を加える。 -
EXPOSE 8080
を足す。 -
ENTRYPOINT
の引数を今回のアプリケーションに合わせて修正する。
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build-env /App/out .
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.1 /lambda-adapter /opt/extensions/lambda-adapter
EXPOSE 8080
ENTRYPOINT ["dotnet", "MvcMovie.dll"]
所感
- NestJSで実装したAPIサーバーが動くのは見ていたので、特段驚くようなことはないと思っていたけど、伝統的な.NETのMVCアプリケーションが(全然ハマることなく)Lambda上で動くのを見てやっぱりビビった。
- 開発する側がLambdaのことを全く気にしなくて良いのは素晴らしい。
- とりあえず、クリティカルじゃないアプリケーションなら全然問題なさそう。ちゃんとしたアプリケーションであればもう少し色々なケースで検証してみたい。
- .NETってDockerfileを書かなくてもコンテナイメージをビルドできるんですね(知らんかった)。Dockerのエコシステムを壊しそう&過去のDockerfileの資産が活きなさそう。
- aws-lambda-adapterの更新頻度が意外と高い。
- 何気にaws-lambda-adapterのリポジトリを見たら結構いろいろなサンプルコードが整備されていた。aspnet-mvcもあった(最初からここを見ればよかった)。
-
0.8.0のリリースノートに
Support all non-HTTP event triggers, such as SQS, SNS, S3, DynamoDB, Kinesis, Kafka, EventBridge, and Bedrock Agents.
の記載があった。S3とかEventBridgeからWebアプリを直接起動できるってこと?気になる。
Discussion