如何寫SysV服務管理腳本

来源:http://www.cnblogs.com/f-ck-need-u/archive/2017/09/15/7524401.html
-Advertisement-
Play Games

本文目錄: 1.1 SysV腳本的特性1.2 SysV腳本要具備的能力1.3 start函數分析1.4 stop函數分析1.5 reload函數分析1.6 status、restart、force-reload等1.7 結束語 SysV服務管理腳本和/etc/rc.d/init.d/function ...


本文目錄:

1.1 SysV腳本的特性
1.2 SysV腳本要具備的能力
1.3 start函數分析
1.4 stop函數分析
1.5 reload函數分析
1.6 status、restart、force-reload等
1.7 結束語

SysV服務管理腳本和/etc/rc.d/init.d/functions文件中的幾個重要函數(包括daemon,killproc,status以及幾個和pid有關的函數)"關係匪淺"。本人已對該文件做了極詳細的分析和說明,參考functions文件詳細分析和說明

1.1 SysV腳本的特性

SysV風格的服務啟動腳本有以下幾個特性:

  1. 一般都放在/etc/rc.d/init.d目錄下。
  2. 這類腳本要求能接受start、stop、restart、status等參數來管理服務進程。
  3. 基本上都會載入/etc/rc.d/init.d/functions文件,因為該文件中定義了幾個對進程管理非常有用的函數。
  4. 基本上都會載入/etc/sysconfig目錄下的同名文件。此目錄下的服務同名文件一般都是為服務管理腳本提供選項參數的。例如/etc/sysconfig/httpd。
  5. 在腳本的頂端,需要加上# chkconfig# description兩行。chkconfig行定義的是該腳本被chkconfig工具管理時的主要依據,包括開機和關機時的啟動、關閉順序,以及運行在哪些運行級別。description是該腳本的描述性語句。雖然這兩行以"#"開頭,但必不可少。

例如,/etc/init.d/httpd腳本的前面幾行內容如下:

#!/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

1.2 SysV腳本要具備的能力

要使用腳本管理服務進程,該腳本還要求具備以下能力,且處理邏輯越完善,腳本就越完美。

  1. 啟動進程時:
    • 要求能夠檢測進程是否已在運行。這包括檢測pid文件是否存在、/proc目錄下是否有進程pid值對應的目錄。
    • 應該為程式創建鎖文件,路徑一般在/var/lock/subsys目錄下。
    • 如果使用daemon函數啟動進程,允許"--user"指定程式的運行身份。
    • 有些進程啟動時需要依賴於其他進程,如NFS啟動時依賴於rpcbind服務、mountd服務等,所以在NFS腳本中必須能夠檢測並啟動這些依賴服務。
  2. 關閉進程時:
    • 要求能夠檢測進程是否已在運行。同樣是檢測pid文件是否存在,/proc目錄下是否有pid對應的目錄。要註意,只有/proc目錄下沒有了對應目錄,才表示進程已死,但pid文件仍可能存在,例如kill -9就會出現這種問題。
    • 可以使用functions文件中的killproc函數殺進程,也可以直接使用kill或killall。
    • 為了讓腳本更完善,殺進程時應該多次檢測進程是否真的已經殺死。
    • 殺死進程的最後,必須要刪除pid文件和鎖文件。
    • 對於有依賴性的服務,考慮是否也應該殺死它們。
  3. 服務重讀配置文件時(reload):
    • 對於非終端進程,發送HUP信號的作用是重讀配置文件,而不會中斷進程。
    • 為了標準,應該找出"master"進程的pid,並向其發送HUP信號。一般來說,服務的子進程或線程不會也沒必要讀取配置文件。為了方便或投籃,可以直接向所有進程發送HUP信號。
    • 最好在發送HUP信號前,也檢查進程是否已在運行。當然,對於reload來說,這無所謂。
    • 如果待管理程式支持配置文件的語法檢查,在發送HUP信號前,應該檢查語法是否錯誤。
    • 實在無法實現重讀配置文件的功能,應該讓其和restart的功能一致,一般這也是"force-reload"的功能。
  4. 重啟服務時:
    • 一般來說,就是先stop,再start。
  5. 查看status時:
    • 除非有額外的狀態顯示需求,否則/etc/init.d/functions中的status函數已經足夠完美了。

