「サーバーを持たずにコードを動かす」AWS Lambda を、Python と boto3 で触ってみるための実践ガイドです。未経験〜駆け出しの方向けに、最小のハンドラから、S3トリガー・定期実行・通知・簡易APIまで、コピペできる断片と一緒にユースケース別で整理しました。使う・使わないの判断と、事故らないコツも添えます。

01Lambda の考え方 — イベント駆動と「使う/使わない」

AWS Lambda は「サーバーを用意せずに、イベントが起きたときだけコードを動かす」しくみです。誰かが S3 にファイルを置いた、決まった時刻になった、API にリクエストが来た――そうしたイベントをきっかけに関数が起動し、処理が終われば止まります。常駐サーバの起動・パッチ当て・スケーリングを自分で抱えなくてよいのが最大の利点です。

イベント源 S3 アップロード EventBridge Scheduler API Gateway SNS / SQS AWS Lambda handler(event, context) boto3 で操作 S3 put / get_object DynamoDB put / get_item SNS publish / SQS Secrets Manager 発火 実行ロール
図:イベント源が Lambda を起動し、Lambda が boto3 で各サービスを操作する。これがイベント駆動の基本形。

向いているのは、次のような「イベント駆動で、上限時間内に終わる」処理です。逆に、常時稼働が要る・1回が長時間・低レイテンシが命、という処理は別の選択肢が向きます。

料金は「呼ばれた回数」と「実行時間×メモリ」に応じた従量課金です。使わなければ基本的に費用は発生しません。裏を返すと、無限ループや過剰なリトライは「動いた分だけ」コストと時間を食うので、暴走しない設計が大切です(具体的な単価は変わるため、最新は公式の料金ページで確認してください)。

OS やネットワークの基礎に不安があれば クラウドエンジニアの教科書(TCP/IP) も合わせてどうぞ。なお、常時起動が必要なプロセスは Lambda ではなく systemd で常駐サービス化するほうが向く場面もあります(サーバーレスとの対比として押さえておくと判断が速くなります)。

現場のコツ:「Lambda で全部やる」を目指さないこと。イベントに反応する薄い処理を Lambda に、重い常駐処理は別基盤に、と役割を分けると事故が減ります。

02最小の Lambda — handler・ログ・環境変数・タイムアウト

Lambda 関数の入り口はハンドラ関数です。Python では def lambda_handler(event, context): の形が基本で、Lambda が呼び出すたびにこの関数が実行されます。event は呼び出し元から渡るデータ(dict)、context は実行に関する情報(残り時間など)です。

import os
import json
import logging

# ハンドラの「外」で初期化しておくと、実行環境が再利用された2回目以降が速い
logger = logging.getLogger()
logger.setLevel("INFO")             # print でもログは出るが、レベル管理できる logger を推奨
TABLE_NAME = os.environ.get("TABLE_NAME")   # 環境変数は os.environ で読む

def lambda_handler(event, context):
    # context から実行の残り時間(ミリ秒)などが取れる
    logger.info(f"start: remaining_ms={context.get_remaining_time_in_millis()}")
    name = event.get("name", "world")
    return {"message": f"hello, {name}"}

ハンドラ名は「ファイル名.関数名」で指定します。上のコードを lambda_function.py に置いたなら、ハンドラは lambda_function.lambda_handler です(コンソール既定値と同じ)。

現場のコツ:重い初期化(SDK クライアント生成やDB接続の準備)はハンドラの外に書くこと。実行環境が再利用されると初期化がスキップされ、コールドスタートの影響を減らせます。

03boto3 の基本 — client と resource・認証・最小権限

boto3 は AWS を Python から操作する SDK です。呼び出し方には client(低レベル)と resource(高レベル)の2種類があります。

import boto3

# client: 低レベル。ほぼ全 API をカバーし、新機能もここに入る(基本はこちら推奨)
s3 = boto3.client("s3")
resp = s3.list_buckets()

# resource: 高レベルで書きやすいが、機能追加が凍結されている
#   → 既存コードは動くが、新しい機能は client 側にしか来ないことがある
ddb = boto3.resource("dynamodb")
table = ddb.Table("my-table")

# 認証情報はコードに書かない。Lambda は「実行ロール」の一時認証情報を
#   boto3 が自動的に使う。リージョンも環境変数 AWS_REGION から自動で入る

迷ったら client を選んでおくと無難です。resource インターフェースは機能フリーズ(新機能の追加なし。廃止ではない)の状態で、AWS 側も新規コードは client を推奨しています。

認証は実行ロール(IAM ロール)に任せます。Lambda に割り当てたロールの権限だけで boto3 が動くので、そのロールに「本当に必要な操作だけ」を与えるのが最小権限の考え方です。同じ操作を手元から試したいときは AWS CLI 実践リファレンス が対応します。

現場のコツ:最初から広い権限(*)を付けない。まず動かしたい1〜2の操作だけ許可し、AccessDenied が出たら足りない権限を1つずつ足す、という順番だと過剰権限を防げます。

04UC:S3 トリガー — アップロードで発火して処理する

