0
1

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 x PagerDutyで定期的に自分に電話をかけるようなシステムを構築する

0
Posted at

概要

AWSの勉強がてら、何か作ろうと思いました
スケジュールを設定したら、その時間に電話をかけてくれるというものを作成してみます

  • この記事に記載すること

    • システム構成図
    • AWSリソースの設定・構築手順など
    • 実際にLambda→PagerDuty経由で電話をかける
  • 記載しないこと

    • AWSの登録の仕方
    • PagerDutyの登録の仕方

本題

システム構成図

今回のシステム構成として検討したのは以下のような構成です

Untitled Diagram.drawio.png

電話かける系のサービスとして使われるAWS Connectを利用しなかった理由としては、従量課金ですら嫌なので、できるだけ完全無料を目指したいといったモットーでシステム構築してみるぞと思った次第になります

2. システム概要 & アーキテクチャ

本システムは以下の2つのフローで構成されています。

① 朝の目覚まし発信フロー(毎日 AM 07:00 等)

  1. EventBridge Scheduler が指定時刻に起動。
  2. AWS Lambda が起動し、SSM Parameter Store から暗号化された PagerDuty の Integration Key を取得。
  3. PagerDuty Events API v2 へアラートを発行。
  4. 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により、インフラのバージョン管理や再構築も容易。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?