概要
AWSの勉強がてら、何か作ろうと思いました
スケジュールを設定したら、その時間に電話をかけてくれるというものを作成してみます
-
この記事に記載すること
- システム構成図
- AWSリソースの設定・構築手順など
- 実際にLambda→PagerDuty経由で電話をかける
-
記載しないこと
- AWSの登録の仕方
- PagerDutyの登録の仕方
本題
システム構成図
今回のシステム構成として検討したのは以下のような構成です
電話かける系のサービスとして使われるAWS Connectを利用しなかった理由としては、従量課金ですら嫌なので、できるだけ完全無料を目指したいといったモットーでシステム構築してみるぞと思った次第になります
2. システム概要 & アーキテクチャ
本システムは以下の2つのフローで構成されています。
① 朝の目覚まし発信フロー(毎日 AM 07:00 等)
- EventBridge Scheduler が指定時刻に起動。
- AWS Lambda が起動し、SSM Parameter Store から暗号化された PagerDuty の Integration Key を取得。
- PagerDuty Events API v2 へアラートを発行。
- PagerDutyの電話通知機能により、スマホへ音声電話が着信(※iPhoneの「緊急着信時バイパス」を設定しておくことで、マナーモードやおやすみモードで
も大音量で鳴動)。
──────
② 早起き時の手動解除 & 深夜の自動リセットフロー
「予定より早く起きた日」に電話が鳴るのを防ぐ手動解除機能と、その後のセット忘れを防ぐ安全装置を備えています。
3. 工夫したポイント & AWS構成の要点
① PagerDuty Freeプランを活用したランニングコスト0円の電話通知
外部の電話API(Twilioなど)は従量課金が発生しますが、PagerDutyのFreeプラン(個人枠)にはインシデント発生時の通知手段として「電話(Voice)
」が用意されています。
これを利用し、Events API v2 経由でアラートをトリガーすることで、追加コストを一切かけずにリピート電話着信機能を実現しました。
② 統合型Lambda関数 × ペイロードによる処理分岐
「目覚ましアラーム(alarm)」と「安全装置(reset)」で別々のLambdaを作成すると管理が煩雑になるため、単一の統合型Lambda関数として実装しまし
た。
EventBridge Schedulerのターゲット指定時に異なるJSONペイロードを渡すことで、処理を動的に分岐させています。
• 目覚まし実行時: { "action": "alarm" }
• 深夜リセット時: { "action": "reset" }
③ 「セット忘れ」を防ぐ自動リセット機能(安全装置)
早起きした日にスケジュールを「無効(Disabled)」に手動変更した場合、翌日以降に再有効化(Enabled)し忘れて寝過ごしてしまう事故が懸念されま
す。
そこで、毎日深夜(00:00)に自動起動するリセット用スケジュールを設置。Lambdaが scheduler:UpdateSchedule
APIを呼び出し、スケジュールの状態を強制的に ENABLED に復帰させる安全装置を組み込みました。
④ サードパーティ非依存(標準ライブラリのみ)& 超高速環境構築( uv )
• Lambda実装: Python 3.13環境を採用し、 urllib.request や json などの標準ライブラリのみで記述。 requests
などの外部パッケージが不要なため、Lambda Layerの構築やzipパッケージングのオーバーヘッドがなく、軽量かつ高速に動作します。
• ローカル開発: パッケージマネージャーには uv を導入。 uv sync で開発環境( boto3 等)を即座に再現し、 uv run python -m unittest
で分離された環境から高速に単体テストを実行できます。
⑤ セキュリティと最小権限の原則(SSM + IAM + Terraform)
• 機密情報の隠蔽: PagerDutyの Integration Key はコードやEventBridgeの設定にベタ書きせず、AWS SSM Parameter Store ( SecureString )
から実行時に動的取得します。
• Terraformでの資格情報保護: aws_ssm_parameter リソースに lifecycle { ignore_changes = [value] }
を設定。Terraformコード上にはダミー値を記述し、本番のキーはコンソール等から安全に設定・保持できるようにしています。
• 最小権限のIAMポリシー: Lambdaロールには、指定したSSMパラメータの取得権限( ssm:GetParameter
)および指定したEventBridgeスケジュールの更新権限( scheduler:UpdateSchedule )のみをピンポイントで付与しています。
コードのポイント抜粋
Lambda関数 ( src/lambda_function.py )
標準ライブラリのみで PagerDuty Events API v2 と EventBridge Scheduler API を操作する構造です。
import json
import os
import urllib.request
import boto3
def trigger_pagerduty_alarm(routing_key):
url = "https://events.pagerduty.com/v2/enqueue"
payload = {
"routing_key": routing_key,
"event_action": "trigger",
"payload": {
"summary": "朝の目覚ましアラーム / Wake up alarm!",
"source": "Wakeup System Lambda",
"severity": "critical"
}
}
req = urllib.request.Request(
url,
data=json.dumps(payload).encode('utf-8'),
headers={'Content-Type': 'application/json'},
method='POST'
)
with urllib.request.urlopen(req) as response:
return json.loads(response.read().decode('utf-8'))
def reset_eventbridge_scheduler(schedule_name, group_name):
scheduler = boto3.client('scheduler')
schedule_info = scheduler.get_schedule(Name=schedule_name, GroupName=group_name)
# 現在の設定を維持したまま State を ENABLED に更新
update_params = {
"Name": schedule_name,
"GroupName": group_name,
"ScheduleExpression": schedule_info["ScheduleExpression"],
"FlexibleTimeWindow": schedule_info["FlexibleTimeWindow"],
"Target": schedule_info["Target"],
"State": "ENABLED"
}
return scheduler.update_schedule(**update_params)
def lambda_handler(event, context):
action = event.get('action')
if action == "alarm":
routing_key = get_ssm_parameter(os.environ['SSM_PARAMETER_NAME'])
trigger_pagerduty_alarm(routing_key)
elif action == "reset":
reset_eventbridge_scheduler(
os.environ['TARGET_SCHEDULE_NAME'],
os.environ.get('TARGET_SCHEDULE_GROUP_NAME', 'default')
)
EventBridge Scheduler (Terraform terraform/main.tf )
schedule_expression_timezone = "Asia/Tokyo" を指定し、時差を意識せず直感的にJSTで設定しています。
# (a) 朝の目覚ましスケジュール
resource "aws_scheduler_schedule" "alarm" {
name = "wakeup-alarm-schedule"
group_name = aws_scheduler_schedule_group.wakeup_group.name
schedule_expression = "cron(0 7 ? * MON-FRI *)" # 平日朝7時
schedule_expression_timezone = "Asia/Tokyo"
target {
arn = aws_lambda_function.wakeup_lambda.arn
role_arn = aws_iam_role.scheduler_role.arn
input = jsonencode({ action = "alarm" })
}
}
# (b) 深夜の自動リセットスケジュール
resource "aws_scheduler_schedule" "reset" {
name = "wakeup-reset-schedule"
group_name = aws_scheduler_schedule_group.wakeup_group.name
schedule_expression = "cron(0 0 * * ? *)" # 毎日深夜0時
schedule_expression_timezone = "Asia/Tokyo"
target {
arn = aws_lambda_function.wakeup_lambda.arn
role_arn = aws_iam_role.scheduler_role.arn
input = jsonencode({ action = "reset" })
}
}
おわりに
SaaSの無料枠(PagerDuty)とAWSのサーバーレスアーキテクチャ(Lambda + EventBridge
Scheduler)を組み合わせることで、信頼性が高くコスト0円の電話通知システムを構築することができました。
• 二度寝防止: スマホの着信音 + PagerDutyのしつこいリピート電話で絶対に起きられる。
• 誤鳴動防止 & 事故防止: アプリから簡単にスケジューラをオフにでき、深夜に自動復帰するセーフティネットも完璧。
• フルIaC管理: Terraformにより、インフラのバージョン管理や再構築も容易。
