檜山正幸のキマイラ飼育記 このページをアンテナに追加 RSSフィード Twitter

キマイラ・サイトは http://www.chimaira.org/です。
トラックバック/コメントは日付を気にせずにどうぞ。
連絡は hiyama{at}chimaira{dot}org へ。
蒸し返し歓迎!
このブログの更新は、Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama
ところで、アーカイブってけっこう便利ですよ。

2012-03-09 (金)

Nginxをダウンタイム・ゼロで入れ替える方法

| 12:32 | Nginxをダウンタイム・ゼロで入れ替える方法を含むブックマーク

chimaira.org を載せているNginxが古いままです。

[hiyama ~]$ /usr/local/nginx/sbin/nginx -v
nginx version: nginx/0.7.64
[hiyama ~]$

2012-03-09現在の安定版は、version 1.0.13 です。入れ替えなくちゃね。Nginxはダウンタイム・ゼロで入れ替える方法があります。それを試してみることにします。

次の記事を参考にしました。

[追記]最後に追記した方法が一番簡単そうです。[/追記]

現状はどうなっている

そもそもシステム環境全体が古いのですが、今回は動いているNginxを入れ替えるだけにします。

[hiyama ~]$ cd /usr/local/nginx/
[hiyama nginx]$ sbin/nginx -V
nginx version: nginx/0.7.64
built by gcc 3.4.6 20060404 (Red Hat 3.4.6-10)
TLS SNI support disabled
configure arguments: --with-http_ssl_module --with-debug --without-http_ssi_module --without-http_fastcgi_module
[hiyama nginx]$ cat logs/nginx.pid
3126
[hiyama nginx]$ pgrep nginx
3126
3127
[hiyama nginx]$

これで次のことが分かります。

  1. 現在動いているnginxのバージョンとconfigureオプション
  2. 現在動いているnginxマスタープロセスのPID
  3. 現在動いているnginxのすべてのプロセスのPID

念のために、Nginxの実行バイナリをバックアップしておきます。(設定ファイルは過去にバックアップ済みなので今日はしませんでした。)以下、sudo時のパスワード入力は省略します。

[hiyama nginx]$ sudo cp sbin/nginx sbin/nginx.OLD
[hiyama nginx]$ ls -l sbin/
合計 6456
-rwxr-xr-x  1 root root 3297507  1月 28  2010 nginx*
-rwxr-xr-x  1 root root 3297507  3月  9 11:28 nginx.OLD*
[hiyama nginx]$

ダウンロード

http://wiki.nginx.org/Install によると、次の /etc/yum.repos.d/nginx.repo を付け加えるとyumで扱えるらしいです。

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

が、今回は手動でビルドすることにします。2012-03-09現在の最新安定版は次のファイルです。

[hiyama ~]$ mkdir Work
[hiyama ~]$ cd Work/
[hiyama Work]$ wget http://nginx.org/download/nginx-1.0.13.tar.gz

(... 省略 ...)

[hiyama Work]$ tar xvzf nginx-1.0.13.tar.gz

(... 省略 ...)

[hiyama Work]$ 

ビルドとインストール

ここで、Nginxを最初に導入したときと同じようにビルドとインストールをしてしまってかまいません。今動いているNginxプロセスはそのままです。configureオプションは以前のものを使用します(nginx -V で確認できます)。

[hiyama Work]$ cd nginx-1.0.13/
[hiyama nginx-1.0.13]$ ./configure --with-http_ssl_module --with-debug --without-http_ssi_module --without-http_fastcgi_module

(... 省略 ...)

[hiyama nginx-1.0.13]$

インストールまでしてしまいましょう。

[hiyama nginx-1.0.13]$ sudo make install

(... 省略 ...)

[hiyama nginx-1.0.13]$

これで、nginxディレクトリの sbin/ と conf/ が更新されます。ただし、走っているNginxプロセスはまだそのままです。

