https://a.storyblok.com/f/270183/102102/a28b08316a/incident-reporting_1200x600.jpg

PagerDutyとVonageによるインシデント報告

最終更新日 May 10, 2021

所要時間:1 分

製品廃止のお知らせ

2025年8月31日以降、Vonage Dispatch APIは新規ユーザーに対してクローズされますが、既存ユーザーに対しては引き続きサポートされます。フェイルオーバー機能を持つメッセージング・アプリケーションを構築したい場合、フェイルオーバーは現在Messages APIで直接サポートされています。

メッセージ・フェイルオーバー機能に関する一般的な情報については、本ガイドを参照してください。 このガイド.Dispatch APIからMessages API Failoverへの移行については、以下を参照してください。 このガイド.

この非推奨製品に関するご質問は、下記までお問い合わせください。 にご連絡ください。 Vonage Community Slackまでお問い合わせください。

はじめに

PagerDutyはインシデントレポート管理システムで、エンジニアリングチームがインフラで発生した問題を検出し、修正するための通知と自動エスカレーションを提供します。この投稿では、インフラストラクチャでインシデントが発生したときに、Vonageを使ってエンジニアリングチームのメンバーにアラートを出す方法を紹介します。

自動フェイルオーバーオプションを提供するVonage Dispatch APIを使用して、まずプライマリメディアとしてFacebook Messenger経由で通知を送信し、次にフォールバックオプションとしてSMSを送信します。

技術要件

フォローするには、以下のものが必要だ:

セッティング

Dispatch APIを使えるようにするには、Vonageアカウントでやることがいくつかある。Vonageのダッシュボードに行き、Messages and Dispatchセクションで新しいメッセージアプリケーションを作成します。

new message app in dashboardnew message app in dashboard

\

  • ステータス URL は、SMS 通知を送信するたびに Vonage が POST リクエストを送信する Webhook エンドポイントです。これにより、送信された SMS のステータス更新(配信、拒否、送信など)を判断することができます。Ngrokを使用するので、ステータスのURLは次のようになります。 qc43v7.ngrok.io/webhooks/status.

  • インバウンドURLは、インバウンドメッセージを受信するたびにVonageがリクエストするエンドポイントで、次のようになります。 qc43v7.ngrok.io/webhooks/inbound-message

  • 次に、公開鍵と秘密鍵のペアを生成する。これで秘密鍵ファイルも自動的にダウンロードされる。このファイルはすぐに必要になるので、控えておこう。

  • アプリケーションを作成し、アプリケーションIDを控えてください。次に、このアプリケーションにNumbersと外部アカウントを関連付けるように促されます。これは完全に任意なので、デフォルトのままでアプリケーションを作成しても構いません。

PagerDutyのセットアップ

こちらへ ページャーデューティにアクセスしてアカウントを作成してください。また、Serviceを作成する必要があります。PagerDutyのServiceはインシデントを開きたいものを表します。アプリケーションでもコンポーネントでもチームでもかまいません。つまり、そのServiceで新しいインシデントが発生するたびに、アプリケーションの特定のエンドポイントにWebhook通知を送信したいのです。

PagerDutyのダッシュボードで、Configuration -> Servicesに移動し、新しいServiceを作成します。

pager duty dashboardpager duty dashboard

独自のカスタム統合を利用するので、統合タイプでAPIを直接使用するを選択し、次に Events API V2を選択し、その他必要な詳細を入力してください。PagerDutyでサービスを作成する方法については こちら.

次に、サービスの作成に成功したら、IntegrationsタブでNew Extensionを選択し、タイプに Generic V2 webhook.詳細セクションにはPagerDutyからの通知を受け取るアプリケーションのエンドポイントを指定します。 qc43v7.ngrok.io/webhooks/incident

pager dutypager duty

Laravelのセットアップ

composerを使って、新しいLaravelプロジェクトをインストールします。コマンドラインから、以下のコマンドを使用して新しいLaravelプロジェクトを作成します:

composer create-project --prefer-dist laravel/laravel vonage-pager-duty

ルートとコントローラー

以下のコードで routes/web.phpを以下のコードで編集する:

<?php

Route::post('/webhooks/inbound-message', 'WebhookController@inboundMessage');
Route::post('/webhooks/status', 'WebhookController@status');
Route::post('/webhooks/incident', 'WebhookController@report');

クロスサイトリクエストフォージェリ攻撃は、認証されたユーザーの代わりに不正なコマンドが実行される悪意のある攻撃の一種です。このような攻撃を防ぐために、Laravelは認証されたユーザーごとに自動的に Csrfトークンを自動的に生成し、認証されたユーザーが実際にアプリケーションにリクエストしたユーザーであることを検証します。しかし、これらのリクエストはアプリケーションの外部から来るものであり、我々はソースを信頼するので、これらのルートに対するバリデーションを無効にする必要があります。 Csrfバリデーションを無効にする必要があります。ミドルウェアは VerifyCsrfTokenミドルウェアはすべてのトークンのバリデーションに使われます。幸運なことに、ミドルウェアはすべてのルートのリストを含む except配列を受け取ります。この配列にはCSRF検証を無効にするすべてのルートのリストが含まれます。

