AWS Lambda コンテナデプロイ入門 ~CloudShellで始めるハンズオン~

1.はじめに

1.1.はじめに

Lambdaに対してコンテナイメージのデプロイの経験がないのでハンズオンをしていきます。

1.2.Lambda コンテナの利点とは?

項番 項目名 詳細
1 サイズ制限の緩和 コンテナイメージでのデプロイ: 10GB まで対応(従来 50MB(解凍後250MB))
2 開発の柔軟性 Lambdaが公式にサポートしていない言語やバージョン、独自のライブラリ・フレームワークの組込みが可能

1.3.本ブログの構築イメージ

  • 本ブログの構成を記載する。

file

2.ハンズオン

2.1.前提

2.1.1.実行環境

  • AWS CloudShell 環境
    • Docker、AWS CLIはプリインストール済み
  • リージョン:バージニア北部

2.1.2.CloudShell環境スペック

項目 上限値
CPU 1 vCPU(仮想CPU)
メモリ 2 GiB RAM
ストレージ 1 GBの永続ストレージ(※120日間アクセスがない場合は自動削除)
セッション時間 最大12時間(無操作で20分で自動休止)

2.2.アプリケーションのコード作成

2.2.1.Lambda_function.py作成

  • Hello from {message}を返すLambda
  • 同内容のレスポンスをする場合、キャッシュが利用されるため回答に時間を含める
# プロジェクトディレクトリ作成・移動
mkdir my-python-lambda && cd my-python-lambda

# アプリケーションコード作成
cat > lambda_function.py << EOF
import json
from datetime import datetime
import pytz

def lambda_handler(event, context):
    # 東京時間の取得
    tokyo_tz = pytz.timezone('Asia/Tokyo')
    current_time = datetime.now(tokyo_tz).strftime('%Y-%m-%d %H:%M:%S %Z')

    # メッセージを取得(event パラメータから'message'キーを取得)
    message = event.get('message', 'Default message from Lambda!')

    return {
        'statusCode': 200,  # HTTP ステータスコード
        'body': json.dumps({
            'greeting': f'Hello from {message}!',
            'event': event,  # 受け取ったイベント全体を返す(デバッグ用)
            'requested_at': datetime.now(tokyo_tz).isoformat(),  # ISO形式の日時
            'display_time': current_time,  # 見やすい形式の日時
            'request_id': context.aws_request_id  # Lambdaリクエストの一意なID
        })
    }
EOF

2.2.2.requirements.txt作成

  • pytzタイムゾーン処理に特化したライブラリ
# 必要パッケージを記載
cat > requirements.txt << EOF
pytz
EOF

2.2.3.Dockerfile作成

# Dockerfile作成
cat > Dockerfile << EOF
# AWS公式よりPython 3.11 環境を利用
FROM public.ecr.aws/lambda/python:3.11

# アプリケーションコードをコピー
COPY lambda_function.py requirements.txt ./

# 依存関係をインストール
RUN pip install --no-cache-dir -r requirements.txt

# ハンドラを設定
CMD ["lambda_function.lambda_handler"]
EOF

2.3.ECR作成

2.3.1.ECRリポジトリ作成

# 変数設定
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REPO_NAME="lambda-container"
REGION=us-east-1

# ECRリポジトリ作成
aws ecr create-repository --repository-name $REPO_NAME

# ECRにログイン
aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com

2.4.Dockerイメージ作成

2.4.1.ビルド・プッシュ手順

# 変数設定
ECR_IMAGE_URI=$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME

# Dockerイメージビルド
docker build -t $ECR_IMAGE_URI:latest .

# ECRにプッシュ
docker push $ECR_IMAGE_URI:latest

2.4.2.【参考】古いイメージ削除する場合

イメージは残置されリソースを圧迫するため、適宜以下のコマンドで古いリソースを削除する

# イメージの一覧を出力
docker images

# 特定のイメージを削除(各イメージのプレフィックスには、各自のアカウントIDが挿入されている)
docker rmi ${AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container:latest

# 古いイメージ(最新バージョンがあるもの)を削除
docker image prune

# 全てのイメージを削除。他のプロジェクトで使用中のイメージも削除される可能性があるため、使用は慎重に実行する。
docker system prune -a

2.5.Lambda関数デプロイ

2.5.1.Lambda用 IAMロール作成

# IAMロール作成
aws iam create-role --role-name lambda-container-role --assume-role-policy-document '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}'

# IAMポリシーをアタッチ
aws iam attach-role-policy \
    --role-name lambda-container-role \
    --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# IAMロールARNを取得
ROLE_ARN=$(aws iam get-role --role-name lambda-container-role --query 'Role.Arn' --output text)

2.5.2.Lambda作成

2.5.2.1.Lambdaの設定値
項目 設定値 説明
function-name my-python-container-function Lambda関数名
role $ROLE_ARN IAMロールARN
code ImageUri=$ECR_IMAGE_URI コンテナイメージURI
description" Python Lambda Container from CloudShell" 関数の説明文
timeout 30 タイムアウト(秒)
memory-size 256 メモリサイズ(MB)
package-type Image デプロイパッケージタイプ
region $REGION デプロイ先のリージョン
2.5.2.2.Lambda関数の作成
# Lambda関数を作成
aws lambda create-function \
  --function-name my-python-container-function \
  --role $ROLE_ARN \
  --code ImageUri=$ECR_IMAGE_URI:latest \
  --description "Python Lambda Container from CloudShell" \
  --timeout 30 \
  --memory-size 256 \
  --package-type Image \
  --region $REGION

# 2回目以降のコマンド((イメージ更新時に使用)
aws lambda update-function-code \
  --function-name my-python-container-function \
  --image-uri $ECR_IMAGE_URI:latest \
  --region $REGION

2.6.挙動確認

2.6.1.コマンド実行

  • "StatusCode": 200が返ってくることを確認
# テストイベントを作成
echo '{"key": "value", "message": "Lambda Container"}' > test-event.json

# Lambda関数の呼出し
aws lambda invoke \
  --function-name my-python-container-function \
  --payload fileb://test-event.json \
  response.json

# レスポンスの確認
cat response.json

2.6.2.実行結果

2.6.2.1.コンソールの出力
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
2.6.2.2.response.jsonの内容
  • 適宜改行して記載
{
  "statusCode": 200,
  "body":
    "{
      \"greeting\": \"Hello from Lambda Container!\",
      \"event\": {
        \"key\": \"value\",
        \"message\": \"Lambda Container\"
        },
      \"requested_at\": \"2025-05-05T08:20:55.071375+09:00\",
      \"display_time\": \"2025-05-05 08:20:55 JST\",
      \"request_id\": \"8f192969-b9b3-4679-abb6-0c3cf307dd92\"
    }"
}

3.おわりに

3.1.得られた知見

  • コンテナイメージを利用した、Lambdaのデプロイ方法
  • 同一イベントによるキャッシュ問題への対応(タイムスタンプ付加など)

3.2.今後の課題

  • ECS/EKS との比較検討
  • コンテナベース開発の発展(CI/CDパイプライン)

3.3.サンプルコード

本ハンズオンで使用したコードは以下のリポジトリで公開しています:

Last modified: 2025-05-08

Author