Lambda ローカルでサンプルアプリを動かす

前回の記事でLambdaのローカル開発環境を構築したので、今回はAWSチュートリアルのサンプルをビルドして動かしてみる。

AWSのチュートリアルは下記を参考にする。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html

前回執筆した記事は下記の通り。

https://qiita.com/nobumichi/items/e876a448b7be21e7e51a

# 作業環境
- Windows11 Pro 22H2
- Windows Terminal
  - PowerShell 7.3.1
- Python 3.9.13
- aws-cli 2.9.11
- sam-cli 1.67.0
- git 2.39.0.windows.2

# サンプルアプリ用の作業ディレクトリを作成する
任意の作業ディレクトリを作成する。私は`Documents`配下に`lambda`ディレクトリを作成しました。
同様の場所に作業ディレクトリを作成する場合は、`xxxxxx`の部分は皆さんの環境に合わせて変更してください。
```
cd C:\Users\xxxxxx\Documents
```
```
mkidr lambda
```
```
cd .\lambda
```

# サンプルアプリをダウンロードする
Windows Terminalを起動し、下記コマンドを実行する。
```
sam init
```

いきなり下記エラーメッセージが出た…
```
Error: Failed to modify a local file when cloning app templates. MAX_PATH should be enabled in the Windows registry.
For more details on how to enable MAX_PATH for Windows, please visit: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html
```
WindowsのレジストリでMAX_PATHを有効にする必要があるそう。

エラーメッセージ中の下記サイトを訪れてみる。

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html

下記Topicsの 3.Enable long paths (Windows 10 and newer only). の注意文を見てみると、Microsoftの開発ドキュメントを見てほしいとのこと。

- Installing the AWS SAM CLI
  - Windows
    - 3.Enable long paths (Windows 10 and newer only).

