はじめて投稿します、はるかなぎと申します。最近になり本格的にAWSを触り始めたいわばにわか勢です。
注意!!
SAM CLIで大幅な仕様変更があったようで、最新版を用いた場合、本記事の内容では動作しないようです。
最新版で動かす方法は現在調査中です。
AWS Lambdaってなあに?
AWS Lambdaは、サーバレス型と呼ばれるサービスのひとつで(利用者が)サーバを用意せずに、プログラムを実行できるサービスです。Faas(Function as a Service)と呼ばれる種類のサービスと説明されることもあります。
詳しい内容は、AWS公式の紹介ページを見た方が早いと思います。
AWS Lambda(イベント発生時にコードを実行)| AWS
ところで、ローカルで動くの?
この手のものを見ると、自宅に環境が欲しくなりますね。調べたところ、AWS SAM CLIというローカルでテストを行うツールがあるようです。
お試し用環境を用意します
早速遊んでみようと、以下のお試し用環境を用意しました。
ここに、SAM CLIとDockerをインストールしておきます。その他必要なツール(Git等)も一緒にインストールしておきます。(インストール方法は割愛します)
早速ためしてみる
SAM CLIで作成したプロジェクトは以下のコマンドでローカル実行することが可能です。実行には、Dockerがインストールされている必要があります。(プロジェクトの作成については割愛します)
$ sam local invoke
Invoking app.lambda_handler (python3.7)
Image was not found.
Building image......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0.
Mounting /home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 Version: $LATEST
END RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739
REPORT RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 Init Duration: 0.18 ms Duration: 93.27 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}
sam local invokeで実行すると、上記の通り作成したLambda関数が実行されます。まぁここまでは普通の話です。SAM CLIでの実行にDockerが必要と書かれていたので、どのようなコンテナが作られるのか調べようと、意気揚々とコンテナ一覧を見てやろうとしたところ・・・
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
あれ?何もないぞ??
試しにイメージ一覧を出してみると、それらしきイメージが存在します。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
amazon/aws-sam-cli-emulation-image-python3.7 rapid-1.22.0 39513e8ac96d 3 minutes ago 908MB
amazon/aws-sam-cli-emulation-image-python3.7 latest c8f4d7381293 About an hour ago 892MB
まさかと思い、sam local invokeを叩いた直後にdocker psを連発してみたところ・・・
$ docker ps --no-trunc=true
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0ab3d3c601864b1b539dddd7ac27c0972b09ceef137ed65c1acf9053e1884cba amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 "/var/rapid/aws-lambda-rie --log-level error" 3 seconds ago Up Less than a second 127.0.0.1:7706->8080/tcp busy_wiles
お、出た出た。どうやら、SAM CLIで実行すると、Lambdaの実行環境を含んだDockerコンテナが作成され、実行後に削除するという動きをするようです。
イメージを調べてみよう
上記の手順で表示されたイメージは、Docker Hubにあるようです。
amazon/aws-sam-cli-build-image-python3.7
とりあえず作成されているイメージを消してから、dockerコマンドでpullしてみます。
$ docker pull amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0
Error response from daemon: manifest for amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 not found: manifest unknown: manifest unknown
ん?イメージが存在しない?試しにタグを指定せずにpullします。
$ docker pull amazon/aws-sam-cli-emulation-image-python3.7
Using default tag: latest
latest: Pulling from amazon/aws-sam-cli-emulation-image-python3.7
df5bcad6d15c: Pull complete
1c6619c430f8: Pull complete
6577ccaf68c7: Pull complete
649bca99560c: Pull complete
Digest: sha256:5358339925e231e94c2c4e0d917af54cadb312625a30df28cda271c5b844d9c9
Status: Downloaded newer image for amazon/aws-sam-cli-emulation-image-python3.7:latest
docker.io/amazon/aws-sam-cli-emulation-image-python3.7:latest
無事にpullできました。
先ほどイメージを表示したときにもlatestのものが表示されていたので、どうやらSAM CLIでの実行時にlatestのイメージから作成しているようです。
ということは、イメージの差分を見れば、どのようなイメージかが分かります。もう一度SAM CLIで実行し、イメージを作成、historyを比較してみましょう。
まずはlatest
$ docker history amazon/aws-sam-cli-emulation-image-python3.7:latest --no-trunc=true
IMAGE CREATED CREATED BY SIZE COMMENT
sha256:c8f4d7381293badf23098d75b891c50a6682a3146ed5c90a889f4685f0f90017 2 hours ago CMD [ "/bin/bash" ] 0B
<missing> 2 hours ago ENV LAMBDA_RUNTIME_DIR=/var/runtime 0B
<missing> 2 hours ago ENV LAMBDA_TASK_ROOT=/var/task 0B
<missing> 2 hours ago ENV LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib 0B
<missing> 2 hours ago ENV PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin 0B
<missing> 2 hours ago ENV TZ=:/etc/localtime 0B
<missing> 2 hours ago ENV LANG=en_US.UTF-8 0B
<missing> 2 hours ago WORKDIR /var/task 0B
<missing> 2 hours ago ADD file:649bca99560c52ca2195dc8410dbee9e1634faa448acfee4696f74db0651773f / 66.4MB
<missing> 2 hours ago ADD file:6577ccaf68c7a9a42e7b1a8bbfa93959abc28b47888855eba289c032685c6770 / 173MB
<missing> 2 hours ago ADD file:1c6619c430f8d56651115043ea1cd3e6d293434dc774f21cc087e86aebf6e1d4 / 424kB
<missing> 2 hours ago ADD file:32665f54d46653b07d35bfa9cdd4baf9b1144d6824516a05218124afc01246f3 / 652MB
<missing> 2 hours ago ARCHITECTURE amd64 0B 0B
次にrapid-1.22.0
]$ docker history amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 --no-trunc=true
IMAGE CREATED CREATED BY SIZE COMMENT
sha256:b42538372e40f0627b62b40313690f2561f7bba02683c066e4221ea32dd2072b 5 minutes ago /bin/sh -c chmod +x /var/rapid/aws-lambda-rie 8.16MB
sha256:cddd62fd80bd20c647cd6d8cc12ff1bfb822da1706e3e7eb9c44c705c559a55f 5 minutes ago /bin/sh -c #(nop) ADD dir:bf074fbf6e9076431dc41d00943644a0df7bd2853140615db6ae0130fd5c91f8 in /var/rapid 8.16MB
sha256:c8f4d7381293badf23098d75b891c50a6682a3146ed5c90a889f4685f0f90017 2 hours ago CMD [ "/bin/bash" ] 0B
<missing> 2 hours ago ENV LAMBDA_RUNTIME_DIR=/var/runtime 0B
<missing> 2 hours ago ENV LAMBDA_TASK_ROOT=/var/task 0B
<missing> 2 hours ago ENV LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib 0B
<missing> 2 hours ago ENV PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin 0B
<missing> 2 hours ago ENV TZ=:/etc/localtime 0B
<missing> 2 hours ago ENV LANG=en_US.UTF-8 0B
<missing> 2 hours ago WORKDIR /var/task 0B
<missing> 2 hours ago ADD file:649bca99560c52ca2195dc8410dbee9e1634faa448acfee4696f74db0651773f / 66.4MB
<missing> 2 hours ago ADD file:6577ccaf68c7a9a42e7b1a8bbfa93959abc28b47888855eba289c032685c6770 / 173MB
<missing> 2 hours ago ADD file:1c6619c430f8d56651115043ea1cd3e6d293434dc774f21cc087e86aebf6e1d4 / 424kB
<missing> 2 hours ago ADD file:32665f54d46653b07d35bfa9cdd4baf9b1144d6824516a05218124afc01246f3 / 652MB
<missing> 2 hours ago ARCHITECTURE amd64 0B
/var/rapid/配下にファイルを追加し、/var/rapid/aws-lambda-rieに実行権限を付与しているという違いが見つかりました。この/var/rapid/aws-lambda-rieの有無がこの2つのイメージの違いのようです。
aws-lambda-rieってなあに?
ではこのaws-lambda-rieって何者なのか調べたところ、AWS Lambda Runtime Interface Emulatorと呼ばれるもので、名前の通りLambda実行環境のエミュレータのようです。
ここで、先ほどのコンテナ一覧の結果を見てみましょう。COMMANDの箇所を見ると「/var/rapid/aws-lambda-rie --log-level error」とあるので、まさにこいつをコンテナ作成時に実行しています。
コンテナの中身はなんだろな
では、次にコンテナを調べていきます。
先ほどの情報だけだと足りないので、docker inspectコマンドで中身を見てみます。
しかし、実行時にコンテナが作成され、実行後に削除される関係上、まともにコマンドを叩いていては間に合わないので、簡単なスクリプトを作って取得します。なお、目的のコンテナの情報さえ取れれば良いということで複数コンテナが動いている状況はまったく考慮していませんのでご注意ください。
# !/bin/bash
CONTAINER_ID=`docker ps -q`
echo ${CONTAINER_ID}
docker inspect ${CONTAINER_ID}
コンテナが起動している間にこのスクリプトを実行すると以下のような情報が得られます。
[
{
"Id": "85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829",
"Created": "2021-04-26T13:20:45.676396302Z",
"Path": "/var/rapid/aws-lambda-rie",
"Args": [
"--log-level",
"error"
],
"State": {
"Status": "removing",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": true,
"Pid": 0,
"ExitCode": 137,
"Error": "",
"StartedAt": "2021-04-26T13:20:47.643574462Z",
"FinishedAt": "2021-04-26T13:20:49.361733871Z"
},
"Image": "sha256:b42538372e40f0627b62b40313690f2561f7bba02683c066e4221ea32dd2072b",
"ResolvConfPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/hostname",
"HostsPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/hosts",
"LogPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829-json.log",
"Name": "/elated_archimedes",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction:/var/task:ro,delegated"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"8080/tcp": [
{
"HostIp": "127.0.0.1",
"HostPort": "5018"
}
]
},
"RestartPolicy": {
"Name": "",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"Dns": null,
"DnsOptions": null,
"DnsSearch": null,
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "shareable",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 134217728,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": null,
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 268435456,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": [
{
"Name": "nofile",
"Hard": 4096,
"Soft": 1024
}
],
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8-init/diff:/var/lib/docker/overlay2/3f3546128854b10663811112acc8423f84abcc1f47b3073172b55bdb3768a7af/diff:/var/lib/docker/overlay2/bcfc11b7e7c587d3a01e09c4c843a3525635ec782635bdc3e707cb56d0d5733b/diff:/var/lib/docker/overlay2/a10c8af58d6fa1f634045400e21b7f6dbbca281ba68a0ab9b5cf23ecaae7c9a7/diff:/var/lib/docker/overlay2/2cdd94e4f72dc4af42a1d5f1d25d8716ed0d7330261c5489ce847882c872d577/diff:/var/lib/docker/overlay2/a6630cafd3c07e2e8a198af012f75d3f035fc4e8ad2a69d5a2edc9d0da7c529c/diff:/var/lib/docker/overlay2/6f9c1a2e3d92bfb822c9f028fe7d98f964cd19a89b063f4082639dba4d1563ce/diff",
"MergedDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/merged",
"UpperDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/diff",
"WorkDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "bind",
"Source": "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction",
"Destination": "/var/task",
"Mode": "ro,delegated",
"RW": false,
"Propagation": "rprivate"
}
],
"Config": {
"Hostname": "85faef4d31c7",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"8080/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"AWS_SAM_LOCAL=true",
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128",
"AWS_LAMBDA_FUNCTION_TIMEOUT=3",
"AWS_LAMBDA_FUNCTION_HANDLER=app.lambda_handler",
"AWS_LAMBDA_FUNCTION_NAME=HelloWorldFunction",
"AWS_LAMBDA_FUNCTION_VERSION=$LATEST",
"AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/HelloWorldFunction",
"AWS_LAMBDA_LOG_STREAM_NAME=$LATEST",
"AWS_REGION=us-east-1",
"AWS_DEFAULT_REGION=us-east-1",
"AWS_ACCESS_KEY_ID=defaultkey",
"AWS_SECRET_ACCESS_KEY=defaultsecret",
"AWS_ACCOUNT_ID=123456789012",
"LANG=en_US.UTF-8",
"TZ=:/etc/localtime",
"PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin",
"LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib",
"LAMBDA_TASK_ROOT=/var/task",
"LAMBDA_RUNTIME_DIR=/var/runtime"
],
"Cmd": [],
"Image": "amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0",
"Volumes": {
"/var/task": {}
},
"WorkingDir": "/var/task",
"Entrypoint": [
"/var/rapid/aws-lambda-rie",
"--log-level",
"error"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "1123e52e745924dc1fce7584d2985878104283b8ea348c9cae5c6466c4dfc591",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/1123e52e7459",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "bb6cb306d6052a81de21c664211c4eafa397dca82b8b690a60d8c7e870413a69",
"EndpointID": "",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
}
}
]
長ったらしいJSONですが、すべてを見る必要はありません。必要なところだけ見ていきます。
コマンド
「/var/rapid/aws-lambda-rie --log-level error」であることがここでも確認できます。
"Path": "/var/rapid/aws-lambda-rie",
"Args": [
"--log-level",
"error"
]
ポートバインディング
ホストの127.0.0.1:5018にバインドしているようです。ポートはランダムになるみたいなので、実際に動かすときは任意のポートにできると思います。IPが127.0.0.1なので、この設定では外部からアクセスできません。
"PortBindings": {
"8080/tcp": [
{
"HostIp": "127.0.0.1",
"HostPort": "5018"
}
]
}
メモリ容量
後述の環境変数でも指定されていますが、128MBが割り当てられているようです。
"Memory": 134217728
環境変数
色々設定されていますが、先ほど確認したコンテナのhistoryの情報からLANGから下はイメージ側で設定されていることがすでに判明していますので、コンテナを作成する際は「AWS」から始まるものを設定すればよさそうです。
"Env": [
"AWS_SAM_LOCAL=true",
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128",
"AWS_LAMBDA_FUNCTION_TIMEOUT=3",
"AWS_LAMBDA_FUNCTION_HANDLER=app.lambda_handler",
"AWS_LAMBDA_FUNCTION_NAME=HelloWorldFunction",
"AWS_LAMBDA_FUNCTION_VERSION=$LATEST",
"AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/HelloWorldFunction",
"AWS_LAMBDA_LOG_STREAM_NAME=$LATEST",
"AWS_REGION=us-east-1",
"AWS_DEFAULT_REGION=us-east-1",
"AWS_ACCESS_KEY_ID=defaultkey",
"AWS_SECRET_ACCESS_KEY=defaultsecret",
"AWS_ACCOUNT_ID=123456789012",
"LANG=en_US.UTF-8",
"TZ=:/etc/localtime",
"PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin",
"LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib",
"LAMBDA_TASK_ROOT=/var/task",
"LAMBDA_RUNTIME_DIR=/var/runtime"
]
環境変数 | 値(例) | 説明 |
---|---|---|
AWS_SAM_LOCAL | true | SAM LOCALで実行しているかを示す模様 |
AWS_LAMBDA_FUNCTION_MEMORY_SIZE | 128 | メモリサイズ(MB) |
AWS_LAMBDA_FUNCTION_TIMEOUT | 3 | 関数実行タイムアウト時間 |
AWS_LAMBDA_FUNCTION_HANDLER | app.lambda_handler | ハンドラ(後述) |
AWS_LAMBDA_FUNCTION_NAME | HelloWorldFunction | Lambda関数名 |
AWS_LAMBDA_FUNCTION_VERSION | $LATEST | Lambda関数のバージョン |
AWS_LAMBDA_LOG_GROUP_NAME | aws/lambda/HelloWorldFunction | ロググループ名 |
AWS_LAMBDA_LOG_STREAM_NAME | $LATEST | ログストリーム名 |
AWS_REGION | us-east-1 | リージョン |
AWS_DEFAULT_REGION | us-east-1 | デフォルトリージョン |
AWS_ACCESS_KEY_ID | defaultkey | IAMアクセスキー |
AWS_SECRET_ACCESS_KEY | defaultsecret | IAMシークレットキー |
AWS_ACCOUNT_ID | 123456789012 | AWSアカウントID |
マウント情報
SourceにSAM CLIでビルドしたLambda関数のディレクトリが読み取り専用で指定されています。つまり、コンテナと作成したコードを紐づける、一番重要な部分になります。
"Mounts": [
{
"Type": "bind",
"Source": "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction",
"Destination": "/var/task",
"Mode": "ro,delegated",
"RW": false,
"Propagation": "rprivate"
}
],
Sourceに指定されているディレクトリを確認すると、以下のような結果が得られます。
$ ls -l /home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction
合計 16
-rw-rw-r-- 1 izayoiwind izayoiwind 0 4月 17 08:23 __init__.py
-rw-rw-r-- 1 izayoiwind izayoiwind 1151 4月 17 08:23 app.py
drwxrwxr-x 2 izayoiwind izayoiwind 77 4月 17 08:23 certifi
drwxrwxr-x 2 izayoiwind izayoiwind 85 4月 17 08:23 certifi-2020.12.5.dist-info
drwxrwxr-x 4 izayoiwind izayoiwind 4096 4月 17 08:23 chardet
drwxrwxr-x 2 izayoiwind izayoiwind 109 4月 17 08:23 chardet-4.0.0.dist-info
drwxrwxr-x 2 izayoiwind izayoiwind 155 4月 17 08:23 idna
drwxrwxr-x 2 izayoiwind izayoiwind 89 4月 17 08:23 idna-2.10.dist-info
drwxrwxr-x 2 izayoiwind izayoiwind 4096 4月 17 08:23 requests
drwxrwxr-x 2 izayoiwind izayoiwind 85 4月 17 08:23 requests-2.25.1.dist-info
-rw-rw-r-- 1 izayoiwind izayoiwind 8 4月 17 08:23 requirements.txt
drwxrwxr-x 5 izayoiwind izayoiwind 272 4月 17 08:23 urllib3
drwxrwxr-x 2 izayoiwind izayoiwind 133 4月 17 08:23 urllib3-1.26.4.dist-info
app.pyの内容は以下の通りです。
import json
# import requests
def lambda_handler(event, context):
"""Sample pure Lambda function
Parameters
----------
event: dict, required
API Gateway Lambda Proxy Input Format
Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
context: object, required
Lambda Context runtime methods and attributes
Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html
Returns
------
API Gateway Lambda Proxy Output Format: dict
Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
"""
# try:
# ip = requests.get("http://checkip.amazonaws.com/")
# except requests.RequestException as e:
# # Send some context about this error to Lambda Logs
# print(e)
# raise e
return {
"statusCode": 200,
"body": json.dumps({
"message": "hello world",
# "location": ip.text.replace("\n", "")
}),
}
環境変数のハンドラの指定について
では、ここで環境変数のハンドラの指定を見てみましょう。以下のように指定されています。
app.lambda_handler
これを踏まえて、上記のapp.pyのコードを見ると、以下のように指定するということが分かります。
<拡張子を除いたソースファイル>.<関数名>
よろしい、ならば手動で動かすまでだ
ここまで得た情報で、実際にSAM CLIを使わずに動かすことができます。
せっかくなので、SAM CLIで作ったものではなく、独自で作ってみます。以下のコードをi_want_five_quadrillion_yen.pyという名前で保存します。(エラー処理等は特に考えてません、さらに筆者はPythonに関しては初心者レベルですので悪しからず)
# coding: utf-8
import json
def lambda_func(event, context):
output = '{}兆円欲しい!'.format(event['input'])
return {
'output': output,
}
保存先は/home/izayoiwind/i_want_five_quadrillion_yen/としています。
それでは、コンテナを起動します。
$ sudo docker run -d -m "128M" \
-e AWS_SAM_LOCAL=true \
-e AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128 \
-e AWS_LAMBDA_FUNCTION_TIMEOUT=3 \
-e AWS_LAMBDA_FUNCTION_HANDLER=i_want_five_quadrillion_yen.lambda_func \
-e AWS_LAMBDA_FUNCTION_NAME=IWantFiveQuadrillionYen \
-e AWS_LAMBDA_FUNCTION_VERSION=$LATEST \
-e AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/IWantFiveQuadrillionYen \
-e AWS_LAMBDA_LOG_STREAM_NAME=$LATEST \
-e AWS_REGION=us-east-1 \
-e AWS_DEFAULT_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID=defaultkey \
-e AWS_SECRET_ACCESS_KEY=defaultsecret \
-e AWS_ACCOUNT_ID=123456789012 \
-p 8080:8080 \
-v /home/izayoiwind/i_want_five_quadrillion_yen:/var/task:ro,delegated \
amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 \
/var/rapid/aws-lambda-rie --log-level error
起動後、curlで以下のURLを叩くと、Lambda関数が実行されます。Pythonの場合、マルチバイト文字を入れるとUnicodeエスケープシーケンスで返されるようなので、応答結果にちょっと細工をいれています。
$ curl -XPOST "http://localhost:8080/2015-03-31/functions/function/invocations" -s -d '{"input": "5000"}' | python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")'
{"output": "5000兆円欲しい!"}
【おまけ】作成したコンテナの関数をAWS CLIから叩いてみる
ところで、先ほど出てきた以下のURLですが、このURLはAWS CLIでLambda関数を叩くときのURLと同様です。
なので、AWS CLIからも叩くことが可能です。
以下のコマンドで叩くことができます。(関係ないけどAmazon Linux 2イメージに含まれるAWS CLIは1.x系のようです)
$ aws --endpoint-url http://localhost:8080 lambda invoke --function-name function --payload '{"input":"5000"}' ./test.txt
{
"StatusCode": 200
}
$ cat ./test.txt | python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")'
{"output": "5000兆円欲しい!"}
AWS CLI 2.x系の場合はpayloadにbase64エンコードした文字列を指定します。AWS CLI 2.x系を入れていた環境がPython 3系だったため、Unicodeエスケープ関連の処理を少し変えています。
$ echo {\"input\":\"5000\"} | base64
eyJpbnB1dCI6IjUwMDAifQo=
$ aws --endpoint-url http://amzn.izayoiwind.net:8080 lambda invoke --function-name function --payload eyJpbnB1dCI6IjUwMDAifQo= ./test.txt
{
"StatusCode": 200
}
$ cat test.txt | python -c 'from sys import stdin; print(stdin.readline().encode("utf-8").decode("unicode-escape"));'
{"output": "5000兆円欲しい!"}
注意点として、本家AWS LambdaをCLI経由で呼び出した場合、レスポンスにX-Amz-Function-Errorヘッダが含まれるため、以下のようにFunctionErrorが通知されますが、エミュレータでの実行の場合、実行に失敗してもレスポンスにX-Amz-Function-Errorヘッダが含まれないようで、ステータスコード以外の情報は一切通知されません。
$ aws lambda invoke --function-name i_want_five_quadrillio
n_yen ./test.txt
{
"FunctionError": "Unhandled",
"ExecutedVersion": "$LATEST",
"StatusCode": 200
}