みなさん、こんにちは。万次郎です。
「毎日決まった時間に Slack へ通知を送りたい」——そんな要件に出会ったことはないでしょうか。日次のレポート、定期的なリマインダー、システムの稼働状況の報告など、スケジュール実行と Slack 通知の組み合わせは、実務でよく登場するパターンです。
AWS Lambda と EventBridge を使えば、この仕組みは比較的簡単に実現できます。しかし、『CloudFormation の YAML を書くのが面倒』『ローカルでの動作確認がしづらい』といった課題を感じることもあるのではないでしょうか。
今回は、AWS Chalice というフレームワークを使って、この課題を解決していきます。Chalice は Python のデコレータでインフラ設定が完結するため、YAML を書く必要がありません。さらに Docker を組み合わせることで、ローカルでの開発体験も向上させます。
この記事を読み終えるころには、ローカル開発から AWS デプロイまで、一連の流れを体験できるようになっています。ぜひ最後までお付き合いください。
※「定刻に Slack へ固定の文面を送るだけ」であれば、EventBridge Scheduler から Webhook を直接叩くほうが手軽です(Lambda のコードも不要)。この記事は、レポートの中身を組み立てるのにコードが必要なケース——データを取得して整形する、条件によって内容を変える、といった処理を Lambda に載せる前提で進めます。
- 1. 今回作るもの
- 2. 前提条件・環境
- 3. プロジェクト構成
- 4. Docker 環境の構築
- 5. Chalice アプリケーションの実装
- 6. Slack 通知の実装
- 7. Chalice 設定
- 8. ローカルでの動作確認
- 9. AWS へのデプロイ
- 10. まとめ
1. 今回作るもの
まずは、今回構築するシステムの全体像を把握しておきましょう。
EventBridge (スケジュール)
↓
Lambda (Dockerコンテナ)
↓
Slack Webhook
↓
Slackチャンネル
仕組みはシンプルです。EventBridge が毎日決まった時間に Lambda 関数を起動し、Lambda 関数が Slack Webhook を通じてメッセージを送信します。
この構成自体は、SAM や Serverless Framework でも実現できます。では、なぜ Chalice を選ぶのでしょうか。
YAML を書かずにスケジュール設定ができる
Lambda + EventBridge で定期実行を実現する場合、一般的には CloudFormation や SAM のテンプレートを書く必要があります。たとえば、毎日 9 時(UTC)に Lambda を実行したい場合、SAM では以下のような設定が必要です:
# SAMの場合(template.yaml) AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Resources: DailyReportFunction: Type: AWS::Serverless::Function Properties: Handler: app.handler Runtime: python3.11 Events: ScheduleEvent: Type: Schedule Properties: Schedule: cron(0 9 * * ? *) Name: daily-report-schedule Enabled: true
YAML の構文を調べながら、インデントに気をつけながら、リソース名を考えながら書いていく。慣れれば問題ありませんが、最初のうちはなかなか手間がかかります。
一方、Chalice ではこうなります:
# Chaliceの場合(app.py) from chalice import Chalice, Cron app = Chalice(app_name="slack-reporter") @app.schedule(Cron(0, 9, "*", "*", "?", "*")) def daily_report(event): # ここに処理を書く return {"status": "success"}
見比べてみてください。Chalice では、関数に@app.schedule()デコレータを付けるだけです。YAML ファイルを別途用意する必要もなければ、リソース名や ARN を意識する必要もありません。デプロイすると、Chalice が EventBridge ルールの作成から Lambda との紐付けまで、すべて自動で行ってくれます。
Python を書いている延長線上で、インフラ設定が完了する。
ここが Chalice を選ぶ最大の理由です。
Docker を組み合わせる理由
Chalice 単体でも十分便利ですが、今回はさらに Docker を組み合わせます。
Lambda 関数の開発でよくある悩みが、『ローカルで動作確認がしづらい』という点です。chalice localというコマンドもありますが、これは HTTP エンドポイントのテスト用であり、スケジュール関数のテストには向いていません。
そこで、AWS 公式が提供する Lambda 用の Docker イメージを使います。このイメージには Lambda 実行環境がそのまま入っているため、ローカルでも本番と同じ方法で関数を呼び出せます。docker compose upでコンテナを起動し、curl でリクエストを送るだけで動作確認ができるようになります。
また、Docker を使うことで、依存パッケージの問題も回避できます。ローカルの macOS や Windows で動いていたのに、Lambda 環境(Amazon Linux)では動かない——特にネイティブライブラリを含むパッケージで起こりがちなこの問題も、最初から Linux 環境で開発することで防げます。
では、実際に構築していきましょう。まずは環境の準備からです。
2. 前提条件・環境
実装に入る前に、開発環境を整えておきましょう。今回のシステムでは、ローカル開発に Docker を、AWS 連携に Chalice と AWS CLI を使います。それぞれ順番に確認していきます。
Python 環境の確認
まずは Python です。Chalice は Python フレームワークなので、これがないと始まりません:
python --version # Python 3.11.x 以上
Python 3.11 以上であれば問題ありません。もし古いバージョンの場合は、pyenv などでアップデートしてください。
Docker 環境の確認
次に Docker です。ローカルで Lambda 関数をテストするために使います。AWS にデプロイする前に手元で動作確認できるので、開発効率が格段に上がります:
docker --version # Docker version 20.10.x 以上 docker compose version # Docker Compose version v2.x.x
AWS CLI・Chalice の準備
ここまではローカル開発に必要なツールでした。記事の後半では AWS にデプロイするので、AWS 関連のツールも準備しておきます。
まずは AWS CLI がインストールされていて、認証情報が設定されているか確認します:
aws --version # aws-cli/2.x.x aws sts get-caller-identity # アカウント情報が表示されればOK
aws sts get-caller-identityでアカウント情報が表示されれば、認証情報は正しく設定されています。表示されない場合は、aws configureで設定してください。
続いて、Chalice 本体をインストールします:
uv pip install chalice --system chalice --version # chalice 1.31.0 以上
これで AWS へのデプロイ準備も完了です。
Slack Incoming Webhook の取得
最後に、Slack 通知のための Webhook URL を取得します。これがないと Slack にメッセージを送れません。
すでに Webhook URL を持っている方は、この手順をスキップして構いません。まだの方は、以下の手順で作成してください:
- Slack APIにアクセス
- 「Create New App」→「From scratch」を選択
- App 名(例:Daily Reporter)と通知先のワークスペースを設定
- 左メニューの「Incoming Webhooks」をクリック
- 「Activate Incoming Webhooks」を ON にする
- 「Add New Webhook to Workspace」で通知先チャンネルを選択
- 生成された Webhook URL(
https://hooks.slack.com/services/...)をコピー
この URL は後ほど環境変数として設定します。安全な場所にメモしておいてください。
これで開発に必要なツールがすべて揃いました。次は、実際にプロジェクトを作成していきます。
3. プロジェクト構成
環境が整ったので、プロジェクトを作成していきましょう。まずはディレクトリを作ります:
mkdir slack-reporter cd slack-reporter
次に、Chalice が必要とするディレクトリを作成します:
mkdir -p .chalice chalicelib
ここで.chaliceとchalicelibという 2 つのディレクトリが登場しました。どちらも Chalice 独自の規約によるもので、この名前でないと正しく動作しません。それぞれの役割を説明します。
.chalice/は、Chalice の設定やデプロイ情報が格納されるディレクトリです。この中にconfig.jsonを置くことで、Lambda 関数のメモリサイズやタイムアウト、環境変数などを設定できます。
chalicelib/は、app.pyから参照する追加モジュールを置く場所です。今回は Slack 通知の処理をここに切り出します。Chalice は、デプロイ時にこのディレクトリを自動的にパッケージに含めてくれます。lib/やsrc/など別の名前にしてしまうと、デプロイ時にファイルが含まれないので注意してください。
最終的なディレクトリ構成は以下のようになります:
slack-reporter/ ├── .chalice/ │ └── config.json # Chaliceの設定ファイル ├── chalicelib/ │ ├── __init__.py │ └── slack.py # Slack通知モジュール ├── .env # 環境変数(Webhook URL) ├── .env.example # 環境変数のテンプレート ├── .gitignore ├── app.py # メインのアプリケーション ├── docker-compose.yaml # ローカル開発用 ├── Dockerfile # Lambda用コンテナ定義 └── requirements.txt # Pythonパッケージ
ファイル数は多く見えますが、一つずつ順番に作っていけば難しくありません。まずは Docker 関連のファイルから始めましょう。
4. Docker 環境の構築
ここでは、Lambda 用の Docker イメージを構築します。
通常の Docker イメージではなく、AWS 公式が提供する Lambda 専用のベースイメージを使用します。このイメージには、Lambda 実行環境(Runtime Interface Client)が組み込まれており、ローカルでも Lambda と同じ方法で関数を呼び出せます。
requirements.txt
まずは依存パッケージを定義します:
chalice>=1.31.0 requests>=2.31.0
- chalice: 今回のメインフレームワーク。デコレータや Cron 式の定義に使用。
app.pyがfrom chalice import ...するため、Docker コンテナ内でも必須 - requests: Slack Webhook への HTTP リクエストに使用
Dockerfile
FROM public.ecr.aws/lambda/python:3.11
# uv のバイナリを公式イメージから取得(バージョンは固定しておくと再現性が高い)
COPY --from=ghcr.io/astral-sh/uv:0.11.26 /uv /uvx /bin/
WORKDIR ${LAMBDA_TASK_ROOT}
# 依存パッケージをインストール(uv を使用)
COPY requirements.txt .
RUN uv pip install --system --no-cache -r requirements.txt
# アプリケーションコードをコピー
COPY app.py .
COPY chalicelib/ ./chalicelib/
# Lambdaハンドラーを指定
CMD ["app.handler"]
各行を見ていきましょう:
| 行 | 説明 |
|---|---|
FROM public.ecr.aws/lambda/python:3.11 |
AWS 公式の Lambda 用 Python イメージ。Lambda 実行環境が組み込まれている |
COPY --from=ghcr.io/astral-sh/uv:0.11.26 /uv /uvx /bin/ |
uv の公式イメージから uv バイナリだけを取り出して配置(マルチステージ)。ホストに uv が入っていなくてもビルドできる |
WORKDIR ${LAMBDA_TASK_ROOT} |
Lambda のコード配置先(/var/task)に移動 |
COPY requirements.txt . → RUN uv pip install --system ... |
依存パッケージを先にインストール(Docker のレイヤーキャッシュを活用)。--system でイメージのシステム Python に直接入れ、--no-cache でレイヤーを軽くする |
COPY app.py . / COPY chalicelib/ ... |
アプリケーションコードをコピー |
CMD ["app.handler"] |
Lambda 起動時に呼び出す関数を指定(app.pyのhandler関数) |
pip install のままでも動きますが、COPY --from で uv バイナリを差し込むだけで、ビルド時の依存解決が高速化します。ghcr.io/astral-sh/uv:0.11.26 のようにバージョンを固定しておくと、いつビルドしても同じ uv で解決されるため再現性が上がります(latest でも動きますが、固定を推奨)。
docker-compose.yaml
ローカル開発用の Docker Compose 設定です:
services: lambda: build: context: . dockerfile: Dockerfile ports: - "9000:8080" environment: - SLACK_WEBHOOK_URL=${SLACK_WEBHOOK_URL} volumes: - ./app.py:/var/task/app.py:ro - ./chalicelib:/var/task/chalicelib:ro
設定のポイントを説明します:
ポートマッピング(9000:8080)
Lambda 用のベースイメージは、内部でポート 8080 をリッスンしています。これをホストの 9000 番ポートにマッピングすることで、http://localhost:9000から Lambda 関数を呼び出せるようになります。
環境変数(SLACK_WEBHOOK_URL)
${SLACK_WEBHOOK_URL}は、ホスト側の環境変数または.envファイルから読み込まれます。機密情報を docker-compose.yaml に直接書かずに済むのがメリットです。
ボリュームマウント(volumes)
app.pyとchalicelib/をマウントしているため、コードを編集するとコンテナを再ビルドせずに反映されます。開発中の試行錯誤が格段に楽になります。
環境変数ファイルの作成
.env.exampleをテンプレートとして作成し、.envにコピーして使用します:
# .env.example(テンプレート) SLACK_WEBHOOK_URL=https://hooks.slack.com/services/XXXX/XXXX/XXXX
# .envを作成してWebhook URLを設定 cp .env.example .env # .envを編集して、実際のWebhook URLを設定
.envファイルには Webhook URL が含まれるため、.gitignoreに追加してリポジトリにコミットしないようにしましょう:
# .gitignore .env .chalice/deployed/ .chalice/deployments/ __pycache__/ *.pyc
5. Chalice アプリケーションの実装
ここでは、定期実行される Lambda 関数のメインロジックを実装します。
コードの全体構造
app.pyには 3 つの関数を定義します:
| 関数 | 役割 |
|---|---|
create_daily_report() |
レポート作成のコアロジック。Slack 通知を実行する |
daily_report(event) |
Chalice のスケジュール関数。AWS デプロイ時に EventBridge から呼び出される |
handler(event, context) |
Lambda ハンドラー。Docker でのローカルテスト時に呼び出される |
『なぜ 2 つのエントリポイントが必要なのか?』と思われるかもしれません。
Chalice の@app.schedule()で定義した関数は、Chalice 独自のイベントラッパーを経由して呼び出されます。しかし、Docker コンテナとしてローカル実行する場合、このラッパーは使えません。そこで、コアロジックをcreate_daily_report()に切り出し、両方のエントリポイントから呼び出す構造にしています。
app.py
from datetime import datetime from chalice import Chalice, Cron from chalicelib.slack import send_slack_message app = Chalice(app_name="slack-reporter") def create_daily_report(): """レポート作成のコアロジック""" now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") message = f"日次レポート -{now}\n\n定期実行されたスケジュールレポートです。" # 他にもここに複雑な処理を書けます send_slack_message(message) return {"status": "success", "timestamp": now} @app.schedule(Cron(0, 9, "*", "*", "?", "*")) def daily_report(event): """毎日9時 UTC(=日本時間18時)に実行される定期レポート""" return create_daily_report() def handler(event, context): """Lambdaハンドラー(ローカルテスト用)""" return create_daily_report()
Cron 式の書き方
@app.schedule()に渡すCronオブジェクトは、6 つの引数を取ります:
Cron(分, 時, 日, 月, 曜日, 年)
今回のCron(0, 9, "*", "*", "?", "*")を分解すると:
| 位置 | 値 | 意味 |
|---|---|---|
| 分 | 0 |
0 分 |
| 時 | 9 |
9 時(UTC) |
| 日 | * |
毎日 |
| 月 | * |
毎月 |
| 曜日 | ? |
指定なし |
| 年 | * |
毎年 |
注意:時刻は UTC で指定します。
日本時間(JST = UTC+9)で実行したい場合は、9 時間引いた値を指定してください:
| 実行したい時刻(JST) | 指定する時刻(UTC) |
|---|---|
| 朝 9 時 | Cron(0, 0, ...) |
| 昼 12 時 | Cron(0, 3, ...) |
| 夕方 18 時 | Cron(0, 9, ...) |
| 深夜 0 時 | Cron(0, 15, ...) |
その他のスケジュール例
日次以外のスケジュールも簡単に設定できます:
# 毎週月曜日の朝9時(UTC) @app.schedule(Cron(0, 9, "?", "*", "MON", "*")) def weekly_report(event): ... # 毎月1日の0時(UTC) @app.schedule(Cron(0, 0, "1", "*", "?", "*")) def monthly_report(event): ... # 平日の毎朝9時(UTC) @app.schedule(Cron(0, 9, "?", "*", "MON-FRI", "*")) def weekday_report(event): ...
曜日を指定する場合は、日(3 番目の引数)を?にする必要があります。日と曜日は同時に*を指定できません。
6. Slack 通知の実装
次に、Slack へメッセージを送信するモジュールを実装します。
chalicelib/init.py
まず、chalicelibを Python パッケージとして認識させるため、空の__init__.pyを作成します:
touch chalicelib/__init__.py
chalicelib/slack.py
import os import requests def send_slack_message(message: str) -> dict: """Slack Webhookを使ってメッセージを送信する""" webhook_url = os.environ.get("SLACK_WEBHOOK_URL") if not webhook_url: raise ValueError("SLACK_WEBHOOK_URL is not set") payload = {"text": message} response = requests.post(webhook_url, json=payload, timeout=10) response.raise_for_status() return {"status_code": response.status_code, "body": response.text}
コードの各部分を見ていきましょう:
環境変数から Webhook URL を取得
webhook_url = os.environ.get("SLACK_WEBHOOK_URL")
Webhook URL はソースコードに直接書かず、環境変数から取得します。これにより、開発環境と本番環境で異なる Slack チャンネルに通知を送ることも容易になります。
Webhook へのリクエスト送信
payload = {"text": message}
response = requests.post(webhook_url, json=payload, timeout=10)
response.raise_for_status()
Slack Webhook は、{"text": "メッセージ"}という形式の JSON を POST するだけで通知が送れます。timeout=10で 10 秒以上応答がない場合はエラーにし、raise_for_status()で HTTP エラー時に例外を発生させます。
Block Kit でリッチなメッセージを送る(発展)
シンプルなテキストメッセージで十分な場合が多いですが、見出しやボタンを含むリッチなメッセージを送りたい場合は、payloadを拡張します:
payload = {
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "Daily Report"}
},
{
"type": "section",
"text": {"type": "mrkdwn", "text": f"*日時*:{now}"}
}
]
}
Block Kit の詳細は Slack 公式ドキュメントを参照してください。
7. Chalice 設定
最後に、Chalice の設定ファイルを作成します。このファイルは、chalice deployで AWS にデプロイする際に使用されます。
.chalice/config.json
{ "version": "2.0", "app_name": "slack-reporter", "stages": { "dev": { "api_gateway_stage": "dev", "lambda_memory_size": 256, "lambda_timeout": 30, "environment_variables": { "SLACK_WEBHOOK_URL": "" } } } }
各設定項目の意味は以下の通りです:
| 項目 | 説明 |
|---|---|
version |
Chalice 設定ファイルのバージョン。現在は"2.0"を使用 |
app_name |
アプリケーション名。AWS リソースの命名に使われる |
stages |
環境ごとの設定。dev、prodなど複数定義可能 |
lambda_memory_size |
Lambda に割り当てるメモリ(MB)。Slack 通知程度なら 256MB で十分 |
lambda_timeout |
Lambda 実行のタイムアウト(秒)。Webhook 送信なら 30 秒で余裕がある |
environment_variables |
Lambda 実行時の環境変数 |
本番環境での環境変数の扱い
開発時は.envファイルで Webhook URL を管理しますが、本番デプロイ時はセキュリティ上、別の方法を検討してください:
方法 1: config.json に直接記述(シンプルだが非推奨)
"environment_variables": { "SLACK_WEBHOOK_URL": "https://hooks.slack.com/services/..." }
config.json がリポジトリに含まれる場合、機密情報が漏洩するリスクがあります。
方法 2: AWS Systems Manager Parameter Store(推奨)
Webhook URL を Parameter Store に保存し、Lambda 実行時に取得する方法です。Chalice は直接の Parameter Store 連携はサポートしていませんが、コード内でboto3を使って取得できます。
8. ローカルでの動作確認
ここまでで必要なファイルはすべて揃いました。実際に動かしてみましょう。
ファイル一覧の確認
$ ls -la .chalice/ chalicelib/ .env .env.example .gitignore app.py docker-compose.yaml Dockerfile requirements.txt
Docker イメージのビルドと起動
# Dockerイメージをビルドしてコンテナを起動 docker compose up -d --build
初回はベースイメージのダウンロードがあるため、数分かかる場合があります。
起動したかどうかは以下で確認できます:
$ docker compose ps NAME SERVICE STATUS PORTS src-lambda-1 lambda running 0.0.0.0:9000->8080/tcp
Lambda 関数の呼び出し
Lambda 用の Docker イメージには、Runtime Interface Emulator(RIE)が含まれています。これにより、本番の Lambda と同じエンドポイント形式で関数を呼び出せます:
curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
成功すると以下のようなレスポンスが返ります:
{ "status": "success", "timestamp": "2025-12-30 06:00:43" }
同時に、Slack チャンネルにメッセージが届いているはずです。確認してみてください。
この呼び出しはhandlerを直接叩くため、@app.schedule経由で届く EventBridge イベントの中身は検証できていません。イベントフィールドを参照するように拡張した場合は、後述の EventBridge 形式ペイロードやaws lambda invokeを使って確認してください。
うまくいかない場合
コンテナのログを確認する
docker compose logs lambda
よくあるエラーと対処法:
| エラー | 原因 | 対処 |
|---|---|---|
SLACK_WEBHOOK_URL is not set |
環境変数が設定されていない | .envファイルを確認 |
401 Unauthorized |
Webhook URL が無効 | Slack API で URL を再生成 |
Connection refused |
コンテナが起動していない | docker compose up -dを再実行 |
コンテナの停止
確認が終わったら、コンテナを停止します:
docker compose down
9. AWS へのデプロイ
ローカルでの動作確認ができました。Slack にメッセージが届くことを確認できたので、次は本番環境である AWS にデプロイしてみましょう。
ここで一つ疑問が浮かぶかもしれません。『Docker コンテナの中でデプロイするの?』という点です。
答えは「いいえ」です。Docker はあくまでローカルでの開発・テスト用であり、AWS へのデプロイはchalice deployコマンドをホストマシンで実行します。ローカル環境から AWS CLI の認証情報を使って AWS にアクセスし、必要なリソースを作成してくれます。
デプロイ前の準備
chalice deployを実行する前に、一つ準備が必要です。
Chalice はrequirements.txtを見て自動で依存関係をパッケージ化するため、デプロイだけを行うならホストに事前インストールする必要はありません。準備として行うのは、環境変数の設定です。
ローカルテストでは.envファイルで Webhook URL を管理しましたが、AWS にデプロイする際は.chalice/config.jsonに設定します。このファイルを開いて、SLACK_WEBHOOK_URLに実際の URL を設定してください:
{ "version": "2.0", "app_name": "slack-reporter", "stages": { "dev": { "api_gateway_stage": "dev", "lambda_memory_size": 256, "lambda_timeout": 30, "environment_variables": { "SLACK_WEBHOOK_URL": "https://hooks.slack.com/services/XXXX/XXXX/XXXX" } } } }
なお、config.json を Git リポジトリにコミットする場合、Webhook URL が漏洩するリスクがあります。本番運用では、AWS Systems Manager Parameter Store を使用するなどの対策が必要です(応用編で紹介予定)。今回は開発環境なので、config.json に直接記述して進めます。
いよいよデプロイ
準備が整いました。以下のコマンドを実行してください:
chalice deploy
初回デプロイでは、以下のような出力が表示されます:
Creating deployment package. Creating IAM role: slack-reporter-dev Creating lambda function: slack-reporter-dev-daily_report Resources deployed: - Lambda ARN: arn:aws:lambda:ap-northeast-1:xxxx:function:slack-reporter-dev-daily_report
出力を見ると、Chalice がいくつかのリソースを作成していることがわかります。まずデプロイパッケージ(アプリケーションコードと依存パッケージをまとめた ZIP ファイル)を作成し、次に Lambda 実行用の IAM ロールを作成、最後に Lambda 関数本体を作成しています。
ここで注目すべき点があります。出力には明示的に表示されていませんが、実は EventBridge ルールも同時に作成されています。Chalice は@app.schedule()デコレータを検出して、自動的にスケジュールを設定してくれるのです。
本当にスケジュールが設定されているか確認する
デプロイが完了したら、本当に EventBridge ルールが作成されているか確認してみましょう:
aws events list-rules --name-prefix slack-reporter
{ "Rules": [ { "Name": "slack-reporter-dev-daily_report-event", "State": "ENABLED", "ScheduleExpression": "cron(0 9 * * ? *)" } ] }
app.pyで@app.schedule(Cron(0, 9, "*", "*", "?", "*"))と定義したスケジュールが、そのまま EventBridge ルールとして作成されています。State: ENABLEDとなっているので、スケジュールはすでに有効です。毎日 9 時(UTC)、つまり日本時間 18 時になると、このルールが Lambda 関数を自動的に起動します。
また、Chalice は Lambda 実行に必要な IAM ポリシーも自動で生成しています:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:*:logs:*:*:*" } ] }
CloudWatch Logs への書き込み権限のみが付与されています。Slack Webhook への通知は HTTPS リクエストなので、特別な AWS 権限は不要です。Chalice は必要最小限の権限(Least Privilege)を自動で設定してくれます。
手動で Lambda 関数を実行してみる
スケジュールの時間まで待つのは時間がかかります。今すぐ動作確認したい場合は、手動で Lambda 関数を呼び出すことができます。
ただし、一点注意があります。Chalice のスケジュール関数は、EventBridge から送られてくる特定の形式のイベントを期待しています。単に空のペイロードを送ると、イベントの解析でエラーになってしまいます。
そこで、EventBridge 形式のテストイベントを作成します:
cat << 'EOF' > /tmp/event.json
{
"version": "0",
"id": "test-event",
"detail-type": "Scheduled Event",
"source": "aws.events",
"account": "123456789012",
"time": "2026-01-01T00:00:00Z",
"region": "ap-northeast-1",
"resources": [],
"detail": {}
}
EOF
この JSON は、実際に EventBridge が Lambda 関数を呼び出す際に送信するイベントの形式を模倣しています。ファイルを作成したら、AWS CLI で Lambda 関数を呼び出します:
aws lambda invoke \ --function-name slack-reporter-dev-daily_report \ --payload fileb:///tmp/event.json \ /tmp/output.json
-payload fileb://...のfileb://は、ファイルをバイナリとして読み込む指定です。AWS CLI v2 ではこの形式が必要になります(代替として、-cli-binary-format raw-in-base64-outを付けたうえでfile://を使う方法もあります)。
実行すると、以下のような出力が表示されます:
{ "StatusCode": 200, "ExecutedVersion": "$LATEST" }
StatusCode: 200は、Lambda 関数が正常に実行されたことを示しています。戻り値も確認してみましょう:
cat /tmp/output.json
{ "status": "success", "timestamp": "2025-12-30 06:28:09" }
ローカルテストの時と同じレスポンスが返ってきました。同時に、Slack チャンネルにメッセージが届いているはずです。確認してみてください。
これで、ローカル開発から AWS デプロイまでの一連の流れが完了しました。
コードを修正したら
開発を進めていく中で、コードを修正することがあるでしょう。その場合は、再度chalice deployを実行するだけで更新できます:
chalice deploy
Creating deployment package. Reusing existing deployment package. Updating lambda function: slack-reporter-dev-daily_report Resources deployed: - Lambda ARN: arn:aws:lambda:ap-northeast-1:xxxx:function:slack-reporter-dev-daily_report
Reusing existing deployment packageと表示されているのは、依存パッケージに変更がないためです。コードの差分だけがアップロードされるので、2 回目以降のデプロイは高速です。
使い終わったらクリーンアップ
開発やテストが終わって、AWS リソースが不要になった場合は削除しておきましょう:
chalice delete
Deleting function: arn:aws:lambda:ap-northeast-1:xxxx:function:slack-reporter-dev-daily_report Deleting IAM role: slack-reporter-dev
このコマンドで、Chalice が作成した Lambda 関数、IAM ロール、EventBridge ルールがすべて削除されます。
なお、Lambda 関数は実行時間に応じた課金なので、待機しているだけでは料金は発生しません。そのため、すぐに削除する必要はありませんが、不要なリソースは整理しておくと管理がしやすくなります。
10. まとめ
今回は、Chalice + Docker + EventBridge を使った定期 Slack 通知システムの構築方法をご紹介しました。
今回作ったもの
slack-reporter/ ├── .chalice/config.json # Chalice設定 ├── chalicelib/slack.py # Slack通知モジュール ├── app.py # メインアプリケーション ├── Dockerfile # Lambda用コンテナ └── docker-compose.yaml # ローカル開発環境
たったこれだけのファイルで、ローカル開発から AWS デプロイまで完結できました。
Chalice を使うメリット(振り返り)
冒頭で SAM との比較をしましたが、改めて整理すると:
- YAML を書かなくていい:
@app.schedule()デコレータだけで EventBridge 連携が完了 - Python だけで完結: インフラ設定もビジネスロジックも同じ言語で書ける
- 学習コストが低い: Flask を使ったことがあれば、すぐに馴染める
- デプロイが簡単:
chalice deploy一発で Lambda + EventBridge が構築される
次のステップ
この構成をベースに、以下のような拡張が可能です:
- 複数スケジュールの追加: 日次・週次・月次レポートを 1 つのアプリで管理
- 動的なレポート生成: データベースや API から情報を取得してレポートに含める
- エラーハンドリング: 失敗時のリトライやアラート通知
- Parameter Store 連携: 機密情報をセキュアに管理
これらの発展的な内容は、次回の応用編で紹介予定です。
ぜひ、みなさんのプロジェクトでも活用してみてください。