Lambda関数の作り方を学んだ後はさらにLambda関数でDockerを利用してみませんか?本文書ははじめてLambda関数でDockerを利用してみたいという人向けの内容になっています。

Python、Java、Node.js、Rubyなどを利用してLambda関数を作成することができますが本文書ではPythonを利用しています。

AWSでLambda関数を作成した経験がない人は下記の公開済みの文書を参考に作成してみてください。

事前準備

macOSですでにDockerがインストールされている状態で開始します。もしDockerがインストールされていない場合は先にインストールを行ってください。インストールが完了している場合にはdockerコマンドを利用してバージョンを確認することができます。


% docker -v
Docker version 25.0.2, build 29cf629
 % which docker
/Users/mac/.docker/bin/docker

動作確認を行うために任意の名前のディレクトリを作成します。


 % mkdir aws_docker

動作確認

利用するDockerイメージ

AWS LambdaでPythonを実行するための公式のDockerイメージがあるためそのイメージを利用する必要があります。

今回利用するDockerイメージはpublic.ecr.aws/lambda/pytho:3.12です。ドキュメントのUsageを確認するとDockerイメージ/コンテナのローカルでの作成方法も記述されているのでその内容を参考に動作確認を行います。

AWSが提供するDockerイメージの利用方法
AWSが提供するDockerイメージの利用方法

こちらの記事も参考になります。

app.pyファイルの作成

aws_dockerディレクトリの下にDocker上で実行するapp.pyファイルを作成します。作成したapp.pyファイルに以下のコードを記述します。


import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

Dockerfileの作成

aws_dockerディレクトリの下にDockerfileを作成します。


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

COPY app.py ${LAMBDA_TASK_ROOT}

CMD ["app.lambda_handler"]

FROMには利用するPythonのイメージ名を指定します。public.ecr.aws/lambda/python:3.12がAWSが提供するDockerイメージです。COPYでは作成したapp.pyファイルをイメージのファイルシステム上のパス(LAMDA_TASK_ROOT)にコピーしています。CMDはコンテナが起動する際に実行したい処理を指定します。Lambda関数を実行するとapp.pyファイルのlambda_handlerが実行されます。

イメージのビルド

dockerのコマンドを利用してDockerfileを元にイメージを作成します。


% docker build -t hello_from_lambda .
[+] Building 24.1s (7/7) FINISHED                                                  docker:desktop-linux
 => [internal] load build definition from Dockerfile                                               
//略
What's Next?
  View a summary of image vulnerabilities and recommendations → docker scout quickview

作成したイメージはdocker image lsコマンドで確認することができます。


 % docker image ls
REPOSITORY          TAG       IMAGE ID       CREATED              SIZE
hello_from_lambda   latest    fd6b985dabd3   About a minute ago   558MB

コンテナの作成、起動

作成したイメージを利用してローカルでLambda関数の動作確認を行うためにコンテナの作成、起動を行います。-pオプションでポートの指定を行っています。public.ecr.aws/lambda/python:3.12のイメージの中にLambda Runtime Interface Emulator(RIE)が含まれているためローカルでLambda関数の動作確認を行うことができます。RIE が8080ポートでリスニングをするためポートマッピングで 9000 ポートにマッピングしています。


% docker run -p 9000:8080 hello_from_lambda
14 Feb 2024 02:08:43,514 [INFO] (rapid) exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)

実行するとhttp://localhost:9000/2015-03-31/functions/function/invocationsのエンドポイントが作成されます。ローカル環境の動作確認ではそのエンドポイントに対してcurlを利用してリクエストを送信します。

コンテナな実行後は、docker psコマンドで起動しているコンテナの情報を確認することができます。


% docker ps
CONTAINER ID   IMAGE               COMMAND                   CREATED          STATUS          PORTS                    NAMES
2cc186f6120a   hello_from_lambda   "/lambda-entrypoint.…"   16 minutes ago   Up 1 minutes   0.0.0.0:9000->8080/tcp   elegant_ritchie

コンテナの名前は指定をしていないので自動で命名されます。上記ではelegant_ritchieとなっており各自の環境によって名前が異なります。

起動しているコンテナへのログインは下記のコマンドで行うことができます。


 %  docker exec -it elegant_ritchie /bin/bash

ログイン後にlsコマンドを実行するとapp.pyファイルを確認することができます。pwdコマンドでは/var/taskにapp.pyファイルが作成されていることができます。


bash-5.2# ls
app.py
bash-5.2# pwd
/var/task

ログインした結果からDockerfileで利用した環境変数のLAMBDA_TASK_ROOTは/var/taskであることもわかりました。

Lamdba関数の実行

curlを実行してローカル環境でLambda関数を実行するために以下のコマンドを実行します。app.pyで記述した通りstatusCodeとbodyが戻されれば正常に動作しています。


 % curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d {}
{"statusCode": 200, "body": "\"Hello from Lambda!\""}%

動作確認が完了したらコンテナを停止します。ここではコンテナ名はelegant_ritchieですがコンテナ名は各自の環境によって異なります。


 % docker stop elegant_ritchie
elegant_ritchie

ECRのリポジトリの作成

