1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS Lambda + ECR + EventBridge で Python の定期実行スクリプトを構築する

Last updated at Posted at 2025-12-26

はじめに

個人開発で株価予測システムを作り、日次でデータ取得+推論を実行、月次でモデルを再学習する仕組みをAWS上に構築しました。

本記事では、そのデプロイ経験をもとに 「ECRコンテナイメージを使ったLambda関数を定期実行する」 汎用的な方法を解説します。

なお、Linux環境(WSL2)での実行です。MacOSでは操作が異なる可能性があります。

この記事で作るもの

EventBridge (cron) → Lambda (コンテナ) → S3 (入出力)
  • EventBridge: 指定時刻にLambdaを起動
  • Lambda: Dockerコンテナとしてスクリプトを実行
  • S3: データの読み書き
  • ECR: Dockerイメージの保管

なぜコンテナ版Lambdaを使うのか

方式 メリット デメリット
ZIP形式 デプロイが簡単 250MBの制限、依存関係管理が面倒
コンテナ形式 10GBまで対応、ローカルと同じ環境 ECRの設定が必要

NumPy、Pandas、PyTorchなどの重いライブラリを使う場合は、コンテナ形式一択です。


1. 前提条件

  • AWSアカウント
  • AWS CLI設定済み (aws configure)
  • Docker インストール済み
# AWS CLIの確認
aws --version
aws sts get-caller-identity

# Dockerの確認
docker --version

2. プロジェクト構成

以下のような構成で進めます。

my-project/
├── src/
│   └── main.py           # 実行するスクリプト
├── docker/
│   ├── Dockerfile
│   └── requirements.txt
└── handler.py            # Lambdaエントリーポイント

3. スクリプトの作成

src/main.py

実行したい処理を書きます。

import json
import boto3
from datetime import datetime

def run():
    """メイン処理"""
    print("Processing started...")

    # S3からデータを読み込む例
    s3 = boto3.client('s3')
    bucket = "my-bucket"

    # 何らかの処理
    result = {
        "timestamp": datetime.now().isoformat(),
        "status": "success",
        "message": "Hello from Lambda!"
    }

    # S3に結果を保存
    s3.put_object(
        Bucket=bucket,
        Key=f"output/{datetime.now().strftime('%Y-%m-%d')}.json",
        Body=json.dumps(result, ensure_ascii=False, indent=2),
        ContentType="application/json"
    )

    print("Processing completed!")
    return result

handler.py

Lambdaのエントリーポイントです。

import json
import sys
import traceback

# srcディレクトリをパスに追加
sys.path.insert(0, "/var/task/src")

def lambda_handler(event, context):
    """Lambda エントリーポイント"""
    print("Lambda handler started")

    try:
        from main import run
        result = run()

        return {
            "statusCode": 200,
            "body": json.dumps(result)
        }

    except Exception as e:
        error_msg = f"{type(e).__name__}: {str(e)}"
        tb = traceback.format_exc()
        print(f"Error: {error_msg}")
        print(f"Traceback:\n{tb}")

        return {
            "statusCode": 500,
            "body": json.dumps({
                "error": error_msg,
                "traceback": tb[-2000:]  # 長すぎる場合は末尾のみ
            })
        }

4. Dockerfileの作成

docker/Dockerfile

LAMBDA_TASK_ROOTとは: Lambdaコンテナ内の作業ディレクトリ(/var/task)
ベースイメージは、public.ecr.aws/lambda/pythonを選択。

# AWS Lambda Python 3.11 ベースイメージ
FROM public.ecr.aws/lambda/python:3.11

# 依存ライブラリのインストール
COPY docker/requirements.txt ${LAMBDA_TASK_ROOT}/
RUN pip install --no-cache-dir -r ${LAMBDA_TASK_ROOT}/requirements.txt

# ソースコードのコピー
COPY src/ ${LAMBDA_TASK_ROOT}/src/
COPY handler.py ${LAMBDA_TASK_ROOT}/

# Lambdaハンドラーを指定
CMD ["handler.lambda_handler"]

docker/requirements.txt

boto3>=1.34.0
pandas>=2.0.0
numpy>=1.24.0

5. ECRリポジトリの作成

今回はコンソールから操作する場合を解説します。

Amazon ECR から リポジトリの作成を選択

スクリーンショット 2025-12-26 135814.png

リポジトリ名を入力して作成を押下


6. Dockerイメージのビルド・プッシュ

# 変数設定(自分の環境に合わせて変更)
ACCOUNT_ID=123456789012
REGION=ap-northeast-1
REPO_NAME=my-scheduled-task

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

# イメージをビルド
docker build --provenance=false \
  -t $REPO_NAME:latest \
  -f docker/Dockerfile .

# タグ付け
docker tag $REPO_NAME:latest \
  $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:latest

# プッシュ
docker push $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:latest

コンソール上で、先ほど作成したリポジトリからpushしたイメージを確認できます。

スクリーンショット 2025-12-26 141113.png

--provenance=false はマルチプラットフォームのメタデータを無効化するオプションです。これがないとLambdaで「manifest list」エラーが出ることがあります。


7. Lambda関数の作成(コンソール)

7.1 関数の作成

  1. Lambda コンソール にアクセス
  2. 「関数の作成」 をクリック
  3. 以下を設定:
項目
関数名 my-scheduled-task
パッケージタイプ コンテナイメージ
コンテナイメージURI 「イメージを参照」→ リポジトリを選択 → latest を選択
アーキテクチャ x86_64

スクリーンショット 2025-12-26 141426.png

関数の作成をクリックする