以上並沒有說明,管理多實例服務時的情況。這需要考慮額外的因素,例如程式自身是否支持多實例,支持的話是否應該寫多個服務腳本分別管理各程式,配置文件是否要共用,pid文件是否能共用,搜索pid時如何避免搜索出非自身實例的pid,還要註意分配鎖文件。這樣的腳本寫起來可能並不難,但這些因素必須要考慮。本文暫不介紹多實例的SysV腳本,因為和程式自身關聯性比較強。

有了以上內容,並理解了functions文件中的函數,再看/etc/init.d/下的服務啟動腳本,絕大多數都感覺很簡單。因為它們的思路和框架都是一致的。

因為網上以及/etc/init.d/下服務啟動腳本示例太多了,所以本文不單獨寫這類腳本,而是從幾個腳本中抽出比較經典的部分,分別介紹start,stop,reload和status的寫法。

1.3 start函數分析

以httpd的服務管理腳本/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
}

函數首先輸出"Starting $prog"信息,再使用daemon啟動"$httpd"程式。

在daemon語句中,"--pidfile"是daemon的參數,該參數為daemon檢測pid文件是否存在,"$httpd"進程是否已在運行。註意,這個"--pidfile"是寫在"$httpd"前面的,表示這是daemon的參數,而非"$httpd"的啟動參數。

檢測完成後,啟動程式。程式的啟動命令從"$httpd"參數開始,"$OPTIONS"是"$httpd"的啟動選項。一般出現"$OPTIONS"這個字眼,很可能載入了/etc/sysconfig目錄下的同名文件,目的是提供程式啟動參數。

如果啟動成功,則會daemon函數會調用functions中的success函數顯示"[ OK ]",否則會顯示"[ FAILED ]"。

最後,如果啟動成功,則會創建該進程的鎖文件"$lockfile"。鎖文件一般都在/var/lock/subsys目錄下。

很多時候,管理的進程也有"--pidfile"類似的選項。例如下麵的啟動語句:

daemon --pidfile $pidfile $processname --pidfile=$pidfile

兩個"--pidfile"選項,但他們的作用是不一樣的。第一個"--pidfile"是daemon函數的參數,以便daemon能夠檢測該文件中的pid進程是否已在運行。第二個"--pidfile"是"$processname"的啟動參數,啟動時會創建此文件作為pid文件。

再看一個不使用daemon函數管理進程啟動動作的示例。以下是/etc/init.d/sshd中的start函數內容。

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
}

前面多了一大段,這和服務啟動腳本的框架無關,是程式自身要求的,但作用很簡單。無非就是判斷下程式是否可執行,配置文件是否存在,是否要創建服務端主機驗證階段的密鑰對,也就是/etc/ssh/ssh_host_{rsa,dsa}_key等幾個文件。

再下麵才是服務啟動腳本中的通用邏輯部分。輸出一段信息,然後啟動程式,創建鎖文件。但這裡沒有使用daemon函數管理,所以這裡配合了success和failure函數以便人性化顯示"[ OK ]"或"[ FAILED ]"。

1.4 stop函數分析

仍然以/etc/init.d/httpd中的stop函數為例。

# 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}
}

前面加了一段註釋,大致意思是說這裡殺死進程的行為和httpd自帶的apachectl工具停止服務的命令"apachectl -k stop"的行為是不同的。之所以我要把這一段也貼上來,也就是為了說明這一點。有些服務程式自帶進程管理工具,亦或是使用functions中的函數,完全由我們自己決定。

再看stop函數的邏輯。首先使用"status"函數檢查進程的狀態,如果進程已在運行,則使用killproc函數殺掉它,否則表示進程未運行或進程已死,但pid文件還存在。所以,在最後刪掉pidfile和lockfile。

