網頁

2013年6月11日 星期二

nginx + smokeping with fastcgi on FreeBSD

緣起


一直以來都會用 Smokeping 來監視各個機房的對外網路狀況,但 Smokeping 全由 perl 寫成,在某次大搬風之後遺失了設定,所以只能暫時跑著 CGI mode。但是剛剛實在是太誇張的慢了,等到 proxy 一直 timeout ,所以就決定還是來把乖乖設定好吧。

說來也有趣,當時的變動是把 lighttpd 換成 nginx,但不知道什麼原因,當時竟然為了要跑 smokeping 所以必須要借助 lighttpd 去跑 FastCGI  所以把 lighttpd 跑在 127.0.0.0:8080 然後用 nginx proxy 到 lighttpd,然後又好像 smokeping 的 FastCGI 哪裡沒設定好不會動,所以又只好變成了 在 lighttpd 上面跑 CGI mode (真的是脫褲子放屁加吃飽了撐著)

作法


大概看到有幾種方法讓 nginx 直接透過 FastCGI 處理 smokeping :
1) 用 p5-CGI-SpeedyCGI (參考 1)
2) 用 p5-Plack 透過 PSGI 來跑 perl-FastCGI (參考)
3) 用 p5-FCGI 和 p5-FCGI-ProcManager 來跑 perl-FastCGI (參考)

這邊是挑 2、3 來測,但 3 比較簡單一點也完工了,步驟大概是這樣:

1) 安裝需要的套件
cd /usr/ports/www/p5-FCGI && make install clean
cd /usr/ports/www/p5-FCGI-ProcManager && make install clean
cd /usr/ports/www/spawn-fcgi && make install clean
或是用 pkg :
 pkg install p5-FCGI p5-FCGI-ProcManager spawn-fcgi
2) 編輯 smokeping 的 fastcgi wrapper,vim /usr/local/smokeping/htdocs/smokeping.fcgi 檔案如下:
# -*-perl-*-

use FCGI;
use FCGI::ProcManager;

use lib qw(/usr/local/smokeping/lib);
use Smokeping 2.004002 ;

use CGI::Fast;
my $cfg = "/usr/local/etc/smokeping/config";
my $proc_manager = FCGI::ProcManager->new( {n_processes => 5} );
my $request = FCGI::Request();
$proc_manager->pm_manage();


while (my $q = new CGI::Fast) {
           Smokeping::cgi($cfg,$q);
   }

while($request->Accept() >= 0) {
         my $q = new CGI::Fast;
        $proc_manager->pm_pre_dispatch();
        Smokeping::cgi($cfg,$q);
        $proc_manager->pm_post_dispatch();
        exit(0);
}

3) 編輯啟動 fastcgi 的 script, vim /usr/local/smokeping/htdocs/spawn-smoke 檔案如下:
#!/bin/sh
/usr/local/bin/spawn-fcgi -a 127.0.0.1 -p 你要的PORT\
-P /var/run/smokeping-fastcgi.pid -u www \
-f /usr/local/smokeping/htdocs/smokeping.fcgi

4) 修改 nginx.conf ,增加 smokeping 的設定
        
        location /smokeping/smokeping.cgi {
            error_log    /PATH_TO/smoke-error.log  info;
            access_log   /PATH_TO/smoke-access.log combined;
                fastcgi_pass 127.0.0.1:你要的PORT;
                fastcgi_param SCRIPT_FILENAME /usr/local/smokeping/htdocs$fastcgi_script_name;
                include fastcgi_params;

        }

        location /smokeping/ {
            error_log    /PATH_TO/smoke-error.log  info;
            access_log   /PATH_TO/smoke-access.log combined;

            alias /usr/local/smokeping/htdocs/;
        }
然後記得跑
        
/usr/local/smokeping/htdocs/spawn-smoke 
之後再把 nginx 跑起來就沒問題了。
UPDATE: 要自動啟動的話 改 rc.conf
spawn_fcgi_enable="YES"
spawn_fcgi_app="/usr/local/smokeping/htdocs/smokeping.fcgi"
spawn_fcgi_bindaddr="127.0.0.1"
spawn_fcgi_bindport="PORT"
Update: slave 設定
smokeping_enable="YES"
smokeping_flags="--master-url=http://MASTER.cgi --slave-name=SLAVENAME --cache-dir=/var/run/smokeping --shared-secret=SECRET"
另外,如果要讓機器自動跑起來的話,我是直接偷改 /usr/local/etc/rc.d/smokeping :
      

# Define these smokeping_* variables in one of these files:
#       /etc/rc.conf
#       /etc/rc.conf.local
#       /etc/rc.conf.d/smokeping
#
# DO NOT CHANGE THESE DEFAULT VALUES HERE
#
# smokeping_flags=""

smokeping_enable=${smokeping_enable-"NO"}
smokeping_pidfile=${smokeping_pidfile-"/usr/local/var/smokeping/smokeping.pid"}
smokeping_fcgi_pidfile=${smokeping_fcgi_pidfile-"/var/run/smokeping-fastcgi.pid"}
smokeping_logfile=${smokeping_logfile-"/var/log/smokeping.log"}
smokeping_user=${smokeping_user-"smokeping"}
smokeping_group=${smokeping_group-"smokeping"}

. /etc/rc.subr

name="smokeping"
rcvar="smokeping_enable"
load_rc_config $name
command="/usr/local/bin/smokeping"
command_args="--logfile=${smokeping_logfile}"
pidfile="${smokeping_pidfile}"
fcgi_pidfile="${smokeping_fcgi_pidfile}"

extra_commands="reload"
reload_cmd="smokeping_reloadcmd"
start_precmd="smokeping_startprecmd"
stop_cmd="smokeping_stopcmd"
status_cmd="smokeping_statuscmd"
spawn_smokeping_fcgi="/usr/local/smokeping/htdocs/spawn-smoke"

smokeping_reloadcmd()
{
        $command --reload
}

smokeping_statuscmd()
{
        if [ ! -e $pidfile ];
        then
                echo "pidfile does not exist. $name is not running?";
                exit 1;
        fi

        if pgrep -F $pidfile >/dev/null;
        then
                echo "$name is running.";
        else
                echo "$name is not running.";
                exit 1;
        fi
}

smokeping_stopcmd()
{
        if pgrep -F $pidfile >/dev/null;
        then
                kill $sig_stop `cat $pidfile`;
                wait_for_pids `cat $pidfile`;

                kill $sig_stop `cat $fcgi_pidfile`;
                wait_for_pids `cat $fcgi_pidfile`;
                rm -rf $fcgi_pidfile;
        else
                echo "$name is not running.";
                exit 1;
        fi
}

smokeping_startprecmd()
{
        if [ ! -e $smokeping_logfile ];
        then
                install -o smokeping -g smokeping /dev/null $smokeping_logfile || echo "ERROR: Could not initialize logfile at $smokeping_logfile.";
        fi
        if [ ! -e $fcgi_pidfile ];
        then
                $spawn_smokeping_fcgi;
                echo "starting smokeping fastcgi";
        fi
}