[hiyama nginx]$ ls sbin
nginx*  nginx.OLD*  nginx.old*
[hiyama nginx]$ sbin/nginx -V
nginx version: nginx/1.0.13
TLS SNI support disabled
configure arguments: --with-http_ssl_module --with-debug --without-http_ssi_module --without-http_fastcgi_module
[hiyama nginx]$ cat logs/nginx.pid
3126
[hiyama nginx]$ pgrep nginx
3126
3127
[hiyama nginx]$

プロセスの入れ替え

いよいよ、走っているプロセスを新しいものと交換します。これを行うにはシグナルを使います。http://wiki.nginx.org/CommandLine でシグナルの使い方を確認しておきます。

マスタープロセス:

シグナル名 動作
TERM, INT 即座にシャットダウン
QUIT グレイスフルなシャットダウン
KILL しぶといプロセスを停止させる
HUP 設定のリロード
USR1 ログファイルを再オープンする
USR2 実行ファイルをオンザフライで更新する
WINCH ワーカープロセスをグレイスフルにシャットダウンする

設定のリロード(HUPシグナル)により、新しい設定で新しいワーカープロセスを走らせ、古いワーカープロセスはグレイスフルにシャットダウンします。

ワーカープロセス(通常は使う必要がない):

シグナル名 動作
TERM, INT即座にシャットダウン
QUIT グレイスフルなシャットダウン
USR1 ログファイルを再オープンする

さて、確認を終えたので作業を始めます。まず、USR2を使って実行ファイルをオンザフライで更新します。現在走っているマスタープロセスのPIDは、/usr/local/nginx/logs/nginx.pid にあります。

[hiyama nginx]$ cat logs/nginx.pid
3126
[hiyama nginx]$ sudo kill -USR2 `cat logs/nginx.pid`
[hiyama nginx]$ cat logs/nginx.pid
22192
[hiyama nginx]$ pgrep nginx
3126
3127
22192
22194
[hiyama nginx]$

これにより、状況は次のようになります。

  • 新しいマスタープロセス: 22192
  • 新しいワーカープロセス: 22194
  • 古いマスタープロセス: 3126
  • 古いワーカープロセス: 3127

古いマスタープロセスにWINCHを送って、古いワーカープロセスを止めます。

[hiyama nginx]$ sudo kill -WINCH 3126
[hiyama nginx]$ pgrep nginx
3126
22192
22194
[hiyama nginx]$

古いマスタープロセス自体はまだ動いています。ワーカーは新しいほうが動くので、ここで新しいワーカープロセスがちゃんと働くかを確認します。万が一問題があれば、新しいワーカープロセスを止めて、古いマスタープロセスにHUPを送れば以前の状態に戻ると思います(やってはいませんけど)。

確認ができたら、古いマスタープロセスをQUITシグナルで止めます。

[hiyama nginx]$ sudo kill -QUIT 3126
[hiyama nginx]$ pgrep nginx
22192
22194
[hiyama nginx]$

おしまい

以上に紹介した手順は決まりきったものですが、注意深くやらないと間違いを犯しかねません。一連の操作をシェルスクリプトにしたものが、http://webdevrefinery.com/forums/topic/8348-nginx-update-script/ にあります。ただし、ディレクトリ/ファイルのパスなどは環境に応じて書き換える必要があります。

この方法はNginxのバージョンアップ以外に、新しいモジュールを追加したバイナリを作ったときにも使えます。Webサーバーを止めずに更新可能なのはいいですね。

[追記]

configureにより作られたMakefileを見ると、upgradeというターゲットが準備されていました。

古いマスタープロセスのPIDは、nginx.pid.oldbin に書き出されるようです。また、 kill -WINCH しないで、いきなり kill -QUIT だけでも大丈夫みたい。

upgrade:
        /usr/local/nginx/sbin/nginx -t

        kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
        sleep 1
        test -f /usr/local/nginx/logs/nginx.pid.oldbin

        kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`

make upgrade ってのが一番簡単そうですね。

[/追記]