今回のお題
前回、LambdaをDockerイメージでデプロイする方法の前編として「AWS CDKの定義」について書きました。
今回はその後編として「Dockerfileの定義&ハマりどころ」について記載したいと思います。
- 前編:AWS CDKの定義(これは前回)
- 後編:Dockerfileの定義&ハマりどころ(今回はここ)
Dockerfileの定義
Dockerfileの定義ですが、これは下記AWS公式ドキュメントに沿って記載すればOKです。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/nodejs-image.html
上記ドキュメントにも記載がある通り、Amazon ECR リポジトリでもLambda用のnode.jsイメージが公開されているので、特に理由がない限りはそれを使えばOKです。
https://gallery.ecr.aws/lambda/nodejs
実際の記載例は下記の通りです。(前編で紹介したコードそのままです)
なおindex.jsが実際のLambdaのソースコードです。(TypeScriptの場合、事前にビルドしておいて下さい)
# Dockerfile # バージョンは適宜選択 FROM public.ecr.aws/lambda/nodejs:18 # /var/task/は、Lambda環境変数LAMBDA_TASK_ROOTの値 WORKDIR /var/task/ # Copy function code COPY index.js . # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) CMD [ "index.handler" ]
ポイントはDocker側で /var/task/
フォルダにLambdaのソースコードをコピーすることです。(/var/task/
はAWSでLambdaソースファイルがコピーされるフォルダで、Lambda環境変数 LAMBDA_TASK_ROOT
でも確認できます)
また最後に CMD
でエントリポイントとしてハンドラー関数を指定します。(これを忘れると実行できません)
なお上記Dockerfileにはないですが、node_moduleを使用する場合、事前にpackage.jsonのコピーや RUN npm install
を忘れないでください。(前回説明した通り、Dockerでデプロイした場合はLambda Layerが使用できないので)
それとDockerfileは上位のファイルは参照できないので、ご注意を。(パスに ../
などは設定できない)
あとは該当のECRにDockerイメージをpushすればOKです。特に問題なければ、Lambdaが実行できるはずです。(Lambda関数URLなりAPI Gateway経由なり)
ハマりどころ:複数のLambda関数をデプロイする場合はどうするの?
次はLambdaをDockerイメージでデプロイする際のハマりどころですが、「複数のLambda関数をデプロイする場合はどうするの」という点です。
Dockerfileの COPY
コマンドで複数のLambdaファイルをコピーできますが、CMD
コマンドでエントリポイントに指定できるLambda関数は1つだけです。
なので下記のようなコードでは正しく動作しません。
かといって、各Lambda関数ごとにDockerイメージを作成するのは非常に手間です。
# 注意:このコードは正しく動きません FROM public.ecr.aws/lambda/nodejs:18 WORKDIR /var/task/ # Copy function code COPY index.js . COPY index2.js . COPY index3.js . # このコードを実行しても、エントリポイントとして動くのはindex3.handlerだけです。(上書き更新) CMD [ "index.handler", "index2.handler", "index3.handler" ]
ではどうやるかというと、下記の方法で実行できます
- Lambda関数単位でフォルダを分ける
- エントリポイントをAWS CDK側で定義する
Lambda関数単位でフォルダを分ける
これは名前の通り、Docker側のフォルダをLambda関数単位で分けます。
先ほどの正しく動かないDockerfileを例にすると、下記のように記載すればOKです。
FROM public.ecr.aws/lambda/nodejs:18 WORKDIR /var/task/ # Lambda関数単位でフォルダを分ける COPY index.js ./func1/index.js COPY index2.js ./func2/index2.js COPY index3.js ./func3/index3.js # Dockerfile内でエントリポイントを定義しないので、CMDは削除
エントリポイントをCDK側で定義する
エントリポイントはDockerfileではなくAWS CDK側で定義するので、上記の通り CMD
は削除します。
その代わり、AWS CDK の DockerImageFunction
側でエントリポイントを定義します。(下記コードを参照)
// fromEcr() を使用してますが、fromImageAsset()でも同じです。 // ecrRepoは事前に作成したECRのインスタンス const func1 = new lambda.DockerImageFunction(this, 'Function1', { code: lambda.DockerImageCode.fromEcr(ecrRepo, { // fromEcrのpropsにcmdがあるので、そこでエントリポイントを定義する // 指定するパスは「/var/task/」以下を記載する cmd: ['./func1/index.handler'], }), functionName: 'Function1', }); const func2 = new lambda.DockerImageFunction(this, 'Function2', { code: lambda.DockerImageCode.fromEcr(ecrRepo, { cmd: ['./func2/index2.handler'], }), functionName: 'Function2', }); const func3 = new lambda.DockerImageFunction(this, 'Function3', { code: lambda.DockerImageCode.fromEcr(ecrRepo, { cmd: ['./func3/index3.handler'], }), functionName: 'Function3', });
あとはECRにDockerイメージをpushすれば、どのLambda関数も正しく動作するはずです。
告知
明日(9/12(火)) に、名古屋で開催の「JAWS-UG 名古屋 AWS認定試験を受けてみようと思った方へ送る勉強会」イベントにて、「AWS ソリューションアーキテクト アソシエイト試験体験記」についてお話しします。(オフライン)
またその翌日の9/13(水)に開催される「JAWS-UG CDK支部 #9」イベントにて、AWS CDK座談会のパネラーの一人として参加します。(オンライン)
さらに9/16(土)に愛媛県松山市で開催される「四国クラウドお遍路 2023 - 四国の外のモノサシを知ってみよう-」イベントにて、「AWS CDKでインフラ、アプリを分離した際に困ったこと」という内容でLTをさせていただきます。(オフライン)
上記イベントに参加される方、およびこれから参加しようと思っている方、ぜひよろしくお願いいたします。
それでは、少し時間が空いてしまいましたが、今回はこの辺で。