AWS - Lambda
概要
AWS Lambdaは、AWSが提供するサーバーレスコンピューティングサービスである。
サーバの管理やプロビジョニングを行うことなく、コードを実行できる環境を提供する。
主な特徴を以下に示す。
- サーバーレス
- サーバ管理、OS管理、パッチ適用が不要
- イベント駆動型
- S3、DynamoDB、API Gateway等のイベントをトリガーに実行
- 自動スケーリング
- リクエスト数に応じて自動的にスケール
- 従量課金
- 実行時間とメモリ使用量に基づく課金
- 多言語対応
- Python、Node.js、Java、Go、Ruby、.NET等をサポート
AWS Lambdaの基本概念を以下に示す。
- 関数
- 実行するコードの単位
- トリガー
- 関数を起動するイベントソース
- ランタイム
- コードを実行する環境 (言語とバージョン)
- ハンドラ
- 関数のエントリーポイント
- 実行ロール
- 関数が他のAWSサービスにアクセスするためのIAMロール
AWS Lambdaは永続的な無料利用枠を提供しており、個人利用や小規模なアプリケーションであれば無料枠内で運用できることが多い。
Lambdaの無料枠について
無料枠の内容
- リクエスト数 : 月100万リクエストまで無料
- コンピューティング時間
- 月40万GB秒まで無料
- 128MBメモリで実行した場合、約320万秒 (約888時間) 相当
- その他
- Lambda関数のコード保存は無料
- CloudWatch Logsへの書き込みは別途課金対象
※注意
- この無料枠は12ヶ月限定ではなく、永続的に利用可能である。
- 無料枠はアカウント全体で共有される。
- データ転送料金は別途発生する場合がある。
- 同時実行数には制限があり、デフォルトは1000 (リージョンごと) である。
料金体系
無料枠を超えた場合の料金 (東京リージョンの例)
- リクエスト料金
- $0.20 / 100万リクエスト
- コンピューティング料金
- $0.0000166667 / GB秒
- 例 : 128MBメモリで100ミリ秒実行 = 0.0125GB秒
- 100万回実行の場合 : 約$0.21
- 追加料金
- Provisioned Concurrency : $0.000004861 / GB秒
- Ephemeral Storage (512MB超過分) : $0.0000000309 / GB秒
Lambdaの停止
AWS Lambdaには従来的な意味での停止という概念がない。
EC2のようなインスタンスベースのサービスとは異なり、Lambdaはイベント駆動型のサーバーレスサービスであり、実行されていない時は課金が発生しないためである。
コストを抑える方法
使用していない場合のコストを抑えるには、以下に示す選択肢がある。
1. トリガーの無効化
- イベントソース (CloudWatch Events、API Gateway等) を無効化する。
- 関数自体は残しておくことができる。
- トリガーがなければ実行されないため、コストは発生しない。
2. 関数の削除
- 完全に使用しない場合は削除する。
- コードはバージョン管理システム(Git等)で管理しておく。
3. メモリサイズの最適化
- 必要最小限のメモリサイズに設定する。
- ただし、メモリサイズはCPU性能にも影響するため、バランスが重要である。
- パフォーマンステストを行い、最適な値を見つける。
コスト構造について
実行がない場合
- コード保存料金は発生しない。(無料)
- CloudWatch Logsのストレージ料金のみ発生する可能性がある。
- 基本的にコストは0円またはほぼ0円
実行がある場合
- リクエスト数とコンピューティング時間に基づいて課金される。
- 例 : 128MBメモリ、100ミリ秒実行、月10万回の場合
- リクエスト料金 : $0.02
- コンピューティング料金 : $0.021
- 合計 : 約$0.041/月 (約6円/月)
コストを下げる方法
- 実行時間の短縮
- コードの最適化により実行時間を短縮する。
- 不要な処理を削減する。
- メモリの最適化
- 適切なメモリサイズを選択する。
- 大きすぎるメモリは無駄なコストとなる。
- ログの管理
- CloudWatch Logsの保持期間を適切に設定する。
- 不要なログ出力を削減する。
完全に無料にするには、トリガーを無効化して関数を実行させないこと。
Lambda関数の作成
1. マネジメントコンソールでの作成
- AWSマネジメントコンソールにログインする。
- リージョンを選択する。
- 東京リージョン : ap-northeast-1
- 検索バーに "Lambda" と入力して選択する。
- [関数の作成]を選択する。
2. 作成オプション
- 作成方法を選択する。
- 1から作成 (推奨)
- 基本的な関数を自分で作成
- ブループリントの使用
- テンプレートから作成
- コンテナイメージ
- Dockerイメージから作成
- 1から作成 (推奨)
- 関数名を入力する。
- 例 : MyFunction
- ランタイムを選択する。
- 例 : Python 3.12、Node.js 20.x、Java 21 等
- ※注意
- サポートされている最新バージョンを選択することを推奨する。
- アーキテクチャ
- x86_64 または arm64 (Graviton2)
- arm64はコスト効率が良い。
- アクセス権限
- デフォルトの実行ロールを使用
- 基本的なLambda実行権限のみ
- 既存のロールを使用
- 事前に作成したIAMロールを指定
- AWS ポリシーテンプレートから新しいロールを作成
- S3、DynamoDB等へのアクセス権限を持つロールを作成
- デフォルトの実行ロールを使用
- [関数の作成]を選択する。
関数が作成されると、コードエディタが表示される。
Python関数の例
# lambda_function.py
def lambda_handler(event, context):
# eventには入力データが含まれる
# contextには実行環境の情報が含まれる
print("イベント内容:", event)
# 処理の例
name = event.get('name', 'World')
message = f'Hello, {name}!'
# レスポンスの返却
return {
'statusCode': 200,
'body': message
}
関数設定の確認と変更
作成した関数を選択して、以下に示す項目を確認・変更する。
- コードタブ
- 関数コードの編集、テストイベントの作成
- テストタブ
- テストイベントの作成と実行
- 設定タブ
- 一般設定 : タイムアウト(デフォルト3秒、最大15分)、メモリ (128[MB]〜10240[MB])
- 環境変数 : キーと値のペアで設定
- トリガー : イベントソースの追加
- 送信先 : 成功・失敗時の送信先設定
- アクセス権限 : 実行ロールの確認と変更
- モニタータブ
- CloudWatchメトリクス、ログの確認
Linux PCからのアクセス設定
AWS CLIのインストール
方法1 : pip経由 (推奨)
Python3をインストールする。
sudo apt update sudo apt install python3 python3-pip -y
AWS CLIをインストールする。
pip3 install awscli --user
正常にインストールされているかどうかを確認する。
aws --version
方法2 : 公式インストーラ
AWS CLIをダウンロードおよびインストールする。
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install
正常にインストールされているかどうかを確認する。
aws --version
アクセスキーの作成
- AWSマネジメントコンソールで "IAM" を検索する。
- [ユーザ] - 作成したIAMユーザを選択する。
- [セキュリティ認証情報]タブを選択する。
- [アクセスキーを作成]を選択する。
- ユースケース : [コマンドラインインターフェイス (CLI)]を選択する。
- 確認のチェックボックスにチェックを入力する。
- [次へ]を選択する。
- 説明タグを入力する。(オプション)
- 例 : MyLinuxPC
- [アクセスキーを作成]を選択する。
- 重要 : アクセスキーIDとシークレットアクセスキーを控えておく。
- シークレットキーは後で確認できない。
- .csvファイルをダウンロードして安全に保管する。
AWS CLIの設定
設定コマンドを実行する。
aws configure
以下に示すものを順番に入力する。
- AWS Access Key ID
- 作成したアクセスキーID
- AWS Secret Access Key
- シークレットアクセスキー
- Default region name
- 例 : ap-northeast-1 (東京リージョン)
- Default output format
- json (推奨)
設定ファイルの場所は以下の通りである。
- ~/.aws/credentials
- アクセスキー情報
- ~/.aws/config
- リージョンや出力形式
接続テスト
Lambda関数一覧を取得する。
aws lambda list-functions
特定の関数の情報を取得する。
aws lambda get-function --function-name MyFunction
Lambdaの基本操作 (CLI)
関数の呼び出し
# 同期呼び出し(レスポンスを待つ)
aws lambda invoke \
--function-name MyFunction \
--payload '{"name": "太郎"}' \
response.json
# レスポンスの確認
cat response.json
関数の呼び出し (非同期)
# 非同期呼び出し(レスポンスを待たない)
aws lambda invoke \
--function-name MyFunction \
--invocation-type Event \
--payload '{"name": "花子"}' \
response.json
関数コードの更新
# ZIPファイルから更新
# まずコードをZIP化
zip function.zip lambda_function.py
# 関数を更新
aws lambda update-function-code \
--function-name MyFunction \
--zip-file fileb://function.zip
環境変数の設定
# 環境変数の設定
aws lambda update-function-configuration \
--function-name MyFunction \
--environment Variables="{DB_HOST=localhost,DB_PORT=5432}"
タイムアウトとメモリの変更
# タイムアウトを30秒、メモリを512[MB]に設定
aws lambda update-function-configuration \
--function-name MyFunction \
--timeout 30 \
--memory-size 512
ログの確認
# CloudWatch Logsのログストリーム一覧を取得
aws logs describe-log-streams \
--log-group-name /aws/lambda/MyFunction \
--order-by LastEventTime \
--descending \
--max-items 1
# ログイベントの取得
aws logs get-log-events \
--log-group-name /aws/lambda/MyFunction \
--log-stream-name 'ログストリーム名'
関数の削除
# 関数の削除
aws lambda delete-function \
--function-name MyFunction
Python SDK (boto3) の使用
以下の例では、Pythonを使用してAWS Lambdaを操作している。
まず、boto3をインストールする。
pip3 install boto3 --user
# lambda_client_example.py
import boto3
import json
# Lambdaクライアントの作成
lambda_client = boto3.client('lambda', region_name='ap-northeast-1')
# 関数の呼び出し(同期)
def invoke_function():
response = lambda_client.invoke(
FunctionName='MyFunction',
InvocationType='RequestResponse', # 同期呼び出し
Payload=json.dumps({
'name': '山田太郎'
})
)
# レスポンスの取得
response_payload = json.loads(response['Payload'].read())
print("レスポンス:", response_payload)
print("ステータスコード:", response['StatusCode'])
# 関数の呼び出し (非同期)
def invoke_function_async():
response = lambda_client.invoke(
FunctionName='MyFunction',
InvocationType='Event', # 非同期呼び出し
Payload=json.dumps({
'name': '佐藤花子'
})
)
print("非同期呼び出し完了:", response['StatusCode'])
# 関数の一覧取得
def list_functions():
response = lambda_client.list_functions()
for func in response['Functions']:
print(f"関数名: {func['FunctionName']}")
print(f" ランタイム: {func['Runtime']}")
print(f" メモリサイズ: {func['MemorySize']}MB")
print(f" タイムアウト: {func['Timeout']}秒")
print()
# 関数の設定取得
def get_function_config():
response = lambda_client.get_function_configuration(
FunctionName='MyFunction'
)
print("関数設定:")
print(f" メモリサイズ: {response['MemorySize']}MB")
print(f" タイムアウト: {response['Timeout']}秒")
print(f" ランタイム: {response['Runtime']}")
print(f" ハンドラ: {response['Handler']}")
# 環境変数の更新
def update_environment_variables():
response = lambda_client.update_function_configuration(
FunctionName='MyFunction',
Environment={
'Variables': {
'DB_HOST': 'mydb.example.com',
'DB_PORT': '3306',
'DEBUG': 'true'
}
}
)
print("環境変数更新完了")
# メイン処理
if __name__ == '__main__':
invoke_function()
# invoke_function_async()
# list_functions()
# get_function_config()
# update_environment_variables()
# 実行方法 python3 lambda_client_example.py
Lambda関数内でのboto3の使用
Lambda関数内で他のAWSサービスにアクセスする場合の例を以下に示す。
# lambda_function.py (DynamoDBへのアクセス例)
import boto3
import json
from datetime import datetime
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('MyTable')
def lambda_handler(event, context):
try:
# DynamoDBにデータを保存
item = {
'id': event.get('id', '001'),
'timestamp': datetime.now().isoformat(),
'data': event.get('data', {})
}
table.put_item(Item=item)
return {
'statusCode': 200,
'body': json.dumps({
'message': 'データ保存成功',
'item': item
})
}
except Exception as e:
print(f"エラー: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps({
'message': 'エラーが発生しました',
'error': str(e)
})
}
※注意
この関数を実行するには、Lambda実行ロールにDynamoDBへのアクセス権限が必要である。
デバッグ方法
# AWS CLIのデバッグモード
aws lambda invoke --function-name MyFunction --payload '{}' response.json --debug
# Lambda関数内でのログ出力
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info(f"受信したイベント: {event}")
logger.debug(f"コンテキスト情報: {context}")
# 処理...
return {'statusCode': 200}
セキュリティ
実行ロールの設定
Lambda関数が他のAWSサービスにアクセスするには、適切なIAMロールが必要である。
- 基本的な実行ロールのポリシー例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
- DynamoDBアクセスを含むポリシー例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan"
],
"Resource": "arn:aws:dynamodb:ap-northeast-1:*:table/MyTable"
}
]
}
環境変数での機密情報管理
- 機密情報 (APIキー、パスワード等) はコードに直接記述しない。
- 環境変数を使用する。
- より安全性を高めるには AWS Secrets Manager または AWS Systems Manager Parameter Store を使用する。
- Secrets Managerの使用例
import boto3
import json
def get_secret(secret_name):
client = boto3.client('secretsmanager', region_name='ap-northeast-1')
response = client.get_secret_value(SecretId=secret_name)
secret = json.loads(response['SecretString'])
return secret
def lambda_handler(event, context):
# シークレットの取得
db_credentials = get_secret('myapp/database')
db_host = db_credentials['host']
db_password = db_credentials['password']
# データベース接続処理
# ...略
VPCアクセス
Lambda関数をVPC内のリソース (RDS、ElastiCache等) に接続する場合
設定方法
- Lambda関数の設定で VPC を選択する。
- サブネット(プライベートサブネット推奨)を選択する。
- セキュリティグループを選択する。
- 実行ロールに以下の権限を追加する。
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface"
],
"Resource": "*"
}
※注意
- VPC接続により、コールドスタート時間が増加する可能性がある。
- インターネットアクセスが必要な場合は、NATゲートウェイが必要となる。
レイヤーの使用
複数の関数で共通のライブラリや依存関係を共有する場合、Lambdaレイヤーを使用する。
- レイヤーの作成例
# ライブラリのインストール
mkdir python
pip3 install requests -t python/
# ZIPファイルの作成
zip -r my-layer.zip python/
# レイヤーの作成
aws lambda publish-layer-version \
--layer-name my-dependencies \
--zip-file fileb://my-layer.zip \
--compatible-runtimes python3.12
- 関数へのレイヤー追加
aws lambda update-function-configuration \
--function-name MyFunction \
--layers arn:aws:lambda:ap-northeast-1:123456789012:layer:my-dependencies:1
トラブルシューティング
エラー : "Task timed out after X seconds"
- 原因
- 関数の実行がタイムアウト設定を超えた
- 解決方法
- タイムアウト設定を延長する(最大15分)
- コードを最適化して実行時間を短縮する
- 長時間処理の場合は Step Functions の使用を検討する
エラー : "AccessDeniedException"
- 原因
- 実行ロールに必要な権限がない
- 解決方法
- Lambda実行ロールに適切なIAMポリシーをアタッチする
- CloudWatch Logsでエラー詳細を確認する
エラー : "Out of memory"
- 原因
- メモリ設定が不足している
- 解決方法
- メモリサイズを増やす。(128[MB]〜10240[MB])
- メモリリークがないかコードを確認する。
- 大きなファイル処理の場合は、S3 または EFS の使用を検討する。
エラー : "ResourceNotFoundException"
- 原因
- 指定した関数が存在しない、または、リージョンが違う。
- 解決方法
- 関数名とリージョンを確認する。
- 関数が削除されていないか確認する。
コールドスタートの遅延
- 原因
- 関数が初回実行時または長時間未使用後に実行環境の初期化が必要。
- 解決方法
- Provisioned Concurrencyを使用する。(有料)
- メモリサイズを増やす。(CPU性能も向上)
- 依存関係を最小化する。
- Lambda SnapStartを使用する。(Java限定)
VPC接続の問題
- 原因
- VPC設定が正しくない、または、セキュリティグループの設定に問題がある。
- 解決方法
- サブネットにルートテーブルが正しく設定されているか確認する。
- セキュリティグループのインバウンド・アウトバウンドルールを確認する。
- NATゲートウェイまたはVPCエンドポイントの設定を確認する。
デバッグのヒント
- CloudWatch Logsの活用
- print文やlogging.info()でログを出力する。
- ログ保持期間を適切に設定する。
- X-Rayの使用
- 関数の実行トレースを可視化する。
- ボトルネックを特定する。
- ローカルでの試験
- AWS SAM CLIを使用してローカル環境で試験する。
- Dockerを使用して、Lambda実行環境を再現する。