以下のコードで app\Http\Middleware\VerifyCsrfToken.phpファイルを以下のコードで編集する:

protected $except = [
        '/webhooks/*'
    ];

次に、以下のコマンドを実行してコントローラを作成する:

php artisan make:controller WebhookController 

これで WebhookController.phpファイルを app\Http\Controllersディレクトリに生成される。そのファイルを以下のコードで編集する:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Jobs\ReportIncident;

class WebhookController extends Controller
{
    public function inboundMessage(Request $request)
    {
        return Log::debug('Inbound Message', $request->all());
    }

    public function status(Request $request)
    {
        return Log::debug('Status', $request->all());
    }

    public function report(Request $request)
    {
        Log::debug('Incident', $request->all());

        dispatch(new ReportIncident());

        return response('Webhook received');
    }
}

については inboundMessage()メソッドと status()メソッドでは、VonageからのリクエストデータをLaravelが提供するログファイルにログするだけです。と report()メソッドは ReportIncidentジョブをディスパッチします。このジョブは、Vonage API周りのカスタムWrapperを使って、SMS通知をトリガーする役割を担っています。

FacebookとVonageアカウントのリンク

VonageからFacebookにメッセージを送信するには、まずFacebookアカウントに関連付けられたFacebookページをVonageアカウントにリンクする必要があります。その方法は こちら.

リンクが完了したら、FacebookアカウントからFacebookページにメッセージを送信します。これはインバウンドメッセージなので、Vonageはメッセージの詳細を含むリクエストを先ほど作成した /webhooks/inbound-messageエンドポイントに送信します。ログファイルを確認すると、以下のようなエントリーがあるはずです:

Inbound Message{  
   "message_uuid":"0a2088d2-e028-4aa0-aa4a-ae11a6f82fb0",
   "to":{  
      "id":"1923256201474167",
      "type":"messenger"
   },
   "from":{  
      "id":"23037543461244470",
      "type":"messenger"
   },
   "timestamp":"2019-08-06T21:56:16.887Z",
   "direction":"inbound",
   "message":{  
      "content":{  
         "type":"text",
         "text":"Hello"
      }
   }
}

フェイスブックの送信者IDは to.id受信者IDは from.id.まもなく必要になるので、これらの詳細をメモしておこう。

カスタム・ラッパーの作成

このチュートリアルを書いている時点では、Dispatch APIはまだベータ版なので、Vonage PHPライブラリはまだサポートしていません。そのため、カスタムラッパーを使ってNexmoのAPIとやりとりすることになります。まず、APIの認証に使用するJson Web Token (JWT)を生成する必要があります。

使用方法 Vonage CLIを使用して、次のコマンドを実行します:

vonage jwt --key_file=./private.key --app_id=VONAGE_APPLICATION_ID

./private.keyは、Messages and Dispatchアプリケーションの作成時に生成された秘密鍵ファイルへのパスです。 app_idは先ほどメモしたアプリケーションIDです。次に、このコマンドの出力をコピーしてください。

環境変数と設定変数

先ほど生成したJWTを、SMSに追加します。 .envに、先ほど説明したメッセンジャーの詳細と、SMS通知の送受信を行う電話番号を追加します。

VONAGE_JWT = xxxx
FB_SENDER_ID = xxxx
FB_RECIPIENT_ID = xxxx
SMS_FROM = xxxx
SMS_TO = xxxx

次に、先ほど定義した環境変数を設定ファイルから参照する。設定ファイルの configディレクトリに移動し services.phpファイルの下に、新しいVonage array.

'vonage' => [
        'jwt' => env('VONAGE_JWT'),
        'fb_sender_id' => env('FB_SENDER_ID'),
        'fb_recipient_id' => env('FB_RECIPIENT_ID'),
        'sms_from' => env('SMS_FROM'),
        'sms_to' => env('SMS_TO')
    ]

依存関係のインストール

プロジェクトが持つ依存関係は GuzzleHTTPライブラリです。以下のコマンドを実行してライブラリをインストールします:

composer require guzzlehttp/guzzle

ラッパーの作成

その appディレクトリに Vonage.phpファイルを作成し、そこに以下のコードを追加する:

<?php

namespace App;

use GuzzleHttp\Client;

class Vonage
{
    protected $client;

    public function __construct()
    {
        $this->client = $this->setUpClient();
    }