需要註意的是,killproc殺進程時,能保證pidfile同時被刪除。但它不負責lockfile,而且執行stop之前曾手動執行了"kill -9"殺進程,那麼進程雖然已死,但pid文件卻存在。因此也仍需手動rm刪除pidfile。

killproc的調用方法為:

killproc [-p $pidfile] -[d $delay] $processname [-signal]

它的邏輯和執行過程是這樣的:

  1. 根據pidfile找出要殺的pid,如果沒有指定pidfile,則預設從/var/run/$base.pid讀取;
  2. 如果指定了要發送的信號,則killproc通過kill命令發送給定信號。0.5秒後檢查/proc目錄下是否還有對應目錄存在,有則說明進程殺死失敗,返回"[ FAILED ]"信息,否則表示成功,於是刪除pid文件。
  3. 如果沒有指定要發送的信號,則killproc先發送TERM信號(即kill -15),然後在給定的延遲時間delay內,每隔一秒檢查一次/proc下是否有對應目錄,如果發現沒有,則表示進程殺死成功,於是刪除pid文件(其實這種情況不用刪,因為TERM信號會自動做收尾動作)。但如果delay都超時了,還發現進程存在,則發送KILL信號強制殺死進程,最後刪除pid文件。

現在再理解killproc -p ${pidfile} -d ${STOP_TIMEOUT} $httpd就很簡單了。

再看/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。但是後面還設置了runlevel的判斷情況,這就屬於程式自身屬性了,和服務管理腳本的邏輯框架無關。

最後再看mysqld中的stop函數。

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號
    if [ -n "$MYSQLPID" ]; then                   # 如果pid不為空,則
        /bin/kill "$MYSQLPID" >/dev/null 2>&1     # 先發送預設的TERM信號殺一次
        ret=$?
        if [ $ret -eq 0 ]; then         # 如果殺成功了,則執行下麵一段。
                                        # 否則直接失敗,但這不可能。為了邏輯完整,後面仍寫了else
            TIMEOUT="$STOPTIMEOUT"
            while [ $TIMEOUT -gt 0 ]; do   # 在延遲時間內,每隔1秒殺一次
                /bin/kill -0 "$MYSQLPID" >/dev/null 2>&1 || break
                sleep 1
                let TIMEOUT=${TIMEOUT}-1
            done
            if [ $TIMEOUT -eq 0 ]; then    # 如果達到延遲時間邊界,則返回殺死進程超時信息
                echo "Timeout error occurred trying to stop MySQL Daemon."
                ret=1
                action $"Stopping $prog: " /bin/false
            else                           # 否則進程殺死成功,刪除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
}

雖然有點長,但有了前面SysV腳本要具備的能力的概念,stop函數的邏輯都一樣好簡單。

1.5 reload函數分析

關於reload函數,主要有兩點:(1).語法檢查;(2).發送HUP信號給"master"進程。其中語法檢查要程式自身能支持,例如httpd -tnginx -t

以下是/etc/init.d/{httpd,nginx}兩個腳本中的reload函數。

## reload() in /etc/rc.d/init.d/httpd
reload() {
    echo -n $"Reloading $prog: "
    if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then  # 語法檢查
        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        # 語法檢查通過,發送HUP信號
        LSB=1 killproc -p ${pidfile} $httpd -HUP
        RETVAL=$?
        if [ $RETVAL -eq 7 ]; then             # 註意reload失敗時退出狀態碼為7
            failure $"httpd shutdown"
        fi
    fi
    echo
}

## reload() in /etc/rc.d/init.d/nginx
reload() {
    configtest_q || return 6           # 語法檢查
    echo -n $"Reloading $prog: "
    killproc -p $pidfile $prog -HUP    # 發送HUP信號
    echo
}

configtest_q() {
    $nginx -t -q -c $NGINX_CONF_FILE
}


