ラベル Apache の投稿を表示しています。 すべての投稿を表示
ラベル Apache の投稿を表示しています。 すべての投稿を表示

2014-09-30

Apache httpd: /bin/sh: /apr-1/build/libtool: No such file or directory

いつも通り Apache httpd を make すると、エラーが発生。

# make
make[1]: Entering directory `/usr/local/src/httpd-2.2.24'
Making all in srclib
make[2]: Entering directory `/usr/local/src/httpd-2.2.24/srclib'
Making all in pcre
make[3]: Entering directory `/usr/local/src/httpd-2.2.24/srclib/pcre'
make[4]: Entering directory `/usr/local/src/httpd-2.2.24/srclib/pcre'
/apr-1/build/libtool --silent --mode=compile gcc -pthread        -I/usr/local/src/httpd-2.2.24/srclib/pcre -I. -I/usr/local/src/httpd-2.2.24/os/unix -I/usr/local/src/httpd-2.2.24/server/mpm/prefork -I/usr/local/src/httpd-2.2.24/modules/http -I/usr/local/src/httpd-2.2.24/modules/filters -I/usr/local/src/httpd-2.2.24/modules/proxy -I/usr/local/src/httpd-2.2.24/include -I/usr/local/src/httpd-2.2.24/modules/generators -I/usr/local/src/httpd-2.2.24/modules/mappers -I/usr/local/src/httpd-2.2.24/modules/database -I/usr/include/apr-1 -I/usr/local/src/httpd-2.2.24/modules/proxy/../generators -I/usr/local/src/httpd-2.2.24/modules/ssl -I/usr/local/src/httpd-2.2.24/modules/dav/main   -c maketables.c && touch maketables.lo
/bin/sh: /apr-1/build/libtool: No such file or directory
make[4]: *** [maketables.lo] Error 127
make[4]: Leaving directory `/usr/local/src/httpd-2.2.24/srclib/pcre'
make[3]: *** [all-recursive] Error 1
make[3]: Leaving directory `/usr/local/src/httpd-2.2.24/srclib/pcre'
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory `/usr/local/src/httpd-2.2.24/srclib'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/usr/local/src/httpd-2.2.24'
make: *** [install-build] Error 2

よく見ると、configure 時にも同様のログが出ていた。

Applying OS-specific hints for httpd ...

./configure: line 5774: /apr-1/build/libtool: No such file or directory
  forcing SINGLE_LISTEN_UNSERIALIZED_ACCEPT to "1"
  forcing AP_NONBLOCK_WHEN_MULTI_LISTEN to "1"

確かにいつもと違ってこのシステムには apr パッケージが入っているが、一体 /apr-1/build/libtool とはどこから来たのか。configure スクリプトを追いかけると、apr-1-config --apr-libtool の出力に辿り着いた。

# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 6.5 (Santiago)

# type apr-1-config
apr-1-config is hashed (/usr/bin/apr-1-config)

# apr-1-config --version
1.3.9

# apr-1-config --apr-libtool
/apr-1/build/libtool

私には apr-1-config と configure スクリプトのどちらが間違っているのかは分からない。しかしどちらであろうと、動かないシステムに価値はない。

結論: --with-included-apr が正義。

今後も余計なトラブルに逢いたくなければ、常にこのオプションを付けておくのが良さそうだ。普通、パッケージ提供バイナリよりも自分でビルドした方がパフォーマンスも良くなるはずだし。

もしかすると最新版の httpd では対処済みかも知れないが、面倒いので未確認。

2012-06-11

Apache: httpd (pid ####) already running

Apache httpd が起動しなくなることがある。

# /usr/local/apache2/bin/httpd -k start
httpd (pid 2369) already running

大抵はサーバー再起動で復旧するが、運が悪いと何度再起動しても復旧しなくなる。

ソースコードでは次の部分。(httpd 2.4 は使ってないので知らない)

httpd-2.2.22/server/mpm_common.c:

int ap_signal_server(int *exit_status, apr_pool_t *pconf)
{
    apr_status_t rv;
    pid_t otherpid;
    int running = 0;
    const char *status;

    *exit_status = 0;

    rv = ap_read_pid(pconf, ap_pid_fname, &otherpid);
    if (rv != APR_SUCCESS) {
        if (rv != APR_ENOENT) {
            ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, NULL,
                         "Error retrieving pid file %s", ap_pid_fname);
            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
                         "Remove it before continuing if it is corrupted.");
            *exit_status = 1;
            return 1;
        }
        status = "httpd (no pid file) not running";
    }
    else {
        if (kill(otherpid, 0) == 0) {
            running = 1;
            status = apr_psprintf(pconf,
                                  "httpd (pid %" APR_PID_T_FMT ") already "
                                  "running", otherpid);
        }
        else {
            status = apr_psprintf(pconf,
                                  "httpd (pid %" APR_PID_T_FMT "?) not running",
                                  otherpid);
        }
    }

PID ファイルに書かれている PID へ kill -0 が成功すれば、つまりプロセスが存在すれば、already running となる。そのプロセスが httpd であるかは関係ない。通常、PID ファイルは httpd 停止時に削除されるが、SIGKILL やサーバーリセットなどで httpd が死ぬと、PID ファイルは残ったままになる。

httpd をソースからビルドしている場合、PID ファイルの場所を /var/run 下などに変更していない限り、サーバーを再起動しても PID ファイルは消えない。故に、運が悪いと何度サーバーを再起動しても復旧しなくなる。サーバー起動時のプロセス起動順なんて、そうそう変わらないからだ。(もっとも、Upstart や Systemd で殆んどのプロセスが並列起動するようになっていれば、この限りではないかも知れない)

要は PID ファイルを消しさえすれば復旧するのだが、システムが客先などにあってコマンドを叩ける人がいない場合、サーバー再起動で復旧しないのは致命的だ。

これがビルドではなくパッケージインストールした httpd の場合だと現象が違って、例えば RHEL6 だと、

# service httpd start
Starting httpd:

起動スクリプト内で処理が止められ、already running すら出ずに起動に失敗する。但し、この場合はサーバーを再起動すれば確実に復旧する。パッケージインストールした httpd の PID ファイルは、例えば RHEL6 なら /var/run/httpd/httpd.pid になるが、/var/run 下はサーバー起動時に必ず削除されるからだ。

最悪はサーバー再起動で復旧しさえすれば何とかなる。しかし欲を言えば、httpd 再起動だけで復旧して欲しい。つまり、httpd の起動前に PID ファイルを削除すれば良い。具体的には、httpd の起動スクリプトでゴニョゴニョすることになるだろう。

気を付けることは、この挙動(already running)自体が二重起動を防止する機構なので、PID ファイルを消す前に自力で二重起動をチェックする必要がある。RHEL なら /etc/init.d/function 中の status 関数、更に言えばその中の __pids_pidof 関数が使えそうに見えるが、httpd なら単純にポート 80 が LISTEN されているか調べる方が簡単かも知れない。但し、いずれの場合も実際に私はやったことがないので、動くコードは載せられない。

私自身は httpd 起動に runit を使っており、二重起動のチェックはそれこそ runit の仕事。runit が起動スクリプト(run)を実行する時点で二重起動でないことが保証されるので、単に起動スクリプトの先頭で rm -f <pidfile> すれば良いだけ。今まで runit には散々苦労させられてきたから、こんな時くらい楽させて貰わないと。:-)

2012-06-01

Apache httpd: not `reload' but `graceful' when logrotate

RHEL で Apache httpd パッケージをインストールすると、logrotate 設定は次のようになる。

RHEL6.2: /etc/logrotate.d/httpd:

/var/log/httpd/*log {
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
    endscript
}

これで負荷試験を行うと、logrotate 時に接続が切れてクライアント側でエラーになる。httpd 起動スクリプトの実装を見てみると、

RHEL6.2: /etc/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
        LSB=1 killproc -p ${pidfile} $httpd -HUP
        RETVAL=$?
        if [ $RETVAL -eq 7 ]; then
            failure $"httpd shutdown"
        fi
    fi
    echo
}

普通に HUP を送っている。HUP を受けると httpd は即座に子プロセスを再起動するので、クライアントの接続が切れるのは当たり前。少なくとも、logrotate 時は graceful reload するべきだろう。

    postrotate
        /sbin/service httpd graceful > /dev/null 2>/dev/null || true
    endscript

参考までに Ubuntu 12.04 を見てみると、RHEL と同様に logrotate 時に reload しているが、起動スクリプト側の reload の実装が graceful reload するようになっているので問題ない。

RHEL と言えども過信は禁物。