はじめに
個人開発で株価予測システムを作り、日次でデータ取得+推論を実行、月次でモデルを再学習する仕組みを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 から リポジトリの作成を選択
リポジトリ名を入力して作成を押下
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したイメージを確認できます。
--provenance=false はマルチプラットフォームのメタデータを無効化するオプションです。これがないとLambdaで「manifest list」エラーが出ることがあります。
7. Lambda関数の作成(コンソール)
7.1 関数の作成
- Lambda コンソール にアクセス
- 「関数の作成」 をクリック
- 以下を設定:
| 項目 | 値 |
|---|---|
| 関数名 | my-scheduled-task |
| パッケージタイプ | コンテナイメージ |
| コンテナイメージURI | 「イメージを参照」→ リポジトリを選択 → latest を選択 |
| アーキテクチャ | x86_64 |
関数の作成をクリックする
7.2 設定の調整
「設定」タブ → 「一般設定」→ 「編集」
| 項目 | 推奨値 | 説明 |
|---|---|---|
| メモリ | 512 MB〜3008 MB | 処理内容に応じて調整 |
| タイムアウト | 5分〜15分 | 処理時間に応じて調整 |
Lambdaの最大タイムアウトは15分です。それ以上かかる処理はStep FunctionsやECS/Fargateを検討してください。
8. S3アクセス権限の設定
LambdaからS3にアクセスするには、実行ロールに権限を付与する必要があります。
8.1 実行ロールの確認
Lambda コンソール → 関数 → 設定 → アクセス権限
「ロール名」のリンクをクリックしてIAMコンソールを開きます。
8.2 インラインポリシーの追加
- 「許可を追加」→「インラインポリシーを作成」
- 「JSON」 タブを選択
- 以下を貼り付け:
{
"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/*"
]
}
]
}
次へを選択
ポリシー名を記入してポリシーの作成を押下
9. テスト実行
9.1 コンソールからテスト
- Lambda コンソール → 関数 → 「テスト」タブ
- イベント名:
test - イベントJSON:
{} - 「テスト」 をクリック
成功すると以下のようなログが表示されます:
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 トリガーの追加
- Lambda コンソール → 関数 → 「設定」→「トリガー」
- 「トリガーを追加」
- ソース: EventBridge (CloudWatch Events)
- ルール: 新しいルールを作成
- ルール名を記入
- スケジュール式を入力
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日ごと
成功すると以下のようにコンソール上に表示されます
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からイメージ取得
様々な定期実行タスクに応用できると思います。ぜひ活用してみてください。