case "$1" in
    reload)
        rh_status_q || exit 7        # reload失敗時,退出狀態碼7
        $1
        ;;

唯一需要註意的是,reload失敗時,退出狀態碼為7。這大概已經約定俗成了吧。

再看/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。它直接退出不做任何動作。

case "$1" in
  reload)
    exit 3
    ;;

如果不使用killproc函數,而是使用kill命令,那麼應該找出"master" pid。可以使用functions中的pidofproc函數。例如:

pid=$(pidofprco -p pidfile $processname)
action "Reloading $prog: " kill -HUP $pid

1.6 status、restart、force-reload等

  • status:就是為了獲取進程狀態的,一般直接調用functions中的status函數status -p "$pidfile" $prog
  • restart:一般直接stop再start即可。
  • force-reload:其實就是restart。
  • condrestart:稱為條件式重啟。所謂的條件一般是判斷鎖文件是否存在,存在則重啟,否則忽略該動作。"try-restart"也是一樣的行為。

1.7 結束語

其實SysV服務啟動腳本大多都很簡單,至少它們的邏輯幾乎都一樣。在瞭解了functions中的幾個函數後,再把腳本的各參數(如start、stop)應該要具備的能力搞搞清楚,這類腳本完全是小菜一兩碟。

 

回到系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7048359.html

轉載請註明出處:http://www.cnblogs.com/f-ck-need-u/p/7524401.html

註:若您覺得這篇文章還不錯請點擊下右下角的推薦,有了您的支持才能激發作者更大的寫作熱情,非常感謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 需求:ftp獲取遠程數據的文件,根據文件的創建時間點下載文件。 可以自行擴展根據文件的大小等其他需求。 知識點總結: 1、獲取文件的時間: 時間內容: Sep 8 16:03 2、時間格式轉換 轉換結果: 201709081603 3、指定文件名,正則匹配 註意awk裡面模式變數用' '括起來,.* ...
  • su switch user 用途:用於用戶之間的切換 格式: su USERNAME切換用戶後,同時切換到新用戶的工作環境中 su USERNAME切換用戶後,不改變原用戶的工作目錄,及其他環境變數 退出:exit或logout ctrl+D sudo sudo是一種許可權管理機制,依賴於/etc/ ...
  • 1. 簡介 ​ lua nginx module(ngx_lua module)把 Lua5.1 的解釋器 或 LuaJIT 2.0/2.1 的解釋器嵌入到 nginx 中,將強大的 Lua 線程(Lua threads)與 nginx 事務模型(Nginx event model)相結合,我們可以 ...
  • 一、安裝環境 硬體:虛擬機 操作系統:Centos 7.0 64位 IP:192.168.120.150 hadoop-2.7.0.tar.gz 鏈接:http://pan.baidu.com/s/1eRT0tk2 密碼:ymim jdk-8u45-linux-x64.tar.gz 鏈接:http: ...
  • 經常使用的命令: #查看埠被占用情況 netstat -tunlp|grep 22 #查看java進程 ps -ef|grep java #壓縮前端工程 rar a -ep1 ./update/win32.zip ./packages/**/win32/* #查找所有帶wine的文件和文件夾 fi ...
  • MySQL資料庫增量備份,在這之前修改我們的資料庫配置文件/etc/my.cnf開啟bin-log日誌功能即可。接下來是我參考了下網上的一些方法,自己寫的,主要還是要能學到他的一些思路和方法。 添加計劃任務: crontab -e 00 03 * * * /root/MySQL_incrementb ...
  • Linux必知必會的目錄,linux啟動過程,PATH環境變數作用 ...
  • 服務端環境:CentOS 6.7客戶端環境:Windows 7 1.伺服器安裝VNC服務端 可以直接rpm安裝vnc的服務端: 如果rpm安裝時發現有依賴,建議直接使用yum安裝,輕鬆解決依賴問題: 如果系統安裝時並沒有安裝桌面選項,那麼就還需要用yum安裝一下桌面: 2.編輯vnc配置文件 編輯/ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...