    protected function setUpClient()
    {
        $authBearer = 'Bearer ' . config('services.vonage.jwt');

        return new Client([
            'base_uri' => 'https://api.nexmo.com',
            'headers' => [
                'Authorization' => $authBearer,
                'Content-Type' => 'application/json',
                'Accept' => 'application/json'
            ]
        ]);
    }


    public function dispatch()
    {
        $response  = $this->client->request('POST', '/v0.1/dispatch', [
            'json' => [
                'template' => 'failover',
                'workflow' => [
                 [
                    'from' => [ 'type' => 'messenger','id' => config('services.vonage.fb_recipient_id')],
                    'to' => ['type' => 'messenger', 'id' => config('services.vonage.fb_sender_id')],
                    'message' => [
                      'content' => [
                        'type' => 'text',
                        'text' => 'An incident just occurred',
                      ]
                     ],
                    'failover' =>[
                      'expiry_time' => 15,
                      'condition_status' => 'read',
                    ]
                   ],
                  [
                    'from' => ['type' => 'sms','number' => config('services.vonage.sms_from')],
                    'to' => ['type' => 'sms','number' => config('services.vonage.sms_to')],
                    'message' => [
                      'content' => [
                        'type' => 'text',
                        'text' => 'An incident just occurred',
                      ]
                    ]
                  ]
                ]
            ]
        ]);

        return json_decode($response->getBody());
    }
}

メソッドでは dispatch()メソッドで、フェイルオーバーテンプレートとワークフローを定義しました。PagerDuty経由でインシデントが発生するたびに、Facebook Messengerでインシデントに関する通知を受け取ります。通知が15秒以内に読まれなかった場合、フェイルオーバー条件がトリガーされ、フォールバックとしてSMS通知が送信されます。

仕事を作る

ターミナルで以下のコマンドを実行し、新しいジョブ・クラスを作成する:

php artisan make:job ReportIncident

以下のコードで app\Http\Jobs\ReportIncidentファイルを以下のコードで編集する:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Vonage;

class ReportIncident implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle(Voange $vonage)
    {
        $vonage->dispatch();
    }
}

この handle()メソッドは、先ほど作成したカスタムVonageラッパーを依存関係として受け取り、クラスのディスパッチ・メソッドを呼び出します。

すべてをひとつに

いよいよこれまで作ってきたものをテストする時が来ました。PagerDutyダッシュボードに向かい、新しいインシデントを作成します。

incidents screenshotincidents screenshot

これにより、PagerDutyアカウントに追加したエンドポイントにWebhook通知が送信され、Vonageアカウントに追加したFacebookページにメッセージが送信されます。すべてがうまくいったと仮定すると、Vonageが先ほど送信したメッセージのステータスのアップデートを送信しているはずなので、ログファイルを検査する必要があります。

{  
   "message_uuid":"c1bcf89b-c16e-427f-a4b7-15816327832f",
   "to":{  
      "id":"1923256201474167",
      "type":"messenger"
   },
   "from":{  
      "id":"23037543461244470",
      "type":"messenger"
   },
   "timestamp":"2019-08-08T01:53:07.922Z",
   "status":"read",
   "_links":{  
      "dispatch":{  
         "href":"v0.1/dispatch/15756412-30d6-4664-8a1e-abcd029ea7a4",
         "dispatch_uuid":"15756412-30d6-4664-8a1e-abcd029ea7a4"
      }
   }
},
{  
   "template":"failover",
   "status":"completed",
   "timestamp":"2019-08-08T01:53:07.959Z",
   "usage":{  
      "price":"0.003",
      "currency":"EUR"
   },
   "dispatch_uuid":"15756412-30d6-4664-8a1e-abcd029ea7a4",
   "_links":{  
      "messages":[  
         {  
            "message_uuid":"c1bcf89b-c16e-427f-a4b7-15816327832f",
            "href":"v0.1/messages/c1bcf89b-c16e-427f-a4b7-15816327832f",
            "channel":"messenger",
            "usage":{  
               "price":"0.001",
               "currency":"EUR"
            },
            "status":"read"
         }
      ]
   }
}

上記のログから、メッセージが読まれたことを知らせるステータス更新が最初にあり、その後、ディスパッチワークフローが完了したことを知らせる別のステータス更新がある。メッセージは15秒以内に読まれたので、フェイルオーバー条件は満たされた。

フェイルオーバー条件が満たされなかった場合にSMS通知が送信されることをテストするには、同じプロセスを繰り返しますが、今回はFacebookメッセンジャー通知を読まないでください。今度はSMS通知がトリガーされることがわかります。

結論

このチュートリアルでは、PagerDutyとVonageのカスタム統合を構築して、緊急時のフォールバック・アラート・システムを確保する方法を見てきました。Githubレポへのリンクはこちら こちら.

シェア:

https://a.storyblok.com/f/270183/250x250/d288ec8a73/dotun.png
Dotun Jolaoso

Software Developer who loves building awesome tools and products. I currently work with Laravel, PHP and Vue.