
最近原稿の締め切りが追いかけてくる夢をよく見る@cubicdaiyaです。今回はその逃避の一環として定番のチャットツールであるSlackのメルカリでの活用法について紹介します。
メルカリでのSlack活用
多くのエンジニア組織がそうであるようにメルカリではSlackを単なる社内チャットに留まらず、所謂ChatOps的な用途にも活用しています。
たとえばメルカリではサーバの監視のためにZabbixを利用していますが、bot ack allとSlackで入力すると現在起きているすべての障害をAcknowledgedな状態にできます。

さらに、bot test masterとSlackで入力するとAPIサーバのテストが走ります。

さらにさらに、bot helloとSlackで入力すると自宅からでも出勤したことにできます。

なお、この時はうるう秒に備えて自宅で待機していたのでした。

ほかにもSlackからデプロイを行うための仕組みなどもありますが、長くなるのでそれはまた次の機会に紹介したいと思います。
Slackプロキシサーバの需要
上記のSlackボットからだけでなくメルカリではプロダクションに投入されているさまざまなサーバからSlackにメッセージがポストされます。以下はその一例です。
- crontabに登録されたバッチの実行エラーの通知とそのエラー内容
- Norikraが検知したイベントとその内容
- Zabbixが検知したアラートとその内容
これらに関連した処理や設定は複数のサーバに散らばっているので各サーバから直接Slackにメッセージをポストするのは運用管理上の問題を抱えることになります。何故ならクライアントがSlackにメッセージをポストするにはAPIトークンかIncoming WebhooksのURLを知っていなければならないからです。
そのため、このどちらかを各サーバに配置するか、HTTPサーバ等を利用して各サーバから参照可能な場所に配置する必要があります。
Incoming WebhooksのURL情報を各サーバに配置する

Incoming WebhooksのURL情報を各サーバから参照可能な場所に配置する

Slackプロキシサーバの導入
昨年まではメルカリでも各サーバ毎にIncoming WebhooksのURLを埋め込んだ各通知プログラムが散らばっていました。そして、ある日諸事情により大元のIncoming WebhooksのURLを変更した数日後いくつかのサーバで変更漏れがあり、とあるログをストレージサービスにインポートするプログラムの実行エラーがSlackに通知されていないのが発覚するなどインシデントが発生しやすい状態でした。
また、Slackへメッセージをポストする各プログラムの実装言語がバラバラなことも運用管理の煩雑さに拍車をかけていました。
こういった事情もあり、現在はSlackのプロキシサーバを立ててそのプロキシと通信するクライアントコマンドを各サーバに配置するという構成に移行しています。

このプロキシサーバとその付属ツール群が次に紹介するslackboardです。
slackboard
slackboardはGoで書かれたSlackのプロキシサーバで以下の3つのプログラムで構成されています。
| プログラム名 | 解説 |
|---|---|
| slackboard | Slackのプロキシサーバ |
| slackboard-cli | slackboardにメッセージをポストするプログラム |
| slackboard-log | プログラムの実行に失敗した時だけslackboardにメッセージをポストするプログラム |
slackboardを起動するには設定ファイル(TOML)が必要です。最小設定では以下のようにslackboardがlistenするポート番号(port)とSlackのIncoming WebhooksのURL(slack_url)を記述します。
# slackboard.toml [core] port = "29800" slack_url = "https://hooks.slack.com/services/..."
チャンネルにタグを付けたり通知アイコンを変更することもできるのですが、もっと詳しく知りたい方はslackboard/CONFIGURATION.mdを参照してください。
-cで設定ファイルを指定してslackboardを起動します。
$ slackboard -c slackboard.toml
slackboardはSlackのIncoming WebhooksのURLを知っているので、各サーバに配置されたslackboard-cliは
単にSlackにポストしたいメッセージをslackboardにポストするだけでよく、通知プログラム側でIncoming WebhooksのURLを埋め込む必要はありません。
実際にslackboard-cliでslackboardを経由してSlackにメッセージをポストするのは以下のようにパイプ経由でメッセージをslackboard-cliに渡します。
$ echo slack-proxy | slackboard-cli -s slackboard-host:29800 -c #tech-test -u cubicdaiya
上記のコマンドを実行するとslackboard(slackboard-host:29800)がslackboard-cliからのメッセージを受信してSlackの#tech-testチャンネルにメッセージをポストします。

