使用 Monit+Mina 監(jiān)控服務(wù)器

服務(wù)器不上個(gè)監(jiān)控總是沒有安全感抹缕,偶爾出點(diǎn)問題荔泳,追蹤起原因也不是很方便。經(jīng)過在monit盹靴、god拱她、eye之間選擇二驰,最終選擇了monit,最主要的優(yōu)點(diǎn)就是占用內(nèi)存很小秉沼,而且和ruby無關(guān)桶雀,所以也不用考慮root用戶下ruby環(huán)境的問題。
monit的安裝和簡(jiǎn)單使用就不做簡(jiǎn)單的介紹唬复,大家可以在官網(wǎng)上查看矗积。需要注意的就是建議使用root用戶來安裝monit,這樣就比較方便的使用monit啟動(dòng)其他用戶下的服務(wù)敞咧,不用考慮權(quán)限問題棘捣。
mina,部署利器休建,具體使用方法可以到官網(wǎng)查看乍恐,不再介紹。
這里主要分享丰包,使用monit+mina對(duì)服務(wù)器進(jìn)行監(jiān)控的一些監(jiān)控和部署腳本,以及踩過的坑壤巷。
部分代碼如下:
config/deploy.rb

Dir[File.dirname(__FILE__) + '/mina/*.rb'].each {|file| require file }

environments = {
  'production1' => {
    domain: '115.115.115.115',
    branch: 'master',
    env: 'production1',
    path: "/var/app/wedding",
    user: "root",
    user_home: "/root",
    rvm_home: "/usr/local/rvm",
    thin_ports: 3000..3003
  },
  'production2' => {
    domain: '222.222.222.222',
    branch: 'master',
    env: 'production2',
    path: "/var/app/wedding",
    user: "cloud",
    user_home: "/home/cloud",
    rvm_home: "/usr/local/rvm",
    thin_ports: 2000..2007
  }
}

rails_env = environments.keys.include?(ENV['RAILS_ENV']) ? ENV['RAILS_ENV'] : 'develop'

env_attrs = environments[rails_env]
branch = env_attrs[:branch]
domain = env_attrs[:domain]
rvm_home = env_attrs[:rvm_home]
rvm_path = rvm_home + "/bin/rvm"
env = env_attrs[:env]
path = env_attrs[:path]
user = env_attrs[:user]
rvm = "ruby-2.1.2"
thin_ports = env_attrs[:thin_ports]
user_home = env_attrs[:user_home]

set :rails_env, env
set :domain, domain
set :deploy_to, path
set :repository, 'git@github.com:huoshaoyun/wedding-memo-rails.git'
set :branch, branch
set :ssh_options, '-A'
set :port, '29168' if rails_env == 'production2'
set :user, user
set :term_mode, :nil
set :rvm_path, rvm_path

## script templates
## 根據(jù)template文件生成腳本邑彪,需要設(shè)置必要的變量
set :rvm_home, rvm_home
set :user_home, user_home
set :rvm, rvm
set :path, env_attrs[:path]
set :thin_ports, thin_ports

config/templates/monit/monitrc.erb

