Linux上に開発コンテナ + SAM でLambdaの開発環境を構築する
概要
AWS SAMでLambdaの関数を作成する際に開発コンテナ上に環境を構築をしたものの、躓きどころがあったため備忘録としてまとめています。
この記事で書くこと
- 開発コンテナのターミナルで
$ sam local invoke
するための基本的な設定 - 環境構築をする上でつまづいたポイントと解決方法
環境
- ホストOS: Ubuntu22.04.2LTS
- エディタ: VSCode
- Lambdaランタイム: Go 1.x
devcontianerを用いた環境構築
以下、構築した手順と躓いたポイントを記載しますが、最終的な状態はリポジトリにPushしています。
基本的なdevcontainer.jsonの作成
最初にプロジェクトのルートディレクトリに開発コンテナを起動するための設定ファイルを作成します。
手元ではVSCodeのコマンドパレットからNew Devcontainer
を選択して生成しましたが、手動で作成しても問題ありません。
作成したファイルは以下の状態です。
{
"name": "Go",
"image": "mcr.microsoft.com/devcontainers/go:0-1",
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
"ghcr.io/customink/codespaces-features/sam-cli:1": {}
}
}
- mcr.microsoft.com/devcontainers/go:0-1
- 公式で提供されるGo言語の開発環境のimageを指定
- その他テンプレートはこちらを参照: https://containers.dev/templates
- ghcr.io/devcontainers/features/aws-cli:1
- 開発コンテナ内にaws cliをインストール
- ghcr.io/customink/codespaces-features/sam-cli:1
- 開発コンテナ内にsam cliをインストール
- ghcr.io/devcontainers/features/docker-outside-of-docker:1
- 開発コンテナ内から兄弟コンテナを作成、操作できるdoodの設定を追加
- sam localコマンドでのエミュレートにコンテナを使用するため
sam アプリケーションの生成
起動した開発コンテナのターミナルで$ sam init
コマンドを実行し、アプリケーションのテンプレートを作成します。
ここでは単一のlambda関数で構成され、シンプルなレスポンスの返るhello-worldテンプレートを選択しました。ランタイムはgo1.xを指定しています。
$ sam init
# 〜対話インターフェース部分は省略〜
-----------------------
Generating application:
-----------------------
Name: sam-app
Runtime: go1.x
Architectures: x86_64
Dependency Manager: mod
Application Template: hello-world
Output Directory: .
Configuration file: sam-app/samconfig.toml
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
SAM CLI update available (1.93.0); (1.92.0 installed)
To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html
躓きどころと変更した点
この時点では開発コンテナからlambdaのローカル実行ができませんでした。以下、ローカル実行ができるまでに変更した点を記載します。
変更1: host.docker.internal
生成したテンプレートをbuildしてlambdaを実行してみます。
$ cd sam-app/
$ sam build
$ sam local invoke
samはlambdaのエミュレートのためにコンテナへ接続しますが、以下の通りタイムアウトになりました。
Timed out while attempting to establish a connection to the container. You can increase this timeout by setting the SAM_CLI_CONTAINER_CONNECTION_TIMEOUT environment variable. The current timeout is 20.0 (seconds).
samはデフォルトで、自身が実行されている環境(開発コンテナ)のlocalhost
でコンテナに接続しようとします。しかし、コンテナの操作にdoodを用いているため実際にコンテナが実行されるのは開発コンテナのホストされているOS側であり、そちらに接続させる必要がありました。
まず、開発コンテナからホストOSのIPアドレスを簡単に扱えるようにhost.docker.internal
を設定します。開発コンテナの作成時にhost.docker.internal
を追加するようにdevcontainer.json
にdockerコマンドの--add-host
オプションを追加しました。
{
"name": "Go",
"image": "mcr.microsoft.com/devcontainers/go:0-1",
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
"ghcr.io/customink/codespaces-features/sam-cli:1": {}
},
"runArgs": ["--add-host=host.docker.internal:host-gateway"]
}
開発コンテナのリビルド後に/etc/hosts
にhost.docker.internal
としてホストOSのIPアドレスが追加されている事が確認できます。
$ cat /etc/hosts | grep host.docker.internal
172.17.0.1 host.docker.internal
変更2: workspace
改めて$ sam local invoke
を実行します。
ここでは変更1で追加したhost.docker.internal
をオプションで指定して実行しています。
$ cd sam-app/
$ sam local invoke --container-host host.docker.internal --container-host-interface host.docker.internal
タイムアウトは発生せず、コンテナに接続できているように見えますが新たにエラーが発生しています。
SAM CLI now collects telemetry to better understand customer needs.
You can OPT OUT and disable telemetry collection by setting the
environment variable SAM_CLI_TELEMETRY=0 in your shell.
Thanks for your help!
Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
Invoking hello-world (go1.x)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/go:1-rapid-x86_64.
Mounting /workspaces/sam-on-devcontainer/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container
START RequestId: 067df06e-cb09-488b-ad53-2fa21df8d20b Version: $LATEST
fork/exec /var/task/hello-world: no such file or directory: PathError
null
END RequestId: 067df06e-cb09-488b-ad53-2fa21df8d20b
REPORT RequestId: 067df06e-cb09-488b-ad53-2fa21df8d20b Init Duration: 0.11 ms Duration: 5.40 ms Billed Duration: 6 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"errorMessage":"fork/exec /var/task/hello-world: no such file or directory","errorType":"PathError"}
SAM CLI update available (1.93.0); (1.92.0 installed)
To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html
samはbuildした実行ファイルをコンテナにマウントして実行しますが、これがうまく行っていませんでした。doodでボリュームをマウントする際、マウント元は開発コンテナではなくホストOSになるようです。
samは開発コンテナ上のパスである/workspaces/sam-on-devcontainer/sam-app/.aws-sam/build/HelloWorldFunction
をマウントしようとしていますが、ホストOS上ではパスが異なるため空のディレクトリが作成されてマウントされていました。
開発コンテナとホストOSでのパスを同一にすることで問題を回避することができるそうなので、workspaceのパスを変更して対処します。
{
"name": "Go",
"image": "mcr.microsoft.com/devcontainers/go:0-1",
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
"ghcr.io/customink/codespaces-features/sam-cli:1": {}
},
"runArgs": ["--add-host=host.docker.internal:host-gateway"],
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind,consistency=cached",
"workspaceFolder": "${localWorkspaceFolder}"
}
開発コンテナのリビルド後、改めて$ sam local invoke
すると正常なレスポンスが確認できました。
$ cd sam-app/
$ sam local invoke --container-host host.docker.internal --container-host-interface host.docker.internal
SAM CLI now collects telemetry to better understand customer needs.
You can OPT OUT and disable telemetry collection by setting the
environment variable SAM_CLI_TELEMETRY=0 in your shell.
Thanks for your help!
Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
Invoking hello-world (go1.x)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/go:1-rapid-x86_64.
Mounting /home/sut103/dev/sam-on-devcontainer/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container
START RequestId: a8671a52-7529-4f26-8e19-342c69fc8527 Version: $LATEST
END RequestId: a8671a52-7529-4f26-8e19-342c69fc8527
REPORT RequestId: a8671a52-7529-4f26-8e19-342c69fc8527 Init Duration: 0.15 ms Duration: 13.10 ms Billed Duration: 14 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"statusCode":200,"headers":null,"multiValueHeaders":null,"body":"Hello, world!\n"}
SAM CLI update available (1.93.0); (1.92.0 installed)
To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html
おわりに
本記事ではシンプルな開発コンテナとsamの基本的な環境構築について記載しました。
手元ではさらにdocker-composeの使用やdynamodb-localとの接続も試していたため、そちらも別途まとめたいと思います。
参考など
Discussion