《LINUX實(shí)操:如何寫(xiě)SysV服務(wù)管理腳本》要點(diǎn):
本文介紹了LINUX實(shí)操:如何寫(xiě)SysV服務(wù)管理腳本,希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
本文目次:
1.1 SysV腳本的特性
1.2 SysV腳本要具備的才能
1.3 start函數(shù)分析
1.4 stop函數(shù)分析
1.5 reload函數(shù)分析
1.6 status、restart、force-reload等
1.7 結(jié)束語(yǔ)
SysV服務(wù)管理腳本和/etc/rc.d/init.d/functions文件中的幾個(gè)重要函數(shù)(包含daemon
,killproc
,status
以及幾個(gè)和pid有關(guān)的函數(shù))"關(guān)系匪淺".本人已對(duì)該文件做了極詳細(xì)的分析和說(shuō)明,參考functions文件詳細(xì)分析和說(shuō)明.
?
SysV作風(fēng)的服務(wù)啟動(dòng)腳本有以下幾個(gè)特性:
# chkconfig
和# description
兩行.chkconfig行定義的是該腳本被chkconfig工具管理時(shí)的主要依據(jù),包含開(kāi)機(jī)和關(guān)機(jī)時(shí)的啟動(dòng)、關(guān)閉順序,以及運(yùn)行在哪些運(yùn)行級(jí)別.description是該腳本的描述性語(yǔ)句.雖然這兩行以"#"開(kāi)頭,但必不可少.例如,/etc/init.d/httpd腳本的前面幾行內(nèi)容如下:
#!/bin/bash
#
# httpd Startup script for the Apache HTTP Server
#
# chkconfig: - 85 15
# description: The Apache HTTP Server is an efficient and extensible \
# server implementing the current HTTP standards.
# processname: httpd
# config: /etc/httpd/conf/httpd.conf
# config: /etc/sysconfig/httpd
# pidfile: /var/run/httpd/httpd.pid
#
# Source function library.
. /etc/rc.d/init.d/functions
if [ -f /etc/sysconfig/httpd ]; then # 斷定后再加載
. /etc/sysconfig/httpd
fi
?
要使用腳本管理服務(wù)進(jìn)程,該腳本還要求具備以下才能,且處理邏輯越完善,腳本就越完美.
kill -9
就會(huì)出現(xiàn)這種問(wèn)題.以上并沒(méi)有說(shuō)明,管理多實(shí)例服務(wù)時(shí)的情況.這需要考慮額外的因素,例如程序自身是否支持多實(shí)例,支持的話是否應(yīng)該寫(xiě)多個(gè)服務(wù)腳本分別管理各程序,配置文件是否要共享,pid文件是否能共享,搜索pid時(shí)如何避免搜索出非自身實(shí)例的pid,還要注意分配鎖文件.這樣的腳本寫(xiě)起來(lái)可能并不難,但這些因素必須要考慮.本文暫不介紹多實(shí)例的SysV腳本,因?yàn)楹统绦蜃陨黻P(guān)聯(lián)性比較強(qiáng).
有了以上內(nèi)容,并理解了functions文件中的函數(shù),再看/etc/init.d/下的服務(wù)啟動(dòng)腳本,絕年夜多數(shù)都感覺(jué)很簡(jiǎn)單.因?yàn)樗鼈兊乃悸泛?a target="_blank" title="框架" class="conTagClass">框架都是一致的.
因?yàn)榫W(wǎng)上以及/etc/init.d/下服務(wù)啟動(dòng)腳本示例太多了,所以本文不單獨(dú)寫(xiě)這類(lèi)腳本,而是從幾個(gè)腳本中抽出比擬經(jīng)典的部分,分別介紹start,stop,reload和status的寫(xiě)法.
?
以httpd的服務(wù)管理腳本/etc/init.d/httpd為例.
start() {
echo -n $"Starting $prog: "
LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch ${lockfile}
return $RETVAL
}
函數(shù)首先輸出"Starting $prog"信息,再使用daemon啟動(dòng)"$httpd"法式.
在daemon語(yǔ)句中,"--pidfile"是daemon的參數(shù),該參數(shù)為daemon檢測(cè)pid文件是否存在,"$httpd"進(jìn)程是否已在運(yùn)行.注意,這個(gè)"--pidfile"是寫(xiě)在"$httpd"前面的,表現(xiàn)這是daemon的參數(shù),而非"$httpd"的啟動(dòng)參數(shù).
檢測(cè)完成后,啟動(dòng)程序.程序的啟動(dòng)命令從"$httpd"參數(shù)開(kāi)始,"$OPTIONS"是"$httpd"的啟動(dòng)選項(xiàng).一般呈現(xiàn)"$OPTIONS"這個(gè)字眼,很可能加載了/etc/sysconfig目錄下的同名文件,目的是提供程序啟動(dòng)參數(shù).
如果啟動(dòng)成功,則會(huì)daemon函數(shù)會(huì)調(diào)用functions中的success函數(shù)顯示"[ OK ]",不然會(huì)顯示"[ FAILED ]".
最后,如果啟動(dòng)勝利,則會(huì)創(chuàng)建該進(jìn)程的鎖文件"$lockfile".鎖文件一般都在/var/lock/subsys目錄下.
很多時(shí)候,治理的進(jìn)程也有"--pidfile"類(lèi)似的選項(xiàng).例如下面的啟動(dòng)語(yǔ)句:
daemon --pidfile $pidfile $processname --pidfile=$pidfile
兩個(gè)"--pidfile"選項(xiàng),但他們的作用是紛歧樣的.第一個(gè)"--pidfile"是daemon函數(shù)的參數(shù),以便daemon能夠檢測(cè)該文件中的pid進(jìn)程是否已在運(yùn)行.第二個(gè)"--pidfile"是"$processname"的啟動(dòng)參數(shù),啟動(dòng)時(shí)會(huì)創(chuàng)建此文件作為pid文件.
再看一個(gè)不使用daemon函數(shù)治理進(jìn)程啟動(dòng)動(dòng)作的示例.以下是/etc/init.d/sshd中的start函數(shù)內(nèi)容.
start()
{
[ -x $SSHD ] || exit 5
[ -f /etc/ssh/sshd_config ] || exit 6
# Create keys if necessary
if [ "x${AUTOCREATE_SERVER_KEYS}" != xNO ]; then
do_rsa_keygen
if [ "x${AUTOCREATE_SERVER_KEYS}" != xRSAONLY ]; then
do_rsa1_keygen
do_dsa_keygen
fi
fi
echo -n $"Starting $prog: "
$SSHD $OPTIONS && success || failure
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $lockfile
echo
return $RETVAL
}
前面多了一大段,這和服務(wù)啟動(dòng)腳本的框架無(wú)關(guān),是程序自身要求的,但作用很簡(jiǎn)單.無(wú)非便是判斷下程序是否可執(zhí)行,配置文件是否存在,是否要?jiǎng)?chuàng)建服務(wù)端主機(jī)驗(yàn)證階段的密鑰對(duì),也便是/etc/ssh/ssh_host_{rsa,dsa}_key等幾個(gè)文件.
再下??才是服務(wù)啟動(dòng)腳本中的通用邏輯部門(mén).輸出一段信息,然后啟動(dòng)程序,創(chuàng)建鎖文件.但這里沒(méi)有使用daemon函數(shù)管理,所以這里配合了success和failure函數(shù)以便人性化顯示"[ OK ]"或"[ FAILED ]".
?
仍然以/etc/init.d/httpd中的stop函數(shù)為例.
# When stopping httpd, a delay (of default 10 second) is required
# before SIGKILLing the httpd parent; this gives enough time for the
# httpd parent to SIGKILL any errant children.
stop() {
status -p ${pidfile} $httpd > /dev/null
if [[ $? = 0 ]]; then
echo -n $"Stopping $prog: "
killproc -p ${pidfile} -d ${STOP_TIMEOUT} $httpd
else
echo -n $"Stopping $prog: "
success
fi
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}
前面加了一段注釋,大致意思是說(shuō)這里殺死進(jìn)程的行為和httpd自帶的apachectl工具停止服務(wù)的命令"apachectl -k stop"的行為是不同的.之所以我要把這一段也貼上來(lái),也就是為了說(shuō)明這一點(diǎn).有些服務(wù)程序自帶進(jìn)程管理工具,亦或是使用functions中的函數(shù),完全由我們本身決定.
再看stop函數(shù)的邏輯.首先使用"status"函數(shù)檢查進(jìn)程的狀態(tài),如果進(jìn)程已在運(yùn)行,則使用killproc函數(shù)殺掉它,否則表現(xiàn)進(jìn)程未運(yùn)行或進(jìn)程已死,但pid文件還存在.所以,在最后刪掉pidfile和lockfile.
必要注意的是,killproc殺進(jìn)程時(shí),能保證pidfile同時(shí)被刪除.但它不負(fù)責(zé)lockfile,而且執(zhí)行stop之前曾手動(dòng)執(zhí)行了"kill -9"殺進(jìn)程,那么進(jìn)程雖然已死,但pid文件卻存在.因此也仍需手動(dòng)rm刪除pidfile.
killproc的調(diào)用辦法為:
killproc [-p $pidfile] -[d $delay] $processname [-signal]
它的邏輯和執(zhí)行進(jìn)程是這樣的:
kill -15
),然后在給定的延遲時(shí)間delay內(nèi),每隔一秒檢查一次/proc下是否有對(duì)應(yīng)目錄,如果發(fā)現(xiàn)沒(méi)有,則表現(xiàn)進(jìn)程殺死成功,于是刪除pid文件(其實(shí)這種情況不用刪,因?yàn)門(mén)ERM信號(hào)會(huì)自動(dòng)做收尾動(dòng)作).但如果delay都超時(shí)了,還發(fā)現(xiàn)進(jìn)程存在,則發(fā)送KILL信號(hào)強(qiáng)制殺死進(jìn)程,最后刪除pid文件.現(xiàn)在再理解killproc -p ${pidfile} -d ${STOP_TIMEOUT} $httpd
就很簡(jiǎn)單了.
再看/etc/init.d/sshd劇本中的stop.
stop()
{
echo -n $"Stopping $prog: "
killproc -p $PID_FILE $SSHD
RETVAL=$?
# if we are in halt or reboot runlevel kill all running sessions
# so the TCP connections are closed cleanly
if [ "x$runlevel" = x0 -o "x$runlevel" = x6 ] ; then
trap '' TERM
killall $prog 2>/dev/null
trap TERM
fi
[ $RETVAL -eq 0 ] && rm -f $lockfile
echo
}
更直接,直接就killproc.但是后面還設(shè)置了runlevel的判斷情況,這就屬于法式自身屬性了,和服務(wù)管理腳本的邏輯框架無(wú)關(guān).
末了再看mysqld中的stop函數(shù).
stop(){
if [ ! -f "$mypidfile" ]; then
# not running; per LSB standards this is "ok"
action $"Stopping $prog: " /bin/true # pid文件都不存在,直接顯示成功
return 0
fi
MYSQLPID=`cat "$mypidfile" 2>/dev/null` # 讀取pidfile中的pid號(hào)
if [ -n "$MYSQLPID" ]; then # 如果pid不為空,則
/bin/kill "$MYSQLPID" >/dev/null 2>&1 # 先發(fā)送默認(rèn)的TERM信號(hào)殺一次
ret=$?
if [ $ret -eq 0 ]; then # 如果殺成功了,則執(zhí)行下面一段.
# 否則直接失敗,但這不可能.為了邏輯完整,后面仍寫(xiě)了else
TIMEOUT="$STOPTIMEOUT"
while [ $TIMEOUT -gt 0 ]; do # 在延遲時(shí)間內(nèi),每隔1秒殺一次
/bin/kill -0 "$MYSQLPID" >/dev/null 2>&1 || break
sleep 1
let TIMEOUT=${TIMEOUT}-1
done
if [ $TIMEOUT -eq 0 ]; then # 如果達(dá)到延遲時(shí)間界限,則返回殺死進(jìn)程超時(shí)信息
echo "Timeout error occurred trying to stop MySQL Daemon."
ret=1
action $"Stopping $prog: " /bin/false
else # 否則進(jìn)程殺死成功,刪除pidfile和lockfile
rm -f $lockfile
rm -f "$socketfile"
action $"Stopping $prog: " /bin/true
fi
else
action $"Stopping $prog: " /bin/false
fi
else # 如果pid為空,則表示未成功讀取pidfile.
# failed to read pidfile, probably insufficient permissions
action $"Stopping $prog: " /bin/false
ret=4
fi
return $ret
}
雖然有點(diǎn)長(zhǎng),但有了前面SysV腳本要具備的能力的概念,stop函數(shù)的邏輯都一樣好簡(jiǎn)單.
?
關(guān)于reload函數(shù),主要有兩點(diǎn):(1).語(yǔ)法檢查;(2).發(fā)送HUP信號(hào)給"master"進(jìn)程.其中語(yǔ)法檢查要程序自身能支持,例如httpd -t
,nginx -t
.
以下是/etc/init.d/{httpd,nginx}兩個(gè)劇本中的reload函數(shù).
## reload() in /etc/rc.d/init.d/httpd
reload() {
echo -n $"Reloading $prog: "
if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then # 語(yǔ)法檢查
RETVAL=6
echo $"not reloading due to configuration syntax error"
failure $"not reloading $httpd due to configuration syntax error"
else
# Force LSB behaviour from killproc # 語(yǔ)法檢查通過(guò),發(fā)送HUP信號(hào)
LSB=1 killproc -p ${pidfile} $httpd -HUP
RETVAL=$?
if [ $RETVAL -eq 7 ]; then # 注意reload失敗時(shí)退出狀態(tài)碼為7
failure $"httpd shutdown"
fi
fi
echo
}
## reload() in /etc/rc.d/init.d/nginx
reload() {
configtest_q || return 6 # 語(yǔ)法檢查
echo -n $"Reloading $prog: "
killproc -p $pidfile $prog -HUP # 發(fā)送HUP信號(hào)
echo
}
configtest_q() {
$nginx -t -q -c $NGINX_CONF_FILE
}
case "$1" in
reload)
rh_status_q || exit 7 # reload失敗時(shí),退出狀態(tài)碼7
$1
;;
唯一必要注意的是,reload失敗時(shí),退出狀態(tài)碼為7.這大概已經(jīng)約定俗成了吧.
再看/etc/init.d/sshd中的reload.
reload()
{
echo -n $"Reloading $prog: "
killproc -p $PID_FILE $SSHD -HUP
RETVAL=$?
echo
}
case "$1" in
reload)
rh_status_q || exit 7
reload
;;
故意思的是mysqld的reload.它直接退出不做任何動(dòng)作.
case "$1" in
reload)
exit 3
;;
如果不使用killproc函數(shù),而是使用kill敕令,那么應(yīng)該找出"master" pid.可以使用functions中的pidofproc函數(shù).例如:
pid=$(pidofprco -p pidfile $processname)
action "Reloading $prog: " kill -HUP $pid
?
status -p "$pidfile" $prog
.?
其實(shí)SysV服務(wù)啟動(dòng)腳本大多都很簡(jiǎn)單,至少它們的邏輯幾乎都一樣.在了解了functions中的幾個(gè)函數(shù)后,再把腳本的各參數(shù)(如start、stop)應(yīng)該要具備的才能搞搞清楚,這類(lèi)腳本完全是小菜一兩碟.
本文永遠(yuǎn)更新鏈接地址:
更多LINUX教程,盡在維易PHP學(xué)院專(zhuān)欄。歡迎交流!
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/6691.html