7.2 設定の調整

「設定」タブ → 「一般設定」→ 「編集」

項目 推奨値 説明
メモリ 512 MB〜3008 MB 処理内容に応じて調整
タイムアウト 5分〜15分 処理時間に応じて調整

Lambdaの最大タイムアウトは15分です。それ以上かかる処理はStep FunctionsやECS/Fargateを検討してください。


8. S3アクセス権限の設定

LambdaからS3にアクセスするには、実行ロールに権限を付与する必要があります。

8.1 実行ロールの確認

Lambda コンソール → 関数 → 設定 → アクセス権限

「ロール名」のリンクをクリックしてIAMコンソールを開きます。

スクリーンショット 2025-12-26 141840.png

8.2 インラインポリシーの追加

  1. 「許可を追加」→「インラインポリシーを作成」

33c62ae6-dd0a-439f-8ccc-e06706d03c88.png

  1. 「JSON」 タブを選択
  2. 以下を貼り付け:
{
    "Version": "2012-10-17",
    "Statement": [
        {
			"Sid": "Statement1",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket",
                "arn:aws:s3:::my-bucket/*"
            ]
        }
    ]
}

スクリーンショット 2025-12-26 143116.png

次へを選択

スクリーンショット 2025-12-26 143242.png

ポリシー名を記入してポリシーの作成を押下


9. テスト実行

9.1 コンソールからテスト

  1. Lambda コンソール → 関数 → 「テスト」タブ
  2. イベント名: test
  3. イベントJSON: {}
  4. 「テスト」 をクリック

スクリーンショット 2025-12-26 143331.png

成功すると以下のようなログが表示されます:

START RequestId: xxx
Lambda handler started
Processing started...
Processing completed!
END RequestId: xxx
REPORT RequestId: xxx Duration: 1234.56 ms ...

9.2 S3で結果を確認

aws s3 ls s3://my-bucket/output/

10. EventBridgeで定期実行を設定

10.1 トリガーの追加

  1. Lambda コンソール → 関数 → 「設定」→「トリガー」
  2. 「トリガーを追加」
  3. ソース: EventBridge (CloudWatch Events)
  4. ルール: 新しいルールを作成
  5. ルール名を記入
  6. スケジュール式を入力

10.2 スケジュール式の書き方

cron式

cron(分 時 日 月 曜日 年)
説明
cron(0 9 * * ? *) 毎日 9:00 UTC
cron(0 0 * * ? *) 毎日 0:00 UTC (= 9:00 JST)
cron(0 14 ? * MON-FRI *) 平日 14:00 UTC (= 23:00 JST)
cron(0 0 1 * ? *) 毎月1日 0:00 UTC (= 9:00 JST)

EventBridgeのcronはUTC基準です!

JST → UTC の変換: JST - 9時間 = UTC

例: JST 23:00 に実行したい → UTC 14:00 → cron(0 14 ...)

rate式(シンプルな間隔指定)

rate(1 hour)    # 1時間ごと
rate(6 hours)   # 6時間ごと
rate(1 day)     # 1日ごと

成功すると以下のようにコンソール上に表示されます

スクリーンショット 2025-12-26 143514.png


11. コード更新時のデプロイ手順

コードを修正した場合は、以下の手順で再デプロイします。

# 1. イメージを再ビルド
docker build --provenance=false \
  -t $REPO_NAME:latest \
  -f docker/Dockerfile .

# 2. タグ付け
docker tag $REPO_NAME:latest \
  $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:latest

# 3. プッシュ
docker push $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:latest

# 4. Lambda関数を更新
aws lambda update-function-code \
  --function-name my-scheduled-task \
  --image-uri $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:latest

コンソール上で反映させたい場合は、Lambda コンソールで 「新しいイメージをデプロイ」 をクリックします。


12. 料金について

Lambda

項目 無料枠
リクエスト数 100万リクエスト/月
実行時間 40万GB-秒/月

計算例:

  • メモリ1024MB、実行時間2分のLambdaを毎日実行
  • 1 GB × 120秒 × 30日 = 3,600 GB-秒/月
  • 無料枠 40万GB-秒の約1%

ほぼ無料で運用可能

ECR

項目 料金
ストレージ $0.10/GB/月

500MBのイメージなら月額約$0.05(約7円)

S3

項目 料金
ストレージ $0.025/GB/月
リクエスト $0.0047/1000リクエスト

小規模なデータなら月額数円程度


13. トラブルシューティング

エラー: Repository does not exist

name unknown: The repository with name 'xxx' does not exist

原因: ECRリポジトリが存在しない、またはリージョンが違う

対処:

aws ecr describe-repositories --region ap-northeast-1

エラー: Access Denied (S3)

An error occurred (403) when calling the GetObject operation: Access Denied

原因: Lambda実行ロールにS3権限がない

対処: 手順8のIAMポリシーを確認

エラー: Task timed out

Task timed out after X seconds

原因: タイムアウト設定が短い

対処: Lambda設定でタイムアウトを延長(最大15分)

エラー: manifest list (ECRプッシュ時)

image manifest unknown

原因: マルチプラットフォームビルドの問題

対処: --provenance=false オプションを追加

docker build --provenance=false -t xxx .

まとめ

本記事では、ECRコンテナイメージを使ったLambda関数を定期実行する方法を解説しました。

構成のおさらい

EventBridge (cron) → Lambda (コンテナ) → S3 (入出力)
        ↑                    ↑
   定期トリガー          ECRからイメージ取得

様々な定期実行タスクに応用できると思います。ぜひ活用してみてください。


参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?