誰が為に戦うのか？ 〜PagerDutyと変身ベルト〜


@boscoworks です。
この記事は [2015年 Livesense Advent Calendar](http://qiita.com/advent-calendar/2015/livesense_1) 第18日目です。
きのうは @Outstrp の「[Rubyで簡単自動化(Confluence/Hipchat/Google Spreadsheets)](http://qiita.com/Outstrp/items/5be2a9c1bbf6415b5344)」でした。
[PagerDuty](https://www.pagerduty.com/) というサービスを使って障害通知をしているので、その事例について紹介しようと思います。

#話の概要
この記事は、ざっくり以下2点についてお話ししています。

1. PagerDutyをREST APIでトリガーする
2. PagerDutyをJenkins Pluginからトリガーする

# お前は誰だ
2014年12月に[リブセンス](http://www.livesense.co.jp/)にJOINすることになりまして、この1年は「[ジョブセンスリンク](http://job.j-sen.jp/)」という正社員転職サイトのバックエンド開発を担当しています。
最近ですと、[Web API開発をRailsでやったり](http://qiita.com/otyoppu/items/e5b0b6437fee045d6252)、PHPのレガシーコードを黙々とリニューアルしたり、システムアーキテクチャの刷新などを担当しています。
先月仲間になったメンバーがたまに[僕のターミナルをマトリックスにしてくる](http://qiita.com/sion_cojp/items/4c8579733deaab79e621)のですが、くじけずに生きています。

# PagerDuty とはなにか
一言で説明するなら「 **障害発生時のエスカレーションツール** 」です。
詳しくは公式ウェブサイトをご覧いただくと、様々な機能があることがわかるのですが、ざっくりまとめるとこんな感じです：

- サービスに障害が発生した時に、担当者に連絡をしてくれるサービス
- メールとかプッシュ通知とかは当然やってくれる
- 電話までしてくれる (サンフランシスコからかかってくる)
- [Nagios](https://www.nagios.org/) や [Mackerel](https://mackerel.io/ja/) などのハードウェア監視ツールとの連携が容易

## なぜ必要なのか？
特筆する必要はないかと思うのですが、個人的に思うところは以下2点です：

### あらゆるケースの障害を自動復旧させるのは不可能
サービスは（事業上ダウンタイムを設けていなければ）24時間365日稼動します。
その間に、ソフトウェアもハードウェアも絶えず変化します。

- 電気がずっと流れてるのでハードウェアは緩やかに（時には急激に) 磨耗していきます
- 最近のソフトウェアは小さな機能ごとに様々なサービスを使い分けていて自動的に通信したり更新したりします。一つのサービスやシステムが落ちると連鎖して障害が起きたりします

技術の進歩により、昨今では障害が発生しても、自動的に復旧させたり、問題が起きている部分を勝手に隔離したりする仕組みが整いつつあります。
とはいえあらゆる事態を想定した自動化は不可能(非現実的)であると考えます。
最終的には人が判断し、人が障害を取り除かねばならないのです。

### 速やかに確実にエスカレーションするには電話が一番良い
先述の通り、通知の仕組みには様々な方法があります。メールとかプッシュ通知とか、あとはHipChatやSlackでメンションを飛ばすとか。
これらの方法にはメリットがあるので当然導入されているのですが、デメリットもあります。

#### メール
- クライアントアプリによっては起動していないとメールを自動受信しない (iPhoneのデフォルトメールアプリとか・・・）
- 常に大量の通知メールを受け取っていると埋もれる (気がついてから読む、では遅い)

#### プッシュ通知
- 通知が短いし見落としがち（自分だけかもしれないけど・・・）

#### HipChatやSlackなどのチャットツールのメンション
- iPhoneのHipChatアプリの通知には以前からずっと不具合があり、メンションが飛んだり飛ばなかったりする（なぜ・どのような条件でそうなるのかはわからないが、事実として通知がこないケースが多々）

## なぜPagerDutyなのか
### 全社共通で導入されている仕組みである
仕組みを一本化すると

- 人事異動があっても学習コストがない
- 横断組織にいる人間が混乱しない

というメリットがあります。
「長いものには巻かれよ」とも言います。

### 他のツールとの連携が容易である
先述の通り nagios や mackerel などとの連携は非常に容易です。
正直このあたりはぐぐればたくさん出ます（この記事では触れません）
簡単なのはいいことですね。

### 費用面
あんまりしっかり競合サービスを調べたわけではないのですが、[Twilio](http://twilio.kddi-web.com/)と比べても安い気がします。
通知先の端末台数や、月間通知回数が少ないのであれば、Twilioのほうが安いかもしれないです。
最近の導入事例だとクックパッドさんはTwilioみたいですね。
自分たちにあったのを使えば良いと思います。弊社も予算的に見直すかもしれないですしね。

#### 参考文献：
- [アラートエスカレーションシステム"Waker"の紹介](http://techlife.cookpad.com/entry/2015/11/18/170634_1)
- [Mackerel と cookpad の Waker を連携させた](http://qiita.com/norisu0313/items/8e66f6b6adae60279d5f)


# PagerDuty をAPIでコールする
PagerDutyには[REST API](https://developer.pagerduty.com/documentation/rest)が準備されています。
これを使うことによって、プログラム内にPagerDutyによるインシデント通知の仕組みを取り入れることができます。
使いどころとしては、「1日1回動いている重要なバッチが失敗したら電話」みたいな感じでしょうか。
アイディアとしては検討したのですが、今の所これをプロダクトに導入していません。あくまでご参考程度に。

## APIコールに必要なもの
### API Access Key
1. PagerDutyウェブサイトにログインし、画面上部ナビゲーションバーの「Configuration」から「API Access」を選択します。
![pd1.png](https://qiita-image-store.s3.amazonaws.com/0/62697/f7527282-0f4c-518d-2fc9-c29b1b926ea5.png "pd1.png")

2. 画面右上部の「Create New API Key」でAPI Access Keyを発行します。
![pd2.png](https://qiita-image-store.s3.amazonaws.com/0/62697/62aa74d9-096c-d729-bd53-cb74d8b2efb7.png "pd2.png")

3. API Access Keyを控えます
注意書きがありますが、ここで発行されたKeyは、ダイアログを閉じると二度と見ることができません。必ず手元に控えましょう。
![pd3_censored.jpg](https://qiita-image-store.s3.amazonaws.com/0/62697/d4d6d838-3d78-34df-5c1e-46b3b9c3de93.jpeg "pd3_censored.jpg")

### Integration Key
1. PagerDutyウェブサイトにログインし、画面上部ナビゲーションバーの「Configuration」から「Services」を選択します。

2. 画面右上部の「+Add New Service」を押下します。
![pd4.png](https://qiita-image-store.s3.amazonaws.com/0/62697/6818b4f5-d348-b005-3ef7-d3494bdeb1fe.png "pd4.png")

3. Generic API Service用の設定を入力します

| 項目 | 補足 |
|:------|:------|
| General Settings | REST APIコールだとわかるように書くといいと思います |
| Integration Settings | Use our API directly を選択します |
| Incident Settings | Escalation Policyだけは間違えないようにしましょう。余所様に電話がかかってしまいます |
終わったらIntegration Key を控えます
忘れても何度でもみられます。再発行もできます。

## curl でコールしてみる
```
curl -sS "https://events.pagerduty.com/generic/2010-04-15/create_event.json" \
-X POST \
-H "Content-type: application/json" \
-d '{
    "service_key": "(Integration Key)",
    "incident_key": "2015-12-18 00:00:00",
    "event_type": "trigger",
    "description": "Test Trigger from PagerDuty API",
    "client": "PagerDuty REST API",
    "client_url": "http://job.j-sen.jp/"
}'
```
送信するデータは適当に読み替えてくださいね。

そして実行します。
**ﾋﾟｼｨ!!!**

```
{"status":"success","message":"Event processed","incident_key":"2015-12-18 00:00:00"}
```
↑こんな感じでレスポンスが返ってきたらPagerDutyでインシデントがトリガーされます。
数秒経つと電話がかかってきます。 **サンフランシスコから**。

### インシデント発生時のPagerDutyのようす
![pd5.png](https://qiita-image-store.s3.amazonaws.com/0/62697/29c068d6-5594-849e-fc58-1ce1061401e9.png "pd5.png")
こんな感じでトリガーされたインシデントが表示されます。

### 電話を受け取った時の操作方法
外国人男性が早口な英語でアナウンスしてくれますが、正直早口すぎて全然聞き取れません。
**4番のキー** を押すと「 **ACKNOWLEDGE** 」（障害は解決していないが認識した）、 **6番のキー** を押すと「 **RESOLVED** 」(障害は解決した)　です。

# PagerDuty をJenkinsから起動する
ジョブセンスリンクでは定期実行バッチの制御用GUIとしてJenkinsを使っています。
~~(そもそもJenkinsはCI用途で使用されるべきツールですが、我々の要件に対して手っ取り早く準備するのには最適なツールでした)~~
この定期実行バッチは1日1回動作するものですが、ユーザに価値を届ける上で事業上重要な仕組みであり、サービスレベルをさげづらいシステムでした。
なにかのトラブルで手動で再実行させたい場合、一刻も早く検知したいので、PagerDutyを組み込みました。

## Jenkins にPagerDuty Plugin をインストールする
- https://wiki.jenkins-ci.org/display/JENKINS/PagerDuty+Plugin

## Jenkinsのジョブの設定をする
ジョブの実行が失敗した時にPagerDutyをコールするには、「ビルド後の処理の追加」から「PagerDuty Incident Trigger」を選択し、以下のように入力します。
![jenkins1.png](https://qiita-image-store.s3.amazonaws.com/0/62697/6f9fc677-74e1-1e53-1947-fb3ad2ea41a9.png "jenkins1.png")

### 注意すべき事項
| 項目 | 補足 |
|:------|:------|
| API Key | Integration Keyを入力してください。Access Keyではないです。(これでだいぶはまった) |
| Incident Description | ここの部分を外国人男性が読み上げてくれます。ジョブの名前を入れておくと読んでくれて便利そう。ヒヤリング力ないと聞き取れませんが。|
| Trigger Incident on SUCCESS job result | これにチェックを入れるとビルド結果の成否にかかわらず問答無用で電話がなります。不用意にチェックを入れないほうがよいでしょう。 |

### 得られた効果
不安定な環境とシステムが影響して、事業上重要な割に月に1回はビルド実行失敗による売上毀損が発生していたのですが、このプラグイン導入により、それが **売上毀損ゼロ** になりました。
（当然アプリケーション側の改善も相乗効果としてあったことは追記しておきます）

# PagerDuty が生み出した悲劇
PagerDutyにより、障害に対する一早い検知と、それに対する初動が劇的に改善しました。
ただ、この施策により思わぬところで二次災害が発生し、対策を余儀なくされました。

## 発生した二次災害
- 自宅の中で深夜休日問わず突然鳴り響く障害通知のアラート音に対して同居人から苦情 ( **緊急度: 高** )

## 二次災害の原因
- iPhoneだけでなく、自宅に置いているiPadにも電話がかかる仕組みになっているが(Apple IDが同じなため)、iPhoneがマナーモードでも気づけるよう **音量最大にしてサイレン音を鳴らしていた**

## 反省文
- システム障害の初動の重要性を言い訳にして、プライベートな空間を緊迫した状況に一変させてごめんなさい。

# 家庭の平和と事業の安定を両立する
上でも少し書きましたが、 **システム障害において初動の素早さと正確さは重要**です。
ただ、これを読んで共感されているであろう読者のエンジニアの皆さんは、きっと「システム開発のために生きている」のではなく「 **生きるためにシステム開発をしている** 」方がほとんどだと思います。
生活を守る。家族を守る。そのために我々は日々汗水を垂らしてシステム開発をするのです。
**障害対応のために家庭を犠牲にするなんてありえない**のです。
でも障害を直さなければ売上が毀損し、ゆくゆくは自分たちの生活を脅かすのです。これがジレンマ。

## 障害検知は怖くない
同居人はエンジニアではありません。
どんな理屈を並べても、自宅に帰ってさながらボランティアのように障害対応をする自分を快く思わないでしょう。
ご家庭を持つ多くのエンジニアの方が、似たような悩みをお持ちだと思います。
けれど障害は常に起きるし、起きたら対応しなくてはならない。
要は障害検知が怖くなければいいのです。
![ipad.PNG](https://qiita-image-store.s3.amazonaws.com/0/62697/815f2ca8-6bcf-e777-e08e-7b4367ed6eb6.png "ipad.PNG")
iPadのほうの **着信音を仮面ライダーの変身ベルトの音にする！**
_(僕はディケイドとカブトが好きなんだけど、目立つ音で明るいイメージがよいと思い電王ソードフォームにしました)_

~~電王？変身ベルトの音？なんのことよ？という方は、某動画サイトなどで調べてみるといいと思います・・・~~

さぁ！　障害は怪人、あなたはヒーロー！！
電話を取ったら、そこから先は平和のために戦うのみです！！


**「変身！！！」**

・・・もはやネタがわからないひとにとってはスベった感半端ない流れですが、続けます。

## 得られた効果
1. ちょっとだけ空気が軽くなった
決して許されてる空気ではないのですが、「あ、電王なったー」みたいな感じで、 **少しだけマイルドに障害を検知**することができるようになりました。

2. 同居人が障害検知するようになった
自分が風呂掃除している間、携帯も手元になく、iPadの音も聞こえない状況で障害が起きる悲惨な状態が先日発生したのですが、仮面ライダー電王の音を聞いた同居人がわざわざ伝えに来てくれるようになりました。
結局家族総出で障害対応。検知すらも最後は人の手が一番早く確実なのです。つらい・・・

# 哀しき戦士たちが忘れてはならない、3つの心がけ
障害はないほうがよいのです。
休みは家族のために心血をそそぐべきなのです。
あぁ、それでも障害は起きる。どうしても起きる。だから誰かが戦わないといけない。

## 家族に感謝する
仕事に費やすだけ費やしたら、残りの全てを家族に費やして、 **ありったけの感謝**をしましょう。
あなたが障害対応をしたせいで、あなたと過ごす時間を失った人がいるのです。 **失った時間の3倍は幸せに**しましょう。

## 後悔しない
きっと障害対応をするエンジニアのなかにはこんなひとがいるでしょう。

- 勤怠の仕組みがわずわらしすぎて結局ボランティアだ
- 売上に貢献しないから評価されない
- マイナスをゼロに戻すだけだし、技術力をアウトプットできない

あなたが血と汗と涙を流しながら障害対応をしても、その貢献は、届けたい人に届かないかもしれません。
でも、あなたが戦ったおかげで、 **インターネットの向こうにいる誰かには少しでも価値が届いている**のです。
安心してください。あなたの後ろには、もう誰もいないのです。 **迷うことなく全力で障害を復旧させてください。** 1分1秒でも早く。

## 日頃から訓練する
### サービスの隅々まで目を配る
ソフトウェアもハードウェアも、事業施策も人員配置も、サービスを構成するありとあらゆる要因に、常日頃から目を配りましょう。 **無関心が一番の敵**です。

### 技術力を上げる
サービスが成り立つうえで必要とする技術は幅広くあります。
**すべてエキスパートになる必要はありません。** 赤点とらない程度にはいろいろ知っておくよう、普段から勉強しましょう。

### イメージトレーニングする
だいたいイメトレできてないようなやつが大災害になります。
でもそれはしょうがないのです。あなたの限界です。
**なにも一人で戦う必要はないのです。**無理だったら誰かに助けを求めましょう。

# 最後に
後半だいぶエモい話になりました。
PagerDutyは便利なエスカレーションツールです。それを組み合わせることで、可能な限り迅速な対応を実現することができるでしょう。
ただ、 **大事なのは障害を起こしにくいシステムを作ること**なのです。そうすれば、障害対応をするエンジニアの休日は守られるのです。
誰の為に戦うのか。
エンジニアのみなさん、あなたのその腕を、どんなことに使いますか？

以上、お粗末様でした。

明日は @yut_h1979 が、僕よりもうちょっとまともな話をしてくれます。