S3 にファイルが置かれたら Lambda を起動する、という定番の連携です。イベントは event["Records"] の配列で届き、そこからバケット名とオブジェクトキーを取り出します。

import urllib.parse
import boto3

s3 = boto3.client("s3")

def lambda_handler(event, context):
    for record in event["Records"]:
        bucket = record["s3"]["bucket"]["name"]
        # キーは URL エンコードされている(スペースや日本語) → 必ずデコードする
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])

        head = s3.head_object(Bucket=bucket, Key=key)
        print(f"uploaded: {bucket}/{key} size={head['ContentLength']}")
        # ここで変換・検証・別バケットへコピーなどの処理を行う

    return {"statusCode": 200}
現場のコツ:大きなファイルを丸ごとメモリに読まない。必要な範囲だけ読む、ストリームで処理する、重い変換は Glue など別基盤に回す、と割り切ると Lambda の上限に引っかかりにくくなります。

05UC:定期実行 — EventBridge Scheduler で日次バッチ

「毎日 0 時に集計する」のような定期実行は、EventBridge Scheduler から Lambda を呼ぶのが基本形です。Scheduler は rate()(間隔)、cron()(時刻指定)、at()(1回だけ)の3種類のスケジュールに対応します。

Lambda 側は、いつも通りのハンドラを書くだけです。起動タイミングは Scheduler が担当します。

# 日次バッチ用のハンドラ。中身は普通の関数。起動は Scheduler 側が受け持つ
def lambda_handler(event, context):
    # event には Scheduler で設定した任意のペイロードが入る(自分で定義できる)
    target_date = event.get("date", "today")
    # ここに集計・レポート生成・掃除などの処理を書く
    return {"status": "done", "target": target_date}

スケジュールの指定はコードではなく式で書きます。代表例は次のとおりです。

rate(1 day)            # 1日ごと
rate(5 minutes)        # 5分ごと
cron(0 15 * * ? *)     # 毎日 15:00 に実行(フィールドは 分 時 日 月 曜日 年)
現場のコツ:定期バッチは「二重起動しても壊れない」ように作るのが安全です(べき等性は08で後述)。再実行や遅延起動が起きても結果が壊れなければ、運用がぐっと楽になります。

06UC:通知 — SNS / Slack Webhook / CloudWatch アラーム

処理の完了や失敗を知らせる通知も Lambda の定番です。AWS 内へファンアウトするなら SNS publish、Slack へ直接送るなら Incoming Webhook に標準ライブラリの urllib で POST します(追加ライブラリの同梱が不要なのが利点)。

import os
import json
import urllib.request
import boto3

sns = boto3.client("sns")

def lambda_handler(event, context):
    msg = "日次バッチが完了しました"

    # (1) SNS へ publish(メール/SMS/他サービスへファンアウトできる)
    sns.publish(TopicArn=os.environ["TOPIC_ARN"], Subject="通知", Message=msg)

    # (2) Slack Incoming Webhook へ POST(Webhook URL は環境変数や Secrets で)
    body = json.dumps({"text": msg}).encode("utf-8")
    req = urllib.request.Request(
        os.environ["SLACK_WEBHOOK_URL"],
        data=body,
        headers={"Content-Type": "application/json"},
    )
    with urllib.request.urlopen(req, timeout=5) as res:
        print("slack status:", res.status)

    return {"statusCode": 200}

監視と組み合わせるなら、CloudWatch アラーム → SNS トピック → (メール or Lambda)という連携がよく使われます。メトリクスがしきい値を超えたらアラームが SNS に通知し、SNS が担当者へメールしたり、整形用の Lambda を起動して Slack に流したりできます。

ログの設定・監視の第一歩は CloudWatch Agent×Logs 設定ガイド にまとめています。

07UC:簡易 ETL/API — DynamoDB と API Gateway

DynamoDB への読み書きと、API Gateway 経由の軽い API を組み合わせると、小さな Web API がすぐ作れます。client の DynamoDB は型付きの値S=文字列、N=数値)で受け渡すのが特徴です。

import json
import boto3

ddb = boto3.client("dynamodb")
TABLE = "visits"

def lambda_handler(event, context):
    # API Gateway(プロキシ統合)からの呼び出しを想定
    path_id = (event.get("pathParameters") or {}).get("id", "unknown")

    # 書き込み: 値は型付きで渡す(S=文字列, N=数値 ...)
    ddb.put_item(TableName=TABLE, Item={"id": {"S": path_id}})

    # 読み出し: 見つからなければ "Item" キー自体が無い
    got = ddb.get_item(TableName=TABLE, Key={"id": {"S": path_id}})
    item = got.get("Item")

    # プロキシ統合のレスポンスは statusCode / headers / body(文字列) の形
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps({"id": path_id, "found": item is not None}),
    }
現場のコツ:API を公開するなら、認証(API キーや Cognito/JWT)と入力チェックを最初から入れること。「動くこと」と「安全に公開できること」は別物です。

08現場のコツ — べき等性・リトライ・秘密・監視・IaC

