初めましての方もご存知の方もこんにちは。
リブセンスで アルコール駆動開発 を提唱し続けているインフラエンジニア、@Etsです。
さっきまでビールを3パイントほど飲んでいたところからこの記事の執筆をスタートしています。
現在の時刻は2016/12/07 02:16。アルコールの力で生産効率が倍増!!
・・・を通り越して 超眠い です。頑張ります。
なお、これは『Livesense Advent Calendar 2016』の8日目の記事です。
昨日は@xorphitusさんの『Lispってどう書くの?』でした。
ちなみに弊社は3本同時アドベントカレンダーという凶行を実施しています。
- Livesense Advent Calendar 2016 その1
- Livesense Advent Calendar 2016 その2
- Livesense Advent Calendar 2016 その3
他2本のカレンダーもよろしくお願いします。
はじめに
タイトルがもう全てなのですが、書かせてください。
この記事の背景とゴール
誰かが言ったわけです。
サーバーにログインしてオペレーションするのは今やイケてないよね。
インフラエンジニアたるもの、問題が起きたらサーバーにログインして調査ってのは基本です。ですが、気持ちはわからなくないですよね。
例えば、 深夜のアラート対応 とか。
アラートの中にはどう考えても 「プロセスを再起動しておけばOK」 なものはあります。
でも、ベッドから起きて、VPN繋いで、SSHして、再起動して・・・なんてことをしていたら、目もしっかり覚めて寝不足になってしまいます。
完全に自動復旧をさせるのは怖い・・・でも、明らかにどうでもいいアラートだったら、
サーバーにログインすることなく、ささっとプロセス再起動程度のオペレーションがしたい ものです。
手軽と言えば、やっぱイマドキなのは ChatOps ですよね。
本記事は、サーバーにログインすることなく 「チャットのような手軽な方法でApacheプロセスの再起動」 を実現することをゴールにしようと思います。
技術選定
Neptune.io流行ってますよね。Qiitaでもこんなにも投稿があります。
・・・嘘です、将来に期待して先にリンクを張りました。
このサービスの最大のメリットは 「オンプレを含む各種環境のサーバーに対して、Webhookなどのインタフェースを通じて、PUSHで処理を送ることができる」 点にあります。
監視サービスと組み合わせて、障害発生時のファーストアクションを自動化したり、自動復旧を実現しようという趣旨ですね。
Webhookなんて簡単なインタフェースがあれば、色々できそうな気がしますね。
これを実装の核に採用します。
準備: Neptune.ioとサーバーの連携
ここではVagrantで構築したCentOS6.8を検証環境として手順をまとめています。
僕が前回書いた記事を繰り返すような内容ですが、約1年ぶりということで改めて記述していきます。
この作業によってNeptune.ioと繋ぎこんでChatOps可能にするサーバーを、本記事では 『hostA』 と呼ぶことにします。
neptune-agentdのセットアップ
インストール
Neptune.ioのサイトにログインして、[SEVERS]->[Add agent to your server]と辿って、手順に従ってインストールしましょう。
・・・というか掲示された手順を対象のサーバーへコピペすれば良いです。
$ AGENT_USER="neptune" API_KEY="xxxxxx" bash -c "$(curl -sS -L https://raw.githubusercontent.com/neptuneio/neptune-agent/prod/scripts/linux/install_neptune_agent_linux.sh)"
(中略)
Agent is running with pid 1332
-------------------------------------
To check agent status : sudo service neptune-agentd status
To stop agent : sudo service neptune-agentd stop
To start agent : sudo service neptune-agentd start
To restart agent : sudo service neptune-agentd restart
To uninstall agent : sudo service neptune-agentd uninstall
Agent log available at : /home/neptune/agent/neptune-agent.log
-------------------------------------
※以前と変わって、ユーザー名が「neptune」とシンプルになってますね。
インストールすると、エージェントは自動的に起動します。しばらくすると、Neptune.ioのサイトの[SERVERS]のページに対象のホストが並ぶのが確認できるはずです。
sudoers設定
neptune-agentdの実行ユーザー「neptune」が特権でコマンドを実行できるように、sudoersを作っておきます。
$ vim /etc/sudoers.d/11_neptuneio
Defaults:neptune !requiretty
neptune ALL=(ALL) NOPASSWD:ALL
本当は必要なコマンドだけ許可しておけば良い のですが、ここでは雑に設定しています。
WebhookによるRuleを作る
Ruleを作成する
Neptune.ioのサイトにて、[Rules]->[Create Rules]と辿って新規Ruleを作成しましょう。
今回は話をシンプルにするために 1Host:1Rule の関係でRuleを定義します。
その気になれば複数のホストに同時にアクションを実行させることもできるようですが、ここでは割愛します。
- Trigger source: webhook
- Target type: SPECIFIC_HOST
- Host name: ["neptune-agentdを入れたホスト"]
- Runbook: 以下参照
echo "$(date) sudo ${command}" >> /tmp/neptune.log.$(date +%Y-%m-%d)
sudo ${command}
いやぁ・・・ 説明不要なくらいリスクを抱えたコード ですね。
本番系でこんなコードが動いていたらゾッとしますが、このまま突き進みます。
curlでの動作確認
ここまで来たらcurlでまずは動作確認しましょう。
$ curl -H "Content-type: application/json" -X POST "https://www.neptune.io/api/v1/trigger/channel/webhook/xxxx......" -d '{ "MetaData" : { "command" : "tail /var/log/messages"}}'
うまく動いたでしょうか?
うまく動けばメール等で通知も来るはずです。
正常動作すれば、本来閲覧には特権が必要なはずの/var/log/messages
の内容が、Neptune.ioのGUIの[Rule]上で見れるかと思います。
Ruleで定義したsudo
経由のコマンドが実行されたわけですね。
見て分かる通り、 MetaData
で与えたcommand
変数の内容が、Runbookのスクリプトに渡されて実行 されています。
commandに渡したものが問答無用に実行されるのです。 クレイジーだぜ。
ここまでの作業で HTTPでリクエストを送ればなんでもできる 準備が整いました。
大事なことなので書いておきますが、 このRuleはセキュリティホール以外の何物でもないので、このまま本番利用したときの責任は取れません ので真似しないでくださいね。
Siriにオペレーションしてもらう
今、ChatOpsどこ行った?って思いましたよね。
・・・ここまで書いて力尽きて寝てしまったので時間がなくなったのです。
仕事もしていたので 2016/12/08 00:00まで、あと3時間しかありません。
ChatOpsなんて前座は書いている暇がありません。ヤバイです。
技術選定
Siriに命令を出す方法は幾つかありますが、今回は比較的自然言語を理解してくれるHomekitを経由して命令を送り込もうと思います。
Homebridgeは、Homekitに対応した仮想デバイスとして振る舞うサービス兼フレームワークです。
様々なプラグインが公開されており、そのうちの1つにcmdSwitch2があります。
cmdSwitch2は、Homebridgeを経由して特定のコマンドを実行するためのプラグインです。
・・・もう見えてきましたね。
Homebridge + cmdSwitch2を準備
Homebridge界隈は色んな人が記事を書いているので、ざっくりと手順を書いていきます。
ここでは、MacにHomebridgeとcmdSwitch2を入れる手順を書いていきます。
nodebrewをインストール
HomebridgeはNode.jsで動いています。nodebrewを利用してNode.js環境を整えましょう。
### インストール
$ curl -L git.io/nodebrew | perl - setup
### パスを追加する
$ vim ~/.bash_profile
# nodebrew
export PATH=$HOME/.nodebrew/current/bin:$PATH
### ロードする
$ . ~/.bash_profile
Homebridgeをインストール
ここも駆け足で書いていきます。躓いた時は、丁寧な人の説明を探して読んで下さい。
### stableバージョンのNode.jsを入れる
$ nodebrew install-binary stable
$ nodebrew use stable
### Homebridgeとhomebridge-cmdswitch2を入れる
$ sudo npm install -g homebridge
$ sudo npm install -g homebridge-cmdswitch2
Homebridge自動起動用plistファイルを記載する
Macでlaunchctl
を使用してHomebridgeをdaemon化するために、以下のような設定ファイルを作っておきます。
$ vim ~/Library/LaunchAgents/com.bridge.server.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>com.homebridge.server</string>
<key>ProgramArguments</key>
<array>
<string>/Users/YOURNAME/.nodebrew/current/bin/homebridge</string>
<string>-U</string>
<string>/Users/YOURNAME/.homebridge</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/Users/YOURNAME/.nodebrew/current/bin:/usr/local/bin/:$PATH</string>
</dict>
</dict>
</plist>
※ YOURNAME
部分にはあなたのユーザー名を入れて、ちゃんとパスを通しましょう。
これで、以下のようなコマンドでdaemon化することが出来ます。
$ launchctl load ~/Library/LaunchAgents/com.bridge.server.plist
Homebridgeの設定ファイルを記載する
Homebridgeの設定ファイルを作りましょう。
$ vim ~/.homebridge/config.json
JSONでこのような設定を作ります。
pin
はHomekitで使用しますので覚えておきましょう。
{
"bridge": {
"name": "Homebridge",
"username": "PCのMACアドレス",
"port": 51826,
"pin": "123-45-678"
},
"platforms": [
### この部分は後述します
]
}
この時点で、Homebridgeを起動して、iPhoneなどのiOSデバイスでHomekitを起動すれば、「Homebridge」という名前のデバイスが見つかるはずです。
登録時にはPINコードを求められますが、これは先程の設定ファイルのpin
を手動で打てばOKです。
しかし、まだ何もデバイス(プラグイン)が設定されていませんので、起動しても意味はありません。
curlコマンドをスクリプト化
後述しますが、JSON中に長いcurlコマンドを埋め込みたくないので、単純なBASHスクリプト『hostA_apache.sh』を予め用意しておきます。
#!/bin/bash -
ACTION=${1}
curl -H "Content-type: application/json" -X POST "https://www.neptune.io/api/v1/trigger/channel/webhook/xxxx..." -d '{ "MetaData" : { "command" : "service httpd '"${ACTION}"'"}}'
実に酷いスクリプトですね。
動作確認しておきましょう。
$ bash hostA_apache.sh stop
$ bash hostA_apache.sh start
hostAでApacheの再起動が走ったでしょうか?
先程Neptune.ioに設定した酷いRule、酷いRunbookを経由して、hostAでservice httpd xxxx
コマンドが実行されたわけです。
Homebridgeにスクリプトを連動させる
Homebridgeの設定ファイルのplatforms
部分に以下の設定を追加しましょう。
"platforms": [
{
"platform": "cmdSwitch2",
"name": "CMD Switch",
"switches": [
{
"name" : "Neptune.io hostA Apache",
"on_cmd": "bash /path/to/hostA_apache.sh start",
"off_cmd": "bash /path/to/hostA_apache.sh stop",
"state_cmd": "curl -s -I http://hostAのIPアドレス/",
"polling": true,
"interval": 30
}
]
}
]
先程のスクリプトは、このように設定の中で使用されています。
※ /path/to
部分にはスクリプトを配置したディレクトリへのパスを書きましょう。
ポイントは、cmdSwitch2のswitches
の設定に
-
on_cmd
として先程のBASHスクリプトをstart
オプションで指定していること -
off_cmd
として先程のBASHスクリプトをstop
オプションで指定していること -
state_cmd
としてcurlでApacheの動作確認を入れていること
です。
名前から推測できるように、それぞれデバイスの「ON」「OFF」「状態確認」に対応しています。
なお、状態確認コマンドは省略しても良いようです。
もっと高度に、監視サービスなどを突いても良いでしょう。
Homebridgeを起動する
Daemon化する場合は以下です。load
の代わりにunload
すれば停止できます。
$ launchctl load ~/Library/LaunchAgents/com.bridge.server.plist
初回はフォアグラウンドで動かしたほうがデバッグしやすいでしょう。
フォアグラウンドで動かすときは、以下でOKです。
$ homebridge
明示的に設定ファイルを読み込ませたければ以下のようにオプションを付けます。(plistの記載と同じ指定になりますね)
$ homebridge -U ~/.homebridge
Homekitに認識させる
iOSデバイスでHomekitアプリを起動しましょう。
HomebridgeをセットアップしたMacと同じネットワークに繋がっていれば、[アクセサリの追加]からHomebridgeを見つけることができるはずです。
更にその中を開けば、『Neptune.io hostA Apache』というデバイスが表示されているはずです。
state_cmd
がちゃんと機能して、今Apacheが動いていることも状態として取れていますね。
お疲れさまでした。 これで準備は整いました。
さぁ試そう
まずはGUIで動かす
Homekitのアプリ上で『Neptune.io hostA Apache』のスイッチをオン・オフしてみましょう。
hostAのApacheが起動・停止するのが確認できたでしょうか。
これが上手くいかないようであれば、何かHomebridgeの設定にミスがあります。
Homebridgeの設定を見直しましょう。
うまく動いた人は、 いよいよSiriOpsをする時です。
SiriOpsを試す(1)
ホームボタンを長押ししてSiriを呼び出しましょう。
落ち着いて、声をかけましょう。
僕「Neptune.io hostA Apacheの電源を切って」
Siri『すみません、よくわかりません』
まだ頑張ったほうだよ、Siri・・・!!
分かる分かる。無理だよね。
期待してはいなかったよ。
むしろ、 Apacheと認識できる のにびっくりしたよ。
名前を変えましょう
デバイス名をHomekitアプリから変更することが出来ます。
なるべく発音が困難じゃない名前 にするのがSiriに優しい設定です。
僕は『テストサーバーのApache』というデバイス名に変更しました。
SiriOpsを試す(2)
再度SiriOpsを試しましょう。
状態確認
ホームボタンを長押ししてSiriを呼び出しましょう。
落ち着いて、声をかけましょう。
「テストサーバーのApacheは点いている?」
おぉぉ!動いた!
ちなみに「点いている?」と質問したのは、SiriはcmdSwitch2デバイスを 家電か何かのスイッチ として認識しているからです。家電に対しての質問のように話しかけるとSiriはスムーズに応答してくれます。
プロセスを停止->起動する
再びSiriに話しかけます。
「テストサーバーのApacheを切って」
hostAのApacheが停止することを確認できました。
「テストサーバーのApacheをオンにして」
hostAのApacheが起動することを確認できました。
完璧です。
連続で命令してみる
もう失敗することはないですね。
Siriに話しかければ、hostAのApacheは起動したり殺されたりされたい放題です。
深夜に起こされても、Siriに再起動が依頼できちゃうわけです。
もう起こされてがっかりするアラートも怖くないですね。
あとがき
現在時刻
現在時刻は、2016/12/07 23:04です。間に合った!!
雑な部分、タイポや間違いがあったら後で直しておこうと思います。が、最初のリリースが間に合うことが大切ですよね。
Apache?
本記事でApache httpdを『Apache』と呼んでいるのは嫌な感じを受ける人もいるかもしれません。
すみません、全てSiriのためです。
『httpd』という呼称を使っていたら、きっと
「テストサーバーのApache」は、
「テストサーバーのエイチティーティーピーディー」 という名前にしておかなければならなかったでしょう。
正確に発音する自信が僕にはありません。
テキストだらけでごめんなさい
Siriのくだりは動画を撮ればわかりやすかったですね。
時間がなかったのです、文章と画像で許してください。
明日は
t_horiさんのアドベントカレンダー9日目の記事です。