> To enable long paths, see [Enable Long Paths in Windows 10, Version 1607, and Later](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=powershell#enable-long-paths-in-windows-10-version-1607-and-later) in the Microsoft Windows App Development Documentation.

ということで、促されるままにMicrosoftの開発ドキュメントを見てみる。

すると、PowerShellを起動し、下記コマンドを実行せよとのこと。
```
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
```

管理者権限でWindows Terminalを起動しないと、下記のエラーメッセージが出てしまうので注意が必要。
参考サイトも一緒に貼り付けておく。
```
New-ItemProperty: Requested registry access is not allowed.
```
https://github.com/ChrisTitusTech/winutil/issues/386

Windows Terminalを起動し直した後に作業ディレクトリに移動し、下記コマンドを再度実行する。
```
sam init
```

無事に成功したようで、下記メッセージが出力された。
参考までに、以下にWindows Terminal上に表示されたやり取りをそのまま貼り付けておく。

```
You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Infrastructure event management
        8 - Serverless Connector Hello World Example
        9 - Multi-step workflow with Connectors
        10 - Lambda EFS example
        11 - Machine Learning
Template: 1

Use the most popular runtime and package type? (Python and zip) [y/N]: y

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: y
X-Ray will incur an additional cost. View https://aws.amazon.com/xray/pricing/ for more details

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: y
AppInsights monitoring may incur additional cost. View https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/appinsights-what-is.html#appinsights-pricing for more details

Project name [sam-app]:   ← ここは空欄です。何も入力せずにエンターキー押下。

Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)

    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: python3.9
    Architectures: x86_64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .

    Next steps can be found in the README file at ./sam-app/README.md


Commands you can use next
=========================
[*] Create pipeline: cd sam-app && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-app && sam validate
[*] Test Function in the Cloud: cd sam-app && sam sync --stack-name {stack-name} --watch
```

# サンプルアプリをビルドする
サンプルアプリの`template.yaml`ファイルがあるプロジェクトディレクトリに移動する。
デフォルトでは`sam-app`となっている。
```
cd sam-app
```

下記コマンドを実行する。
```
sam build
```

見事にビルドが失敗した。ランタイムがPython3.9になっている模様。
```
Building codeuri: C:\Users\xxxxxx\Documents\lambda\sam-app\hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction

Build Failed
Error: PythonPipBuilder:Validation - Binary validation failed for python, searched for python in following locations  : ['C:\\Users\\xxxxxx\\AppData\\Local\\Programs\\Python\\Python311\\python.EXE', 'C:\\Users\\xxxxxx\\AppData\\Local\\Microsoft\\WindowsApps\\python.EXE', 'C:\\Users\\xxxxxx\\AppData\\Local\\Microsoft\\WindowsApps\\python3.EXE'] which did not satisfy constraints for runtime: python3.9. Do you have python for runtime: python3.9 on your PATH?
```

そのため、RuntimeのPythonのバージョンを3.11に変更する。
`template.yaml`ファイルは`sam-app`ディレクトリ配下にある。
```diff_yaml:template.yaml
- Runtime: python3.9
+ Runtime: python3.11
```

再び、下記コマンドを実行する。
```
sam build
```
```
Building codeuri: C:\Users\xxxxxx\Documents\lambda\sam-app\hello_world runtime: python3.11 metadata: {} architecture: x86_64 functions: HelloWorldFunction

Build Failed
Error: 'python3.11' runtime is not supported
```
？？

どうやら、ランタイムのPythonのバージョンは3.9までしかサポートしていないらしい…

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html

急遽、Macでお馴染みのpyenvをインストールし、3.9系最新のPython3.9.13をインストールした。

https://my-web-note.com/install_python_pyenv_windows/

Windows Terminalを起動し直し、Python3.9.13が使用可能なことを確認した。
そして、再び下記コマンドを実行する。
```
sam build
```
```
Building codeuri: C:\Users\のぶみち\Documents\lambda\sam-app\hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction
Running PythonPipBuilder:ResolveDependencies

Build Failed
Error: PythonPipBuilder:ResolveDependencies - 'utf-8' codec can't decode byte 0x82 in position 765: invalid start byte
```
？？

色々調べたが、このエラーの原因はよく分からなかった…

`sam-app`ディレクトリ配下の`README.md`を見ると、ローカルのテストでは下記コマンドを使用せよとのこと。
試しに実行したらビルドが成功した。

> Use the SAM CLI to build and test locally
> Build your application with the `sam build --use-container` command.
> sam-app$ sam build --use-container
```
sam build --use-container
```

以下にビルド時のログを貼り付けておく。
Docker container imageのロードに結構時間がかかった。
```
Starting Build inside a container
Building codeuri: C:\Users\xxxxxx\Documents\lambda\sam-app\hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction

Fetching public.ecr.aws/sam/build-python3.9:latest-x86_64 Docker container image...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Mounting C:\Users\xxxxxx\Documents\lambda\sam-app\hello_world as /tmp/samcli/source:ro,delegated inside runtime container

Build Succeeded

Built Artifacts  : .aws-sam\build
Built Template   : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
```

# サンプルアプリをローカルでテストする
下記コマンドを実行する。
```
sam local start-api
```

下記のようなメッセージが出力されれば、動作確認の準備が完了となる。
```
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. If you used sam build before running local commands, you will need to re-run sam build for the changes to be picked up. You only need to restart SAM CLI if you update your AWS SAM template
2023-01-03 18:06:07  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
Invoking app.lambda_handler (python3.9)
Image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-python3.9
Building image...Invoking app.lambda_handler (python3.9)
Image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-python3.9
Building image...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
....Skip pulling image and use local one: public.ecr.aws/sam/emulation-python3.9:rapid-1.67.0-x86_64.

Mounting C:\Users\xxxxxx\Documents\lambda\sam-app\.aws-sam\build\HelloWorldFunction as /var/task:ro,delegated inside runtime container
.
Skip pulling image and use local one: public.ecr.aws/sam/emulation-python3.9:rapid-1.67.0-x86_64.

Mounting C:\Users\xxxxxx\Documents\lambda\sam-app\.aws-sam\build\HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: a413c2a5-b64a-4973-a621-38acc4762742 Version: $LATEST
START RequestId: 84c14d09-78bf-4cc1-9316-960d5ab62847 Version: $LATEST
END RequestId: a413c2a5-b64a-4973-a621-38acc4762742
REPORT RequestId: a413c2a5-b64a-4973-a621-38acc4762742  Init Duration: 0.55 ms  Duration: 1232.29 ms    Billed Duration: 1233 ms        Memory Size: 128 MB     Max Memory Used: 128 MB
END RequestId: 84c14d09-78bf-4cc1-9316-960d5ab62847
REPORT RequestId: 84c14d09-78bf-4cc1-9316-960d5ab62847  Init Duration: 0.41 ms  Duration: 980.83 ms     Billed Duration: 981 ms Memory Size: 128 MB     Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2023-01-03 18:12:47 127.0.0.1 - - [03/Jan/2023 18:12:47] "GET /hello HTTP/1.1" 200 -
```

試しに`curl`コマンドでリクエストを送信してみる。
```
curl http://127.0.0.1:3000/hello
```

下記が表示されることを確認する。
```
{"message": "hello world"}
```

下記コマンドでLambda関数を直接呼び出すこともできるらしい。
```
sam local invoke "HelloWorldFunction" -e events/event.json
```

下記のようなログが表示されることを確認する。
```
Invoking app.lambda_handler (python3.9)
Skip pulling image and use local one: public.ecr.aws/sam/emulation-python3.9:rapid-1.67.0-x86_64.

Mounting C:\Users\xxxxxx\Documents\lambda\sam-app\.aws-sam\build\HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: 36a75d90-f84f-4fc1-9f08-0dbd1be90e3b Version: $LATEST
END RequestId: 36a75d90-f84f-4fc1-9f08-0dbd1be90e3b
REPORT RequestId: 36a75d90-f84f-4fc1-9f08-0dbd1be90e3b  Init Duration: 0.18 ms  Duration: 192.46 ms     Billed Duration: 193 ms Memory Size: 128 MB     Max Memory Used: 128 MB
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}
```

# 参考文献
- [チュートリアル: Hello World アプリケーションのデプロイ](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html)
- [Installing the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)
- [Enable Long Paths in Windows 10, Version 1607, and Later](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=powershell#enable-long-paths-in-windows-10-version-1607-and-later)
- [Requested registry access is not allowed. #386](https://github.com/ChrisTitusTech/winutil/issues/386)
- [Lambda ランタイム](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html)
- [【2022年版】WindowsにPythonバージョン管理『pyenv』をインストールする方法](https://my-web-note.com/install_python_pyenv_windows/)

以上。