Google Cloud Shell から AWS ECR/Lambdaデプロイ ハンズオン

1.はじめに

1.1.1.背景

AWS CloudShellは便利なツールですが、限られたリソース(1 vCPU、2GB RAM)しか持たないため、大きめのコンテナをビルドする際に制約を感じることがあります。
そこで代替手段として、より高いスペック(2 vCPU、4GB RAM)を持つGoogle Cloud Shellを活用し、AWS ECRへのイメージプッシュとLambda関数のデプロイを試みました。

1.1.2.AWSとGoogle Cloud の Cloud Shellの違い

  • DockerイメージのビルドにはCPUやメモリリソースが要求されるため、Google Cloud Shellのスペックは助かります。
項目 AWS Cloud Shell Google Cloud Shell
CPU 1 vCPU 2 vCPU
メモリ 2 GB RAM 4 GB RAM
ストレージ 1 GB 永続ストレージ 5 GB 永続ストレージ
データ保持期間 120日間 手動でリセットするまで無期限
コードエディタ シンプルなエディタ フル機能のWeb IDEを内蔵
ウェブプレビュー 非対応 Web Previewで5000番ポート等を外部公開可能

1.1.3.本構築の構成図

file

2.ハンズオン

2.1.前提

2.1.1.実行環境

  • AWS の Cloud Shell
    • リージョン:us-east-1 として実施
  • Google Cloud の Cloud Shell

2.1.2.手順の流れ

  • AWS側での準備はAWS Cloud Shellで、それ以降のDockerビルドやデプロイはGoogle Cloud Shellで実施する。

2.2.AWS側での準備

  • AWSのCloud Shellで以下コマンドを実施
  • PoCのためIAMユーザを作成して認証情報を付与する(※本番環境では、IAMロール作成やポリシーアタッチに必要な最小限の権限(例: iam:CreateRole, iam:AttachRolePolicy, iam:GetRole, iam:PassRoleなど)を付与することを推奨)
  • 作成されたアクセスキーの取扱いには注意してください(※後続の手順後に削除推奨)
# 変数設定
USER="GoogleCloud_CloudShell"

# IAMユーザ作成
aws iam create-user --user-name $USER

# ユーザーにポリシーをアタッチする(ECR、Lambda、IAMの権限)
aws iam attach-user-policy --user-name $USER --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
aws iam attach-user-policy --user-name $USER --policy-arn arn:aws:iam::aws:policy/AWSLambda_FullAccess
aws iam attach-user-policy --user-name $USER --policy-arn arn:aws:iam::aws:policy/IAMFullAccess

# アクセスキー作成して結果をJSONファイルに保存
aws iam create-access-key --user-name $USER > ${USER}_access_key.json

# ファイル確認
cat ${USER}_access_key.json

2.3.Google Cloud側での準備

2.3.1.AWS CLI インストール

  • Google CloudのCloud Shellで以下コマンドを実施
  • aws configureでの設定した認証情報は~/.aws/credentialsファイルに保存される。
# AWS CLI ダウンロード
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

# 解凍
unzip awscliv2.zip

# AWS CLI インストール
sudo ./aws/install

2.3.2.AWS認証情報の設定

  • 2.2.AWS側での準備で作成した${USER}_access_key.jsonを登録
# AWS認証情報の設定
aws configure

# 以下を払い出されたユーザのものを登録
AWS Access Key ID [None]: ■■■■■■■■■■■
AWS Secret Access Key [None]: ■■■■■■■■■■■
Default region name [None]: us-east-1
Default output format [None]: json

2.4.Lambda関数作成

2.4.1.アプリケーション部分

# lambda_function.py作成
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.4.2.requirements.txt作成

# requirements.txt作成
cat > requirements.txt << EOF
pytz
EOF

2.4.3.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.5.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.6.Dockerイメージのビルドとプッシュ

# 変数設定
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.7.Lambda実行ロールと関数デプロイ

# 変数設定
FUNCTIONNAME="my-python-container-function"
LAMBDAROLE="lambda-container-role"

# IAMロール作成
aws iam create-role --role-name $LAMBDAROLE --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 $LAMBDAROLE \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

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

# Lambda関数を作成
aws lambda create-function \
--function-name $FUNCTIONNAME \
--role $ROLE_ARN \
--code ImageUri=$ECR_IMAGE_URI:latest \
--description "Python Lambda Container from GCP CloudShell" \
--timeout 30 \
--memory-size 256 \
--package-type Image \
--region $REGION

2.8.挙動確認

2.8.1.コマンド実行

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

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

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

2.8.2.実行結果

2.8.2.1.コンソールの出力
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
2.8.2.2.response.jsonの内容
  • 適宜改行して記載
{
  "statusCode": 200,
  "body":
    "{
      \"greeting\": \"Hello from Lambda Container from Google Cloud!\",
      \"event\": {
        \"key\": \"value\",
        \"message\": \"Lambda Container from Google Cloud\"
        },
      \"requested_at\": \"2025-05-07T22:41:16.821398+09:00\",
      \"display_time\": \"2025-05-07 22:41:16 JST\",
      \"request_id\": \"452d46a9-df6a-40be-889c-58c1183003d8\"
    }"
}

2.9.クリーンアップ

2.9.1.Google Cloud側での実行

# Lambda関数の削除
aws lambda delete-function --function-name my-python-container-function

# ECRリポジトリの削除(必要に応じて)
aws ecr delete-repository --repository-name $REPO_NAME --force

# IAMロールの削除
aws iam detach-role-policy \
--role-name lambda-container-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam delete-role --role-name lambda-container-role

2.9.2.AWS側での実行

  • アクセスキーIDは、2.2で作成した${USER}_access_key.jsonファイルから取得可能
# 変数設定
USER="GoogleCloud_CloudShell"

# IAMユーザーのクリーンアップ
aws iam delete-access-key --user-name $USER --access-key-id ${アクセスキーID}
aws iam detach-user-policy --user-name $USER --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
aws iam detach-user-policy --user-name $USER --policy-arn arn:aws:iam::aws:policy/AWSLambda_FullAccess
aws iam detach-user-policy --user-name $USER --policy-arn arn:aws:iam::aws:policy/IAMFullAccess
aws iam delete-user --user-name $USER

3.おわりに

3.1.得られた知見

  • Google CloudのCloudshellからAWS ECRとLambdaを操作する方法の理解

3.2.今後の課題

  • 本番環境では一時的な認証情報を使用する方法(IAM Roles Anywhere、SAML連携など)への移行
  • マルチクラウド環境における認証情報の一元管理の方法
Last modified: 2025-05-07

Author