これで通知プログラム側でSlackのIncoming WebhooksのURLを知らなくてもSlackに簡単に通知できるようになりました。
slackboard-logでプログラムの実行失敗時にのみSlackに通知する
slackboardとslackboard-cliを利用することでSlackに気軽にメッセージをポストできるようになりました。
しかし、時々プログラムの実行に失敗した場合にのみSlackに通知してほしいことがあります。
例えばgsutilでGoogle Cloud Storageにログをインポートする場合を考えてみましょう。
滅多に起こりませんが、外部サービスとネットワーク通信するので失敗する場合を考慮しなければなりません。
なので失敗した場合だけslackboard-cliでSlackに通知する処理をシェルスクリプトで書いてみます。
# copy log file to Google Cloud Storage
gsutil cp /data/${data_log}_20150505.log.gz gs://${bucket}/
result=</span><span class="synStatement">echo</span><span class="synConstant"> </span><span class="synPreProc">$?</span><span class="synSpecial">
if [ $result -ne 0 ];
then
echo "@channel: failed to copy log to Google Cloud Storage(${date_log})." | \
slackboard-cli -s slackboard-host:29800 -t error-gcs
exit
fi
このやり方は汎用的である一方少し煩雑です。そして私は記憶力が悪く未だにシェルスクリプトのif文を素で書くことができないので毎回ググる羽目になります。
次にcrontabに書かれたスクリプトの実行が失敗した際にSlackに通知したいとします。
0 6 * * * some-command some-args
some-commandをラップしてsome-commandが失敗した際にSlackに通知するロジックを埋め込ることができれば便利です。
似たようなことをするツールにcronlogがあります。
0 6 * * * cronlog -- some-command some-args
cronlogはQ4Mやh2oの開発者である@kazuhoさんがgithubで公開しているkaztoolsに含まれるコマンドユーティリティです。上記のようにcronlogをはさむとsome-commndが失敗した(リターンコードが非ゼロの)ときにだけ実行結果を標準出力や標準エラー出力に吐くことができます。
slackboard-logはsome-commandが失敗した(リターンコードが非ゼロの)ときにだけslackboard経由でSlackにエラー内容を通知するプログラムです。
0 6 * * * slackboard-log -s slackboard-host:29800 -t error-some -- some-command some-args
例えば、存在しないファイルをlsしようとするとエラーになりますが、
$ ls notfound ls: notfound: No such file or directory $ echo $? 1 $
これにslackboard-logをはさんでみます。
$ slackboard-log -s slackboard:29800 -c #tech-test -u cubicdaiya -- ls notfound
するとこんな風にSlackに通知されます。

ところで、メルカリでは@kazeburoさんがPerlで書いたslacklogというslackboard-logと同じ用途のプログラムの方が主流だったりします。(slacklogの方がslackboard-logよりも先に実装されて投入されたので)
slackboard-cliやslackboard-log、slacklogはslackboardのHTTPベースのAPIを元に通信しているので新たにslackboardと通信するクライアントを作るのは難しくありません。興味のある方はslackboard/SPEC.mdをご覧下さい。
まとめ
メルカリでのSlackとSlackのプロキシサーバであるslackboardの活用の仕方について解説しました。
Slackへの通知を直接ではなくプロキシを介して行うのには以下のメリットがあります。
- Slackへの通知設定をプロキシサーバで一元管理できる
- 各サーバに散らばったSlackへの通知プログラムを一本化できる
- Slackへのメッセージのポストをロギングできる
slackboardはこういった目的を達成するために開発しました。元々は昨年末の冬休み初日に設定変更漏れに気付いた直後ついカッとなって1時間で書いたものですが、使ってみたら思いのほか便利だったので年明けに本番投入して今に至ります。
それでは快適なSlackライフを。



