はじめに
Lambdaの開発で「ローカルで動いたのに本番で動かない」「チームメンバーの環境では再現しない」という経験はないでしょうか。
その根本原因の多くは開発環境の差異にあります。Lambdaはランタイムバージョン・環境変数・IAMロールなど依存する要素が多く、ローカル環境を本番に近づけることが難しいです。
Dev Containerはこの問題を一気に解決します。.devcontainerの設定ファイルをリポジトリに含めるだけで、チーム全員が同一の開発環境をDockerコンテナ上に再現できます。SAM CLIと組み合わせることで、Lambda関数をクラウドにデプロイせずにローカルで呼び出し・デバッグできる開発体験が得られます。
本記事では、Dev Container + SAM CLIによるLambdaローカル開発環境の構築から実際の開発フローまでを解説します。
前提条件
以下がインストール済みであることを確認してください。
- Docker Desktop(またはDocker Engine + Docker CLI)
- Visual Studio Code
-
Dev Containers拡張機能(
ms-vscode-remote.remote-containers)
AWS CLIやSAM CLIはコンテナ内にインストールするため、ホストマシンには不要です。
.devcontainerの構成
プロジェクトルートに.devcontainer/ディレクトリを作成し、以下の2ファイルを配置します。
your-lambda-project/
├── .devcontainer/
│ ├── devcontainer.json
│ └── Dockerfile
├── src/
│ └── handler.py
├── template.yaml
└── ...
Dockerfile
FROM public.ecr.aws/amazonlinux/amazonlinux:2023
# 基本ツールのインストール
RUN dnf install -y \
python3.12 \
python3.12-pip \
python3-pip \
git \
curl \
unzip \
make \
tar \
gzip \
&& dnf clean all
# AWS CLI v2 のインストール
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
&& unzip awscliv2.zip \
&& ./aws/install \
&& rm -rf aws awscliv2.zip
# AWS SAM CLI のインストール
RUN curl -Lo sam-installer.zip "https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip" \
&& unzip sam-installer.zip -d sam-installation \
&& ./sam-installation/install \
&& rm -rf sam-installation sam-installer.zip
# 非rootユーザーの作成
RUN useradd -ms /bin/bash vscode
USER vscode
WORKDIR /workspace
ポイント: ベースイメージに
amazonlinux:2023を使うことで、Lambdaの実行環境(Amazon Linux 2023ベース)と最も近い環境が手元に揃います。
devcontainer.json
{
"name": "Lambda Dev",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"runArgs": [
"--privileged"
],
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"workspaceFolder": "/workspace",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
"customizations": {
"vscode": {
"extensions": [
"amazonwebservices.aws-toolkit-vscode",
"ms-python.python",
"ms-python.vscode-pylance",
"amazonwebservices.amazon-q-vscode"
],
"settings": {
"python.defaultInterpreterPath": "/usr/bin/python3.12",
"editor.formatOnSave": true
}
}
},
"postCreateCommand": "pip3 install --user -r requirements-dev.txt 2>/dev/null || true",
"remoteUser": "vscode"
}
重要:
docker.sockのマウントはSAM CLIがLambda実行用のDockerコンテナを起動するために必要です。Dev Container内からDocker(Docker-in-DockerではなくDocker-outside-of-Docker)を使う形になります。
SAMテンプレートとLambda関数
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda local dev example
Globals:
Function:
Timeout: 30
MemorySize: 256
Runtime: python3.12
Environment:
Variables:
LOG_LEVEL: DEBUG
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: handler.lambda_handler
Events:
ApiEvent:
Type: Api
Properties:
Path: /hello
Method: get
src/handler.py
import json
import logging
import os
logger = logging.getLogger()
logger.setLevel(os.environ.get("LOG_LEVEL", "INFO"))
def lambda_handler(event, context):
logger.debug("Received event: %s", json.dumps(event))
name = event.get("queryStringParameters", {}) or {}
name = name.get("name", "World")
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"message": f"Hello, {name}!"}),
}
SAM CLIによるローカル実行
Dev Containerを開いたターミナルで以下のコマンドを使います。
ビルド
sam build
--use-containerを付けるとLambdaのランタイムコンテナ内でビルドされ、ネイティブ拡張を含む依存ライブラリも正しく解決されます。
sam build --use-container
単発呼び出し(sam local invoke)
# JSONファイルでイベントを渡す
sam local invoke HelloFunction --event events/hello.json
# 標準入力から渡す
echo '{"queryStringParameters": {"name": "Yudai"}}' | sam local invoke HelloFunction
API Gatewayのローカルエミュレーション
sam local start-api --port 3000
別ターミナルからcurlで叩けます。
curl "http://localhost:3000/hello?name=Yudai"
# => {"message": "Hello, Yudai!"}
Lambdaエンドポイントのエミュレーション
AWS SDKから直接Lambdaを呼び出すテストをしたい場合はstart-lambdaを使います。
sam local start-lambda --port 3001
import boto3
client = boto3.client(
"lambda",
endpoint_url="http://localhost:3001",
region_name="us-east-1",
aws_access_key_id="dummy",
aws_secret_access_key="dummy",
)
response = client.invoke(
FunctionName="HelloFunction",
Payload=b'{"queryStringParameters": {"name": "test"}}',
)
print(response["Payload"].read())
実際の開発フロー
Dev Containerを使った日常の開発サイクルはシンプルです。
- VS Codeでリポジトリを開く → 「Reopen in Container」でコンテナ起動
-
src/handler.pyを編集 -
sam buildでビルド(初回は数分、2回目以降はキャッシュが効いて速い) -
sam local invokeまたはsam local start-apiで動作確認 - ユニットテストも
pytest src/tests/でコンテナ内で完結 - 問題なければ
sam deployで本番環境へ
# 初回デプロイ(設定ファイルを生成)
sam deploy --guided
# 2回目以降
sam deploy
ホットリロードを効かせる
sam local start-apiは--warm-containers EAGERオプションを付けると、コンテナを事前起動して呼び出しのレイテンシを下げられます。ただし変更を反映させるには都度sam buildが必要です。
コードの変更を即座に反映したい場合はsam sync --watchで変更を自動検知・デプロイできます(クラウドへのsyncですが、差分デプロイなので高速)。
まとめ
| 手法 | メリット | デメリット |
|---|---|---|
| Dev Container + SAM CLI | 環境差異ゼロ・チーム共有簡単 | 初期セットアップに数十分 |
| ローカルに直接SAM CLIインストール | すぐ始められる | チーム間で差異が出やすい |
| LocalStack | 周辺サービス(S3/DynamoDB等)も含めてエミュレート | Pro プランが必要な機能あり |
Dev Containerを一度セットアップしてしまえば、git clone → 「Reopen in Container」だけで誰でも同じ環境を手に入れられます。特にチーム開発・CI連携を見据えると、この投資は早い段階で回収できます。
Lambdaのローカル開発に課題を感じていたら、ぜひ試してみてください。