LoginSignup
0
0

コンテナイメージからLambda関数をデプロイする

Posted at

はじめに

コンテナイメージからLambda関数のデプロイにトライ。
(コンテナイメージからのデプロイ自体は2020年のアップデート)

コンテナイメージからLambdaをデプロイする

コンテナイメージからLambda関数をデプロイすることでデプロイ可能なMaxのサイズが10GBになる。当時のre:Inventの動画を見ても機械学習などパッケージが大きいケースでもLambdaを使いやすく、というのが念頭に置かれている印象。

2020年の記事

zipファイルアーカイブからLambda関数をデプロイする方法では、解凍後のzipファイルのサイズが250MBまでに制限される

コンテナイメージからデプロイすれば依存関係の管理も楽ではあるけど、単純にWebアプリをLambdaに移植しても入出力インターフェースの違いから正常に動かないことがある。(Lambdaにはコードのエントリポイントとなるhandler関数があってイベントオブジェクトとコンテキストオブジェクトを受け取っているけど。そこがLambda独自仕様の部分)

この状態だとコンテナ化しても移植性はいまひとつになってしまう……のでHTTPを話すフレームワークであればLambda Web Adapterを使うとよさげ。

Lambda Web Adapter

Lambda Extensionに追加することでNext.jsやFlaskなどHTTPを話すフレームワークのWebアプリをそのままLambdaでも動かせる、というもの。
Web AdapterにLambdaイベント->HTTPリクエスト変換、HTTPレスポンス->Lambdaレスポンス変換を担ってもらい、インターフェースの違いを意識せずに動かせるようにする。

Lambda Web AdapterはAWS公式OSSで、dockerイメージ、zipパッケージ両方に対応している。
詳細は以下のREADMEで。

実際にデプロイする

EC2にDocker入れて操作する。

EC2にDockerインストール

$ sudo yum install -y docker 
$ sudo service docker start

lambda_function.pyを作成する(Pythonの場合)

中身は好きなコードでどうぞ。

サンプルコード

requirements.txtを作成する

インストールしたいパッケージをrequirements.txtに記載する。

Dockerfileを作成

簡単なコードであれば参考リンクのサンプル通り5文で大丈夫。Lambda Web Adapterを使いたい場合だとCOPY文が一行増える。

FROM public.ecr.aws/lambda/python:3.12

COPY requirements.txt ${LAMBDA_TASK_ROOT}

RUN pip install -r requirements.txt

COPY lambda_function.py ${LAMBDA_TASK_ROOT}

CMD [ "lambda_function.lambda_handler" ]

参考

上記リンクのサンプルでは
CMD [ "lambda_function.lambda_handler" ]の部分は
CMD [ "lambda_function.handler" ]になっているけど、ここは自分のコードに合わせて修正する。
コンソールから関数作るとハンドラはlambda_function.lambda_handlerになるはず。(Pythonの場合)

関数コードのファイル名がlambda_function.pyでなければCOPY lambda_function.py ${LAMBDA_TASK_ROOT}も修正する。

dockerイメージを構築

docker build --platform linux/amd64 -t docker-image:test .

ECRに対してdocker CLIを認証する

aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <your_account_id>.dkr.ecr.us-east-1.amazonaws.com

以下のようなエラーが出たときは/var/run/docker.sockでpermission deniedになっているので属性を変更する必要がある。(参考リンクでは666)

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied

参考

ECRにリポジトリを作成する

リポジトリはLambda関数と同じリージョンを指定する。

aws ecr create-repository --repository-name <repository name> --region <region> --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE

repositoryUriが出力されるので控えておく。

{
    "repository": {
        "repositoryArn": "arn:aws:ecr:<region>:<accountID>:repository/<repository name>",
        "registryId": "xxxxxxxxxxx",
        "repositoryName": "<repository name>",
        "repositoryUri": "<accountID>.dkr.ecr.us-east-1.amazonaws.com/<repository name>",
        "createdAt": "2024-06-02T06:10:26.698000+00:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": true
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

GUIでも確認できる。
repo.png

ローカルイメージのタグ付け

ローカルイメージをECRリポジトリにタグ付け(latest)

docker tag docker-image:test <ECRrepositoryUri>:latest

ECRリポジトリにローカルイメージをpushする

docker push

docker push <accountID>.dkr.ecr.<region>.amazonaws.com/<repository name>:latest

最初に上記のコマンドを実行したらno basic auth credentialsと言われてしまって、原因は認証してるリージョン違いとかトークンの有効期限切れとか色々あるらしいけど、今回は以下のコマンドを実行して再度Docker CLIを認証したらpushできた。

aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <your_account_id>.dkr.ecr.us-east-1.amazonaws.com

イメージができている。
image.png

Lambda側でも関数の概要などは見れるけど、コードの表示はできない。
image.png

Lambda関数を作成する

GUIからでもaws lambda create-functionコマンドのどちらでも

マネコンだとロールの設定忘れにくいかもしれない。
container.png

Lambda関数を実行する

response.jsonに実行結果(returnした戻り値)が出力される

aws lambda invoke --function-name <function-name> response.json

依存関係のファイル作ってないと実行したときにエラーが出る。(今回はコードの中でboto3使ってたのにrequirements.txtが空のままビルドしていた)

"Unable to import module 'lambda_function': No module named 'boto3'", "errorType": "Runtime.ImportModuleError", "requestId": "f03937c4-719e-4bf4-85a7-dbf769282d06", "stackTrace": []}

LambdaがBedrockのAPIにリクエスト投げるのにLambdaに何の権限もついてない、とかだともちろん関数実行時エラーになるので、実行に必要な権限があればつけておく。

Lambda関数を更新する

新しいイメージをECRリポジトリにアップロードしてからupdate-function-codeを実行する。

update-function-code --function-name <function name> --image-uri <imageUri>

おわりに

Lambdaはちょっとしたコードを実行する、といった用途で使っていたけどもう少しスケールの大きいこともできそう、という印象。手持ちのLambda関数コードだとLambda Web Adapterの出る幕が無かったのでサンプルコードでWeb Adapter試したい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0