うどん大学 情報系 院1年の堀内です.
勢いで Sensu Advent Calendar を立てましたが,無事埋まっていてホッとしています.
SensuはAnsibleと同時期に使い始めました.
現在は,研究室のサーバ監視に使っています.
もくじ
- Sensuとの出会い
- 研究室のサーバ監視で
- handlerとしてのAnsible
Sensuとの出会い
「研究室でAnsible使ってる話」でも書きましたが,8月末にヤフーのインターンシップに参加しました.
そこでSensuが使われているのを見せて頂き,興味を持ったのがキッカケです.
ホテルに戻ってから,試してみようと作業していたのを覚えています.
(Ansibleを使ってsensu-clientを流し込もうと四苦八苦.)
ヤフーでの取組みはAdvent Calendarに書かれています.
研究室のサーバ監視で
研究室にはVMを含めて20台以上のサーバがあります.
そこにAnsibleを使ってsensu-cluentを流し込み,監視しています.
監視項目はCPUやメモリ,HTTPなど,基本的なものだけです.
community-plugins もしくは,その機能を削って使っています.
metricsはElasticsearchに投げて,Kibanaで可視化しています.
(fluentdなどを介さず,handlerから直接投げています.)
また,研究室で Typetalk を使っているので,Hubotを使ってアラートを投げたりもしています.
handlerとしてのAnsible
ここからが本題です.
例えば,SensuのHTTPチェックでCRITICALが発生したとします.
そこで,handlerからWebサーバを再起動するためにAnsibleを使ってみます.
(ついでに,Typetalkに再起動の通知も出します.)
発生したアラートはこんな感じ.
{
"client":{
"name": "web-server-01",
"address": "192.168.11.10",
"subscriptions": ["webservers"],
"timestamp": 1326390159
},
"check":{
"name": "check-http",
"issued": 1326390169,
"output": "HTTP CRITICAL: HTTP/1.1 503 Service Temporarily Unavailable",
"status": 2,
"command": "etc/sensu/community-plugins/plugins/http/check-http.rb -r -u http://localhost/",
"subscribers":["webservers"],
"interval": 60,
"handler": "ansible",
"history": [],
"flapping": false
},
"occurrences": 1,
"action": "create"
}
まず,このアラートを受ける/etc/sensu/plugins/ansible_handler.rb
を作ります.
#!/usr/bin/env ruby
# Sensu Ansible Handler
require 'sensu-handler'
class AnsibleHandler < Sensu::Handler
def playbooks
settings['ansible']['playbooks'] || '/etc/sensu/playbooks'
end
def typetalk_vars
{
client_id: settings['ansible']['typetalk_client_id'],
client_secret: settings['ansible']['typetalk_client_secret'],
topic: settings['ansible']['typetalk_topic']
}
end
def generate_hostfile(event)
client = event['client']['name']
address = event['client']['address']
check = event['check']['name']
hostfile = "/tmp/#{Time.now.strftime '%y%m%d%H%M%S'}.hosts"
typetalk = typetalk_vars
File.open(hostfile, 'w') do |f|
f.puts "[#{check}]"
f.puts "#{client} ansible_ssh_host=#{address}"
f.puts "[#{check}:vars]"
f.puts "typetalk_client_id=#{typetalk[:client_id]}"
f.puts "typetalk_client_secret=#{typetalk[:client_secret]}"
f.puts "typetalk_topic=#{typetalk[:topic]}"
end
hostfile
end
def handle
status = @event['check']['status']
occurrences = @event['occurrences']
return if status < 2 || occurrences > 1
hostfile = generate_hostfile @event
check = @event['check']['name']
result = `ansible-playbook -i #{hostfile} #{playbooks}/#{check}.yml`
unless $?.to_i == 0
puts result
end
File.delete hostfile
end
end
handlerの設定ファイル/etc/sensu/conf.d/handler_ansible.json
は下記の通り.
{
"ansible": {
"playbooks": "/etc/sensu/playbooks",
"typetalk_client_id": "abcdefghijklmnopqrstuvwxyz123456",
"typetalk_client_secret": "abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz123",
"typetalk_topic": 1234
},
"handlers": {
"ansible": {
"type": "pipe",
"command": "/etc/sensu/handlers/ansible_handler.rb"
}
}
}
ansibleで実行する/etc/sensu/playbooks/check-http.yml
.
Nginxの再起動と,Typetalkの通知のみでシンプルにします.
---
- hosts: check-http
sudo: yes
tasks:
- name: restart nginx
service:
name=nginx
enabled=yes
state=restarted
- name: notify to typetalk
typetalk:
client_id={{ typetalk_client_id }}
client_secret={{ typetalk_client_secret }}
topic={{ typetalk_topic }}
msg='[sensu] restart nginx on {{ ansible_hostname }}'
後は,実際に対象サーバのNginxを止めると,Ansibleが実行されるはずです.
こんな感じで Huboco ちゃんが通知してくれます.
まとめ
今ハマっているSensuとAnsibleを組合せる方法を紹介しました.
今回はNginxでしたが,AnsibleでRailsをデプロイ しているので,こちらも対応させたいなと思います.
また,この記事のhandlerはGitHubで公開しています.
コメント・プルリクお願いします!