AWS_Lambdaを使って日次ジョブを仕込んでみる
Categories:
やること
OCIの課金情報をメールに送付するスクリプトを作成したのでAWSのサーバレス環境でジョブ化してみる
主に2つのサービスを使う
- AWS Lambda: サーバーレス実行環境
- AWS EventBride Schedule: ジョブスケジューラ
AWS Lambda
この辺にあったLambda
Create a funcation
3パターンある。Use a blueprintってのはテンプレから作成するやつ。見てみたけど他のAWSサービスと連携する用みたいなのがいろいろ。
今回はAuthor from scratchで作ってPython用のコードをアップロードすることにする。
この辺にアップロード用のzip作成手順が載ってる
https://docs.aws.amazon.com/lambda/latest/dg/python-package.html
https://docs.aws.amazon.com/lambda/latest/dg/python-handler.html
とりあえず側だけ(サンプルコード付き)作って、あとからコードアップロードするっぽい
資材の準備
スクリプトはPyCharmで書いてるので、
PyCharm
Tools > Sync Pythons requirements で requirements.txtを生成
依存ライブラリもろもろカレントに詰め込んでzipに固めてアップロードすればいいらしい
依存ライブラリの取得はスクリプトに包んだ
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ cat ../build_lambda_fun.sh
#!/usr/bin/env bash
set -euo pipefail
PROJECT_ROOT=$(pwd)
BUILD_DIR="${PROJECT_ROOT}/build"
rm -rf "$BUILD_DIR" && mkdir -p "$BUILD_DIR"
# 依存を確定
#uv lock
#uv export --frozen --no-dev -o requirements.txt
docker run --rm \
--entrypoint /bin/bash \
-e PIP_DEFAULT_TIMEOUT=1200 \
-v "${PROJECT_ROOT}":/var/task \
-w /var/task \
public.ecr.aws/lambda/python:3.13 \
-eu -c '
PM=dnf; command -v yum >/dev/null && PM=yum
$PM -y install gcc python3-devel || echo "skip gcc"
python -m pip install --upgrade pip
python -m pip install --only-binary=:all: \
-r requirements.txt \
--target build/python \
--progress-bar off
'
# entrypointがない 開発・ビルド専用イメージ public.ecr.aws/sam/build-python3.13 もあるらしい
sudo chown -R "$(id -u):$(id -g)" "$BUILD_DIR"
echo "依存ライブラリを build/python に展開しました"
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
実行する
# ディレクトリ作る
mkdir ~/lambda_build/multicloud_billing_report
cd ~/lambda_build/multicloud_billing_report
# 作成したソースコード類を配置する
→scp 等で配置
# 依存ライブラリをダウンロードしてzipにまとめる
bash ../build_lambda_fun.sh
cd build/python
zip -r ../lambda-package.zip .
# ソースコード類もzipにまとめる
cd ../..
zip -g build/lambda-package.zip *.py config oci_api_key.pem
資材アップロード
Lambdaのファンクション詳細画面からUpload
→失敗した
どうやらzipサイズは50MB以下である必要があるらしい。
S3を経由すればいけるらしいけど、そもそも解凍後250MB以下である必要があるらしく全然ダメだった。
docker@ubuntu24:~/lambda_build/multicloud_billing_report/build$ du -sm ./*
123 ./lambda-package.zip
550 ./python
docker@ubuntu24:~/lambda_build/multicloud_billing_report/build$
ociがデカすぎる
docker@ubuntu24:~/lambda_build/multicloud_billing_report/build/python$ du -sm ./* | sort -n
1 ./bin
1 ./certifi
1 ./certifi-2025.4.26.dist-info
1 ./cffi
1 ./cffi-1.17.1.dist-info
1 ./circuitbreaker-2.1.3.dist-info
1 ./circuitbreaker.py
1 ./cryptography-44.0.3.dist-info
1 ./dateutil
1 ./dotenv
1 ./dotenv-0.9.9.dist-info
1 ./numpy-2.3.0.dist-info
1 ./OpenSSL
1 ./pandas-2.2.3.dist-info
1 ./__pycache__
1 ./pycparser-2.22.dist-info
1 ./pyOpenSSL-24.3.0.dist-info
1 ./python_dateutil-2.9.0.post0.dist-info
1 ./python_dotenv-1.1.0.dist-info
1 ./pytz-2025.2.dist-info
1 ./rust
1 ./six-1.17.0.dist-info
1 ./six.py
1 ./tzdata-2025.2.dist-info
2 ./_cffi_backend.cpython-313-x86_64-linux-gnu.so
2 ./pycparser
3 ./oci-2.153.0.dist-info
3 ./pytz
3 ./tzdata
13 ./cryptography
27 ./numpy.libs
43 ./numpy
75 ./pandas
379 ./oci
docker@ubuntu24:~/lambda_build/multicloud_billing_report/build/python$
コンテナイメージを使う方法に変更
コンテナイメージで実施
https://docs.aws.amazon.com/lambda/latest/dg/python-image.html
テンプレに沿ってDockerfileを作る
${LAMBDA_TASK_ROOT} →/var/taskらしい。
スクリプトからファイルの読みこむ場合はちょっと工夫しないといけないっぽい。
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ cat Dockerfile
FROM public.ecr.aws/lambda/python:3.13
# Copy requirements.txt
COPY requirements.txt ${LAMBDA_TASK_ROOT}
# Install the specified packages
RUN pip install -r requirements.txt
# Copy function code
COPY *.py ${LAMBDA_TASK_ROOT}
COPY config ${LAMBDA_TASK_ROOT}
COPY *pem ${LAMBDA_TASK_ROOT}
# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "lambda_function.handler" ]
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
ビルド
※キャッシュを利用しないでベースイメージも最新から引っ張ってくるコマンド:docker buildx build --no-cache --pull --platform linux/amd64 --provenance=false -t multicloud_billing_report:latest .
→キャッシュでハマったことがあるので俺みたいなDocker初心者はキャッシュをバイパスする用にしたほうがいいかも。その分ビルドに時間がかかるのだが。
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ docker buildx build --platform linux/amd64 --provenance=false -t multicloud_billing_report:latest .
[+] Building 0.4s (12/12) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 579B 0.0s
=> [internal] load metadata for public.ecr.aws/lambda/python:3.13 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/7] FROM public.ecr.aws/lambda/python:3.13 0.0s
=> [internal] load build context 0.2s
=> => transferring context: 315B 0.2s
=> CACHED [2/7] COPY requirements.txt /var/task 0.0s
=> CACHED [3/7] RUN pip install -r requirements.txt 0.0s
=> CACHED [4/7] COPY *.py /var/task 0.0s
=> CACHED [5/7] COPY .env /var/task 0.0s
=> CACHED [6/7] COPY config /var/task 0.0s
=> CACHED [7/7] COPY *pem /var/task 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:6f04cd85c01547f2a0ade8e81a8d6b7911f5b34f61cd638adcdb29716835c03a 0.0s
=> => naming to docker.io/library/multicloud_billing_report:latest 0.0s
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
ビルドが出来たらお試しにローカルで実行
→Ctrl+Cで止めるまでプロンプト戻ってこない
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ docker run --platform linux/amd64 -p 9000:8080 multicloud_billing_report:latest
14 Jun 2025 09:21:24,483 [INFO] (rapid) exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)
別termからcurlで確認
→テンプレに沿うとこれでキックできる
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
{"status": "OK"}
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
標準出力はdocker runを流したtermで出力される
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ docker run --platform linux/amd64 -p 9000:8080 multicloud_billing_report:latest
14 Jun 2025 10:55:19,462 [INFO] (rapid) exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)
START RequestId: 43c245bc-8842-4b02-b307-dc2f5075d283 Version: $LATEST
14 Jun 2025 10:55:29,172 [INFO] (rapid) INIT START(type: on-demand, phase: init)
14 Jun 2025 10:55:29,172 [INFO] (rapid) The extension's directory "/opt/extensions" does not exist, assuming no extensions to be loaded.
14 Jun 2025 10:55:29,172 [INFO] (rapid) Starting runtime without AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN , Expected?: false
14 Jun 2025 10:55:29,899 [INFO] (rapid) INIT RTDONE(status: success)
14 Jun 2025 10:55:29,900 [INFO] (rapid) INIT REPORT(durationMs: 727.773000)
14 Jun 2025 10:55:29,900 [INFO] (rapid) INVOKE START(requestId: 2ce5b621-9824-4b31-819b-cec31ca29ce8)
raw event: {}
request id: 2ce5b621-9824-4b31-819b-cec31ca29ce8
remaining ms: 299271
date | cost(小数点以下繰り上げ) | currency
2025-06-01 | 140 | JPY
2025-06-02 | 66 | JPY
2025-06-03 | 78 | JPY
2025-06-04 | 55 | JPY
2025-06-05 | 55 | JPY
2025-06-06 | 43 | JPY
2025-06-07 | 43 | JPY
2025-06-08 | 39 | JPY
2025-06-09 | 37 | JPY
2025-06-10 | 13 | JPY
2025-06-11 | 13 | JPY
2025-06-12 | 25 | JPY
2025-06-13 | 18 | JPY
2025-06-14 | 4 | JPY
=======================================
sum | 629 | JPY
END RequestId: 2ce5b621-9824-4b31-819b-cec31ca29ce8
REPORT RequestId: 2ce5b621-9824-4b31-819b-cec31ca29ce8 Init Duration: 0.04 ms Duration: 3277.68 ms Billed Duration: 3278 ms Memory Size: 3008 MB Max Memory Used: 3008 MB
14 Jun 2025 10:55:32,449 [INFO] (rapid) INVOKE RTDONE(status: success, produced bytes: 0, duration: 2548.942000ms)
Ctrl+Cで止める
メモ
デバッグ用
→通常イメージだとコンテナにログインできないがデバッグ用に用意されているイメージを使うとコンテナにログインできる
# Dockerfile
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ cat Dockerfile
#FROM public.ecr.aws/lambda/python:3.13
FROM public.ecr.aws/sam/build-python3.13 AS dev
# Copy requirements.txt
COPY requirements.txt ${LAMBDA_TASK_ROOT}
# Install the specified packages
RUN pip install -r requirements.txt
# Copy function code
COPY *.py ${LAMBDA_TASK_ROOT}
COPY .env ${LAMBDA_TASK_ROOT}
COPY config ${LAMBDA_TASK_ROOT}
COPY *pem ${LAMBDA_TASK_ROOT}
# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
#CMD [ "lambda_function.handler" ]
CMD ["python"]
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
# ビルド
docker buildx build --platform linux/amd64 --provenance=false -t multicloud_billing_report:test .
# 実行&コンテナログイン
docker run --rm -it multicloud_billing_report:test /bin/bash
Amazon ECR にプッシュ
AWSのコンテナレジストリ
この辺にある
Create
名前を入力してCreate
できました
Repositoryの中はまだ空
view push commmandsを押すとアップロード用コマンドが表示されるので、ここからはCLI対応
まずawscliをインストールする
https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
インストールコマンド
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
実行した
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ sudo ./aws/install
[sudo] password for docker:
You can now run: /usr/local/bin/aws --version
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ aws --version
aws-cli/2.27.35 Python/3.13.3 Linux/6.8.0-48-generic exe/x86_64.ubuntu.24
docker@ubuntu24:~/lambda_build/multicloud_billing_report/aws/dist$ ldd aws
linux-vdso.so.1 (0x00007ffee88b9000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007774854c1000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007774854a5000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007774854a0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000777485200000)
/lib64/ld-linux-x86-64.so.2 (0x00007774854d8000)
docker@ubuntu24:~/lambda_build/multicloud_billing_report/aws/dist$
つぎにawscliからAWSに接続できるようにAccess Keyを発行する
IAM > Security credentials
Access keysのところからCreate accesss key
Root userで発行するなという警告がでる
できた
接続構成
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ aws configure
AWS Access Key ID [None]: <Access Keyをここに入力>
AWS Secret Access Key [None]: <Secret access Keyをここに入力>
Default region name [None]: us-east-1
Default output format [None]:
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
ECRにログイン
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin xxxxxxxxxxxxxx.xxx.ecr.us-east-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/docker/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
Login Succeeded
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
イメージにタグをつけてPush
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ docker tag multicloud_billing_report:latest xxxxxxxxxxxxxx.xxx.ecr.us-east-1.amazonaws.com/multicloud_billing_report:latest
docker@ubuntu24:~/lambda_build/multicloud_billing_report$ docker push xxxxxxxxxxxxxx.xxx.ecr.us-east-1.amazonaws.com/multicloud_billing_report:latest
The push refers to repository [xxxxxxxxxxxxxx.xxx.ecr.us-east-1.amazonaws.com/multicloud_billing_report]
a58c0862a8be: Pushed
f7311e9d678c: Pushed
3062268dddc3: Pushed
9a865928ce17: Pushed
b1a54c892e52: Pushed
1349293713ba: Pushed
ce6a38e7833c: Pushed
d316c5099768: Pushed
6a9b57324378: Pushed
86fc9027353c: Pushed
6b702557483e: Pushed
0b81e7a3683d: Pushed
latest: digest: sha256:45ec3f9c22ff58ca8cb815506b40e17729be35dea0bfa2431c0b1d73fa66f689 size: 2828
docker@ubuntu24:~/lambda_build/multicloud_billing_report$
ここまでやってなんだけど、金かかりそうだから別の所に移すかも
入っとる。346MBらしい。これなら無料枠に収まるかも。
Lambda Function作成画面からPushしたイメージを読み込んでCreate functionする
Test OK
以下ハマった点
ECRにイメージアップロードしなおしたら、再度Deploy仕直さないとFunction側には反映されないらしい。ECRにtag上書きで保存しなおしてもイメージとしては元のやつが使われちゃう。
Functionの実行タイムアウト設定できる。デフォルト3秒は世知辛い。
Amazon EventBridge Schedule
作成したLambda Functionを日次で起動されるようにする
https://docs.aws.amazon.com/lambda/latest/dg/with-eventbridge-scheduler.html
この辺にあった
EventBrige Schedule
設定
毎日21:30実行
この辺はざっくり5分
Lambdaを選んで作ったfunctionを選ぶ
ここはとりあえずようわからんからDefault
最後確認画面が出てCreate Schedule
はい、出来ました。あとは実行されるのを待つ
CloudWatchってので見るのね
CloudWatch > Log groups にLambda FunctionのLoggroupができてた
標準出力はここにでるらしい
無事飛ぶようになりました
ちゃんとメール飛ぶようになったのでひとまずは完了
とりあえずで作ったのでOCIのAPIキーとかコンテナイメージに包んでしまったが、それはよろしくないのでAWSのシークレットマネージャーなるものに格納するようにしてみたいと思う。