#這里是monitrc的配置,省略1000行代碼胧华。
include /etc/monit/conf.d/*

config/templates/monit/mysql.erb
記得加上as uid user and gid usergroup寄症,這樣就可以以非root用戶啟動(dòng)服務(wù)宙彪。

check process mysqld with pidfile /var/run/mysqld/mysqld.pid
        group mysql
        start program = "/etc/init.d/mysql start" as uid <%= user %> and gid <%= user %>
        stop program = "/etc/init.d/mysql stop" as uid <%= user %> and gid <%= user %>
        if failed host 127.0.0.1 port 3306 then restart
        if 5 restarts within 5 cycles then timeout

config/templates/monit/nginx.erb

check process nginx with pidfile /run/nginx.pid
        start program = "/etc/init.d/nginx start" as uid <%= user %> and gid <%= user %>
        stop  program = "/etc/init.d/nginx stop" as uid <%= user %> and gid <%= user %>

config/templates/monit/redis.erb

# redis
check process redis with pidfile <%= user_home %>/pids/redis.pid
        start = "/bin/bash -c '/bin/sh <%= user_home %>/mysh/startRedis.sh'" as uid <%= user %> and gid <%= user %>
        stop program = "/etc/init.d/redis-server stop" as uid <%= user %> and gid <%= user %>
        group redis

config/templates/monit/sidekiq.erb

check process sidekiq
        with pidfile /var/app/wedding/shared/pids/sidekiq.pid
        start program = "/etc/init.d/sidekiq start" with timeout 90 seconds
        stop program = "/etc/init.d/sidekiq stop" with timeout 90 seconds
        group sidekiq

config/templates/monit/thin.erb

<% thin_ports.each do |thin_port| %>
check process thin-<%= thin_port %> with pidfile /var/app/wedding/tmp/pids/thin.<%= thin_port %>.pid
        start = "/bin/bash -c '/bin/sh <%= user_home %>/mysh/thin.<%= thin_port %>.sh start'" as uid <%= user %> and gid <%= user %>
        stop = "/bin/bash -c '/bin/sh <%= user_home %>/mysh/thin.<%= thin_port %>.sh stop'"  as uid <%= user %> and gid <%= user %>

        if 3 restarts within 5 cycles then timeout
        if failed port <%= thin_port %> protocol http with timeout 30 seconds for 2 cycles then restart
        group thin
<% end %>

config/templates/mysh/redis-server.sh.erb

#!/bin/sh
 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
# SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH  
# DAMAGE. 

# 存在bug不能正常start,只能stop
 
### BEGIN INIT INFO
# Provides:             redis-server
# Required-Start:       $syslog
# Required-Stop:        $syslog
# Should-Start:         $local_fs
# Should-Stop:          $local_fs
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    redis-server - Persistent key-value db
# Description:          redis-server - Persistent key-value db
### END INIT INFO
 
 
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/bin/redis-server
DAEMON_ARGS=/etc/redis.conf
NAME=redis-server
DESC=redis-server
PIDFILE=<%= user_home %>/pids/redis.pid
 
test -x $DAEMON || exit 0
test -x $DAEMONBOOTSTRAP || exit 0
 
set -e
 
case "$1" in
  start)
        echo -n "Starting $DESC: "
        touch $PIDFILE
        chown <%= user %>:<%= user %> $PIDFILE
        if start-stop-daemon --start --quiet --umask 007 --pidfile $PIDFILE --chuid <%= user %>:<%= user %> --exec $DAEMON -- $DAEMON_ARGS
        then
                echo "$NAME."
        else
                echo "failed"
        fi
        ;;
  stop)
        echo -n "Stopping $DESC: "
        if start-stop-daemon --stop --retry 10 --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON
        then
                echo "$NAME."
        else
                echo "failed"
        fi
        rm -f $PIDFILE
        ;;
 
  restart|force-reload)
        ${0} stop
        ${0} start
        ;;
  *)
        echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2
        exit 1
        ;;
esac
 
exit 0

這里存在一個(gè)問題不能通過這個(gè)腳本來啟動(dòng)redis有巧,只能停止redis释漆,所以又單獨(dú)寫了一個(gè)startRedis。
config/templates/mysh/startRedis.sh.erb

#!/bin/sh
cd $HOME && /usr/local/bin/redis-server $HOME/redis-2.8.16/redis.conf 

config/templates/mysh/thin.sh.erb
需要export ruby環(huán)境篮迎,否則root用戶下沒有辦法來啟動(dòng)thin男图,而且export PATH="${PATH}:<%= rvm_home %>/gems/<%= rvm %>/bin:/usr/bin:<%= rvm_home %>/bin:<%= rvm_home %>/gems/<%= rvm %>@global/bin:<%= rvm_home %>/rubies/<%= rvm %>/bin/"要將${PATH}放到前面,這樣就不會(huì)被系統(tǒng)默認(rèn)的ruby環(huán)境覆蓋甜橱。

#!/bin/bash
 
# Set the environment, as required by Monit
export PATH="${PATH}:<%= rvm_home %>/gems/<%= rvm %>/bin:/usr/bin:<%= rvm_home %>/bin:<%= rvm_home %>/gems/<%= rvm %>@global/bin:<%= rvm_home %>/rubies/<%= rvm %>/bin/"
export GEM_PATH="<%= rvm_home %>/gems/<%= rvm %>:<%= rvm_home %>/gems/<%= rvm %>@global"
export GEM_HOME="<%= rvm_home %>/gems/<%= rvm %>"
 
start () {
  cd <%= path %>/current
  BUNDLE_GEMFILE=<%= path %>/current/Gemfile bundle exec thin -C /etc/thin/wedding.<%= thin_port %>.yml -d start
}
 
stop () {
  kill -s QUIT $(cat <%= deploy_to %>/tmp/pids/thin.<%= thin_port %>.pid)
}
 
case $1 in
  start)
    start
  ;;
  stop)
    stop
  ;;
  *)
  echo $"Usage: $0 {start|stop}"
  exit 1
  ;;
esac
 
exit 0

config/templates/thin.yml.erb

---
chdir: /var/app/wedding/current
environment: <%= rails_env %>
address: 0.0.0.0
port: <%= thin_port %>
timeout: 30
log: /var/app/wedding/shared/log/thin.log
pid: /var/app/wedding/tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
servers: <%= servers_number %>
daemonize: true

config/mina/base.rb

require 'erb'

def template(from, to)
  queue %{echo "-----> Put #{from} file to #{to}"}
  erb = File.read(File.expand_path("../../templates/#{from}", __FILE__))
  put ERB.new(erb).result(binding), to
end

def put(content, file)
  queue %[echo #{escape content} > "#{file}"]
end

def escape(str)
  Shellwords.escape(str)
end

config/mina/mysh.rb

namespace :mysh do

  task :setup do
    invoke :'mysh:thin'
    invoke :'mysh:sidekiq'
    invoke :'mysh:redis-server' if rails_env == 'production2'
    %w[startRedis.sh].each do |name|
      destination = "$HOME/mysh/#{name}"
      template "mysh/#{name}.erb", destination
      queue "chmod a+x #{destination}"
    end
  end

  task :thin do
    thin_ports.each do |thin_port|
      set :thin_port, thin_port
      destination = "$HOME/mysh/wedding.#{thin_port}.sh"
      template "mysh/thin.sh.erb", destination
      queue "chmod a+x #{destination}"
    end
  end

  task :sidekiq do
    destination = "$HOME/mysh/sidekiq.sh"
    template "mysh/sidekiq.sh.erb", destination
    queue "chmod a+x #{destination}"
    queue "sudo cp #{destination} /etc/init.d/sidekiq"
  end

  task "redis-server" do
    destination = "$HOME/mysh/redis-server.sh"
    template "mysh/redis-server.sh.erb", destination
    queue "chmod a+x #{destination}"
    queue "sudo cp #{destination} /etc/init.d/redis-server"
  end

end

通過mina mysh:setup來生成服務(wù)器相關(guān)的啟動(dòng)腳本逊笆。

config/mina/thin.rb

namespace :thin do

  task :setup do
    thin_ports.each do |thin_port|
      destination = "/etc/thin/wedding.#{thin_port}.yml"
      set :thin_port, thin_port
      set :servers_number, 1
      template "thin.yml.erb", destination
    end
    invoke :'thin:railsapp'
  end

  task "railsapp" do
    destination = "/etc/thin/railsapp.yml"
    set :thin_port, thin_ports.first
    set :servers_number, thin_ports.size
    template "thin.yml.erb", destination
  end

end

通過mina thin:setup來生成thin的配置文件。
config/mina/monit.rb

namespace :monit do

  desc "Setup all Monit configuration"
  task :setup do
    queue %{echo "-----> Setting up Monit..."}
    monit_config "monitrc", "/etc/monit/monitrc"
    monit_config "monitrc", "/etc/monitrc"
    invoke :'monit:mysql'
    invoke :'monit:redis' if rails_env == 'production2'
    invoke :'monit:nginx'
    invoke :'monit:thin'
    invoke :'monit:sidekiq'
  end
  after "deploy:setup", "monit:setup"

  task(:nginx) { monit_config "nginx" }
  task(:mysql) { monit_config "mysql" }
  task(:redis) { monit_config "redis" }
  task(:thin) { monit_config "thin" }
  task(:sidekiq) { monit_config "sidekiq" }

  %w[start stop syntax reload].each do |command|
    desc "Run Monit #{command} script"
    task command do
      queue %{echo "-----> Monit #{command}"}
      queue "sudo service monit #{command}"
    end
  end

  task :status do
    queue "sudo monit status"
  end

end

def monit_config(name, destination = nil)
  destination ||= "/etc/monit/conf.d/#{name}"
  template "monit/#{name}.erb", "$HOME/monit/#{name}"
  queue "sudo cp $HOME/monit/#{name} #{destination}"
  queue "sudo chown root #{destination}"
  queue "sudo chmod 600 #{destination}"
end

通過mina monit:setup來生成monit的配置文件岂傲。 這里需要注意难裆,一定要將monit的一些配置文件的owner修改為root,即和monit安裝用戶是同一用戶镊掖,否則是無法啟動(dòng)的乃戈。 另外需要注意的是,需要考慮各項(xiàng)服務(wù)的pid文件亩进,某些service是默認(rèn)關(guān)閉pid文件的症虑,需要修改相應(yīng)的配置文件打開。
將配置文件和腳本模版化镐侯,可以在配置完一臺(tái)服務(wù)器后侦讨,非常迅速的配置完成其他服務(wù)器。

一切搞定苟翻,這樣就可以隨時(shí)查看服務(wù)器的狀態(tài)韵卤,來點(diǎn)效果圖。




試著kill掉一個(gè)thin


:smiley:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末崇猫,一起剝皮案震驚了整個(gè)濱河市沈条,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诅炉,老刑警劉巖蜡歹,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涕烧,居然都是意外死亡月而,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門议纯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來父款,“玉大人,你說我怎么就攤上這事『┰埽” “怎么了世杀?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)肝集。 經(jīng)常有香客問我瞻坝,道長(zhǎng),這世上最難降的妖魔是什么杏瞻? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任所刀,我火速辦了婚禮,結(jié)果婚禮上伐憾,老公的妹妹穿的比我還像新娘勉痴。我一直安慰自己,他們只是感情好树肃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布蒸矛。 她就那樣靜靜地躺著,像睡著了一般胸嘴。 火紅的嫁衣襯著肌膚如雪雏掠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天劣像,我揣著相機(jī)與錄音乡话,去河邊找鬼。 笑死耳奕,一個(gè)胖子當(dāng)著我的面吹牛绑青,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屋群,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼闸婴,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了芍躏?” 一聲冷哼從身側(cè)響起邪乍,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎对竣,沒想到半個(gè)月后庇楞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡否纬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年吕晌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片临燃。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡睛驳,死狀恐怖壁拉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柏靶,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布溃论,位于F島的核電站屎蜓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏钥勋。R本人自食惡果不足惜炬转,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望算灸。 院中可真熱鬧扼劈,春花似錦、人聲如沸菲驴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赊瞬。三九已至先煎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間巧涧,已是汗流浹背薯蝎。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谤绳,地道東北人占锯。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像缩筛,于是被迫代替她去往敵國(guó)和親消略。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容