小さく作った Lambda を「本番で安心して回す」ために、最低限おさえたい勘所です。

Secrets Manager から秘密を取り出す小さな例です(取得結果は JSON 文字列のことが多い)。

import json
import boto3

sm = boto3.client("secretsmanager")

def get_secret(name):
    resp = sm.get_secret_value(SecretId=name)
    return json.loads(resp["SecretString"])   # {"user": "...", "password": "..."} など
未経験からでも、こうした「小さく作って本番で運用する」経験は確実に力になります。EMW で一緒に取り組みたい方は 採用情報・カジュアル面談はこちら からどうぞ。
現場のコツ:「まず動かす」段階と「本番で運用する」段階を分けて考えること。最初の動作確認は最小権限+手動テストで、公開前にべき等性・リトライ・監視・秘密管理を1つずつ足すと堅くなります。

09早見表 — よく使う boto3 スニペット逆引き&トリガー一覧

「やりたいこと」から boto3(client)のスニペットを引ける早見表です。まずはコピペして動かし、細部は公式リファレンスで確認してください。

やりたいことboto3 スニペット(client)ひとこと
S3 に保存s3.put_object(Bucket=b, Key=k, Body=data)Body は bytes か str
S3 から取得s3.get_object(Bucket=b, Key=k)["Body"].read()Body はストリーム
S3 一覧s3.list_objects_v2(Bucket=b, Prefix=p)v2 を使う。件数多いとページング
署名付き URLs3.generate_presigned_url("get_object", Params=...)期限付きで一時配布
DynamoDB 書込ddb.put_item(TableName=t, Item={"id":{"S":v}})値は型付き(S/N)
DynamoDB 取得ddb.get_item(TableName=t, Key={"id":{"S":v}})無ければ Item キー無し
SNS 通知sns.publish(TopicArn=a, Message=m)複数宛先へファンアウト
SQS 送信sqs.send_message(QueueUrl=u, MessageBody=m)非同期の緩衝に
秘密取得sm.get_secret_value(SecretId=n)["SecretString"]中身は JSON が多い

主なトリガーと、event から取り出すデータの入り口です。

トリガー発火のきっかけevent の主な中身
S3オブジェクト作成/削除Records[].s3.bucket / object.key
EventBridge Schedulercron / rate / 1回任意のペイロード(自分で定義)
API Gateway(proxy)HTTP リクエストhttpMethod, path, body, pathParameters
SNSトピックへ publishRecords[].Sns.Message
SQSキューにメッセージRecords[].body(バッチで届く)
DynamoDB Streams項目の変更Records[].dynamodb.NewImage
シリーズ内の関連記事:AWS CLI 実践リファレンスAWS Glue×PySpark 入門CloudWatch Agent×Logs 設定ガイド

10よくある質問(FAQ)

Lambda はどんなときに「使わない」ほうがいいですか?

常時稼働させたい処理、1回の実行が15分を超える長時間バッチ、大きなメモリを常駐させ続けたい処理、そして数ミリ秒単位の低レイテンシが要る処理は、EC2 や ECS/Fargate のほうが向く場面が多いです。Lambda はイベントが来たときだけ起動し、上限時間内で完了する処理に向きます。逆に「たまにしか呼ばれない」「イベントに反応させたい」処理は、常駐サーバを持たずに済む Lambda が有利です。

アクセスキーはコードに書く必要がありますか?

書きません。Lambda 関数には実行ロール(IAM ロール)を割り当て、boto3 はその一時認証情報を自動的に使います。ローカルの長期アクセスキーをコードや環境変数に埋め込むのは避けてください。DB のパスワードや外部サービスのトークンなどの秘密は Secrets Manager や SSM パラメータストアに置き、実行時に取得します。秘密はソースやリポジトリにコミットしないのが大原則です。

ランタイム(Python の版)はどれを選べばいいですか?

2026年時点では Amazon Linux 2023 ベースの python3.12 / python3.13 / python3.14 がサポート中です。python3.10・python3.11 は Amazon Linux 2 上で非推奨(deprecation)に向かっているため、新規はサポート中の版から選びます。どの版もいずれは非推奨になるので、「更新できる状態を保つ」前提で運用するのが現実的です。最新の対応表は AWS 公式ドキュメントで確認してください。

ローカルで動いたコードが Lambda では落ちます。何を疑えばいい?

よくある原因は、(1) 依存ライブラリの同梱漏れ(Layer もしくはコンテナイメージ化が必要)、(2) 実行ロールの権限不足(AccessDenied)、(3) 書き込みは /tmp 以外は不可、(4) タイムアウトやメモリ不足、(5) 環境変数の設定漏れ、あたりです。まずは CloudWatch Logs に出るエラーメッセージとスタックトレースを読むのが近道です。

EMWは札幌を拠点にAWSの設計・運用を支援しています。Lambdaを含むサーバーレス構成の設計や、既存バッチのイベント駆動化を検討中の方は、お気軽にご相談ください。基礎から積み上げたい方の採用・カジュアル面談も歓迎です。

相談する
← ブログ一覧へ戻る