Lambda関数はAWS ECR(Elastic Container Registry)に保存したDockerイメージを利用します。そのため作成したDockerイメージを保存するリポジトリの作成を行います。ここではリポジトリを作成して作成したイメージをアップロードします。

ECRにリポジトリを作成する前にECRにログインを行います。123456789012の部分を各自のAWSのアカウントIDに変更します。


  % aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

An error occurred (AccessDeniedException) when calling the GetAuthorizationToken operation: User: arn:aws:iam::123456789012:user/johndoe is not authorized to perform: ecr:GetAuthorizationToken on resource: * because no identity-based policy allows the ecr:GetAuthorizationToken action
Error: Cannot perform an interactive login from a non TTY device

IAMユーザに権限(ecr:GetAuthorizationToken)がない場合には上記のようにエラーメッセージが表示されます。

権限があり正しいコマンドで実行した場合には”Login Succeded”のメッセージが表示されます。


  % aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
Login Succeeded

権限がない場合はECRを利用できるポリシー”AmazonEC2ContainerRegistryFullAccess”をユーザにアタッチします。

aws ecr get-login-password –region ap-northeast-1のみ実行するとTokenが戻され、–password-stdinに取得したTokenが渡されログイン処理が行われます。

ログイン完了後はcreate-repositoryコマンドを利用してhello_lambda_repoという名前のリポジトリを作成しています。リポジトリ名には任意の名前をつけることができます。ECRはプライベートとパブリック用のリポジトリを作成することができますが下記のコマンドではプライベート用のリポジトリを作成しています。


% aws ecr create-repository --repository-name hello_lambda_repo --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:123456789012:repository/hello_from_lambda",
        "registryId": "123456789012",
        "repositoryName": "hello_lambda_repo",
        "repositoryUri": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/hello_from_lambda",
        "createdAt": "2024-02-14T13:13:18.831000+09:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": true
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}
AWS無料利用枠の一部としてプライベートリポジトリ用に1年間月々500MBのストレージを利用することができます。動作確認では180.70MBを利用します。

作成後はdescribe-repositoriesで作成したリポジトリの情報を確認することができます。


% aws ecr describe-repositories
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:123456789012:repository/hello_from_lambda",
        "registryId": "123456789012",
        "repositoryName": "hello_lambda_repo",
        "repositoryUri": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/hello_from_lambda",
        "createdAt": "2024-02-14T13:13:18.831000+09:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": true
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

リポジトリを作成後は作成済みのイメージにタグをつけるためdocker tagコマンドを実行します。イメージをECRにアップロードするためにはタグ付けは必須です。123456789012の箇所は各自のAWSのアカウントIDを指定してください。


 % docker tag hello_from_lambda:latest 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/hello_lambda_repo:latest
//書式
 % docker tag イメージ名: 作成したECRのリポジトリ名:

docker tagを実行後にdocker imagesコマンドを実行すると名前の異なる2つのイメージが同じIDで作成されていることがわかります。


% docker images
REPOSITORY                                                            TAG       IMAGE ID       CREATED       SIZE
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/hello_lambda_repo   latest    0706fcaa0e46   1 hours ago   558MB
hello_from_lambda                                                     latest    0706fcaa0e46   1 hours ago   558MB

タグ付けしたイメージのアップロードにはdocker pushコマンドを利用します。タグづけ後に作成されているイメージの名前を指定してください。


 % docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/hello_lambda_repo:latest
The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/hello_lambda_repo]
da20c8544dac: Pushed 
b2fbcdbc3abe: Pushed 
01237e4b624b: Pushed 
7393ae547845: Pushed 
08352d8f528a: Pushed 
4ad08681a382: Pushed 
8a302ef602af: Pushed 
latest: digest: sha256:0f82092ea1df081186fd83788f50fc8629a223ebd13d1b8699a4b33a5cb14f size: 1785

アップしたイメージの情報をManagement ConsoleのECRのサービスから確認することができます。

リポジトリにアップしたイメージの確認
リポジトリにアップしたイメージの確認

Lambda関数の作成

ECRにイメージがアップロードできたらいよいよDockerのイメージを利用してLambda関数の作成を行います。

Management ConsoleからLambda関数を作成します。

関数の作成画面のオプションではコンテナイメージを選択してください。コンテナイメージを選択するとイメージを参照ボタンから作成したリポジトリのイメージが選択できるようになるので選択してください。名前はhelloLambdaとしています。

動作確認でLambda関数から別のサービスを利用するわけではないので設定するロールがない場合はロールには基本的なLambdaアクセス権限で新しいロールを作成を選択してください。自動で命名されたロールが追加されて設定されます。

lambda関数設定画面
lambda関数設定画面

関数の作成ボタンをクリックするとhelloLambdaという名前のLambda関数が作成されます。Management Consoleからでもテストは実施できますが、作成したLambda関数をAWS CLIコマンドを利用して実行します。


 % aws lambda invoke --function-name helloLambda response.json 
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

response.jsonファイルには関数の戻り値が保存されているので中身を確認します。


{"statusCode": 200, "body": "\"Hello from Lambda!\""}

Dockerを利用して作成したLambda関数を実行することができました。簡単なPythonファイルの実行でしたが作成方法は理解できたと思うので次はDockerで実行させる内容を高度なものにしてチャレンジしてみてください。