Create a gist now

Instantly share code, notes, and snippets.

rcスクリプトの書き方について

CentOS6.3でrcスクリプトを書くよ

ランレベルとは?

/etc/inittabに書いてあるので確認.

# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)

関連ファイル/ディレクトリ

  • /etc/init.d
  • /etc/rc[0-6].d
  • /etc/sysconfig

CentOS6.3では/etc/(init|rc[0-6]).dは全て/etc/rc.d以下にあるディレクトリへのシンボリックリンクでRedHat系はこうなっているらしい.

lrwxrwxrwx.  1 root     root         11  7月 10 22:12 2012 /etc/init.d -> rc.d/init.d
lrwxrwxrwx.  1 root     root         10  7月 10 22:12 2012 /etc/rc0.d -> rc.d/rc0.d
lrwxrwxrwx.  1 root     root         10  7月 10 22:12 2012 /etc/rc1.d -> rc.d/rc1.d
lrwxrwxrwx.  1 root     root         10  7月 10 22:12 2012 /etc/rc2.d -> rc.d/rc2.d
lrwxrwxrwx.  1 root     root         10  7月 10 22:12 2012 /etc/rc3.d -> rc.d/rc3.d
lrwxrwxrwx.  1 root     root         10  7月 10 22:12 2012 /etc/rc4.d -> rc.d/rc4.d
lrwxrwxrwx.  1 root     root         10  7月 10 22:12 2012 /etc/rc5.d -> rc.d/rc5.d
lrwxrwxrwx.  1 root     root         10  7月 10 22:12 2012 /etc/rc6.d -> rc.d/rc6.d

/etc/rc.d/rc*.d

ランレベル毎のスクリプト. init.d以下へのシンボリックリンク.

$ ll /etc/rc.d/*/*nginx*
-rwxr-xr-x 1 root root 2795  4月 26 22:36 2013 /etc/rc.d/init.d/nginx
lrwxrwxrwx 1 root root   15  6月 14 10:43 2013 /etc/rc.d/rc0.d/K15nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root   15  6月 14 10:43 2013 /etc/rc.d/rc1.d/K15nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root   15  6月 14 10:43 2013 /etc/rc.d/rc2.d/S85nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root   15  6月 14 10:43 2013 /etc/rc.d/rc3.d/S85nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root   15  6月 14 10:43 2013 /etc/rc.d/rc4.d/S85nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root   15  6月 14 10:43 2013 /etc/rc.d/rc5.d/S85nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root   15  6月 14 10:43 2013 /etc/rc.d/rc6.d/K15nginx -> ../init.d/nginx

S**は起動用、K**は停止用で、上記ではシングルユーザーモード(ランレベル1)では起動しないサービスということとなる. 2桁の数字は実行順で、数字の小さなスクリプト->大きなスクリプトの順で実行される.

chkconfig

/etc/rc[0-6].d以下のシンボリックリンクはchkconfigコマンドで操作できる.

rcスクリプトの書き方

  1. /etc/rc.d/init.d以下に起動用スクリプトを作成する
  2. (必要であれば)chkconfigなどで有効化する

起動用スクリプトが受け取る引数はstart, stopが最低限、restart, reload, statusがあればなお良い(Chefでの設定が捗る).

nginxのrcスクリプトを参考にする

他のサービス用を書くにあたって共通となりそうなところを搔い摘んで.

まずchkconfig用のコメント. ランレベルとプライオリティの設定でchkconfigコマンドで設定する場合に参照される. man chkconfigで詳細確認できる.

# chkconfig:   - 85 15
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server

すぐ後に続く以下コメントは必要なのかしら?

# processname: nginx
# config:      /etc/nginx/nginx.conf
# config:      /etc/sysconfig/nginx
# pidfile:     /var/run/nginx.pid

daemonkillprocなどのユーティリティ関数を含むshellを読み込む.

# Source function library.
. /etc/rc.d/init.d/functions

各ファイルパスなどを変数に設定.

nginx="/usr/sbin/nginx"
prog=$(basename $nginx)

sysconfig="/etc/sysconfig/$prog"
lockfile="/var/lock/subsys/nginx"
pidfile="/var/run/${prog}.pid"

NGINX_CONF_FILE="/etc/nginx/nginx.conf"

[ -f $sysconfig ] && . $sysconfig

プログラム名や設定ファイルパスを設定している. $lockfileは命名規則(/var/lock/subsys/${base})でfunctionsのstatus関数から参照される. $pidfilestart時に指定していなくnginxの設定ファイル中で指定される、functionsからの参照は命名規則(/var/run/${base}.pid)が揃っているので解決

start関数. functionsで定義されるdaemon関数を利用. $lockfiletouchしている.

start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop関数. functionsで定義されるkillproc関数を利用. startで作成した$lockfileの削除もやっている.

stop() {
    echo -n $"Stopping $prog: "
    killproc -p $pidfile $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restartreload. 前者はstopしてstart. 後者はkillproc関数にkilllevel引数(-HUP)を与えて利用している.

restart() {
    configtest_q || return 6
    stop
    start
}

reload() {
    configtest_q || return 6
    echo -n $"Reloading $prog: "
    killproc -p $pidfile $prog -HUP
    echo
}

status用. functionsで定義されるstatus関数を利用している.

rh_status() {
    status $prog
}

最後にコマンド引数の解析とそれぞれの関数実行部分.

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest|reopen_logs)
        $1
        ;;
    force-reload|upgrade) 
        rh_status_q || exit 7
        upgrade
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    status|status_q)
        rh_$1
        ;;
    condrestart|try-restart)
        rh_status_q || exit 7
        restart
            ;;
    *)
        echo $"Usage: $0 {start|stop|reload|configtest|status|force-reload|upgrade|restart|reopen_logs}"
        exit 2
esac

気付いたこと

  • pidfileの出力はアプリケーションがやらなければならない. functionsの関数に渡しているのは参照用.
  • lockfileはstatusでの参照用.
  • 実行プログラムはサブシェルで実行されるのみ(daemonizeは含まれていない)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment