無停止でnginxを手動upgradeする

# 無停止でnginxのupgradeを行う手順

無停止でnginxを新しいバージョンへアップグレードする手順です。

だいたいここに書いてあります。
http://nginx.org/en/docs/control.html#upgrade

## 作業内容
nginx 1.7.3 -> 1.9.9 へアップグレード

## 環境
- OS  
CentOS 6.6
- nginx1.7.3が起動している  
nginx.confなどがすでに存在  
nginx1.7.3 は ソースからインストールされている(/usr/local/nginx/以下)
- php-fpm等は起動していない

### 作業はすべてrootユーザで実施します
kill/make install等でsudoが必要な場合があります。
rootユーザで実施するためその辺りは考慮していません。

## nginx 1.9.9 のバイナリの用意
configureオプションは適当に。

```
# wget http://nginx.org/download/nginx-1.9.9.tar.gz
# tar zxf nginx-1.9.9.tar.gz
# cd nginx-1.9.9 ; pwd
# ./configure
# make
# make install
```

この状態では、まだアップグレードされていません。

```
# /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.7.3
```

この状態で`make upgrade`すると自動で置き換わります。
すごいですね。


## アップグレード手順
最初に手順だけをあげると下記となります。

```
# /usr/local/nginx/sbin/nginx -t
# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
# kill -WINCH `cat /usr/local/nginx/logs/nginx.pid.oldbin`
# kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
# /usr/local/nginx/sbin/nginx -V
```

## 挙動を見ていきます

- アップグレード前の状態  
masterプロセスのpidは`4388`です。

```
# ps auxww | grep 'nginx'
root      4388  0.1  0.3 105792  6304 ?        S    02:29   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/ngin /etc/nginx.conf
nginx     4389  0.0  0.1 106228  2836 ?        S    02:29   0:00 nginx: worker process
nginx     4390  0.0  0.1 106228  2904 ?        S    02:29   0:00 nginx: worker process
nginx     4391  0.0  0.1 106228  2884 ?        S    02:29   0:00 nginx: worker process
root      4397  0.0  0.0   6388   680 pts/2    S+   02:29   0:00 grep --color=auto nginx
#
```

1.config test

```
# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
#
```

2.USR2シグナル送信

- 新しいバイナリのnginxプロセスが起動
- アップグレード前nginxのpidファイルが`nginx.pid.oldbin`となる
- アップグレード後のnginxが処理を開始

```
# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
# ps auxwwf | grep 'ngin[x]'
root      4388  0.0  0.3 105792  6304 ?        S    02:29   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/ngin /etc/nginx.conf
nginx     4389  0.0  0.1 106228  2836 ?        S    02:29   0:00  \_ nginx: worker process
nginx     4390  0.0  0.1 106228  2904 ?        S    02:29   0:00  \_ nginx: worker process
nginx     4391  0.0  0.1 106228  2884 ?        S    02:29   0:00  \_ nginx: worker process
root      4464  0.0  0.3 103516  6240 ?        S    02:31   0:00  \_ nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/etc/nginx.conf
nginx     4465  0.0  0.1 103944  2828 ?        S    02:31   0:00      \_ nginx: worker process                                        
nginx     4466  0.0  0.1 103944  2896 ?        S    02:31   0:00      \_ nginx: worker process                                        
nginx     4467  0.0  0.1 103944  2872 ?        S    02:31   0:00      \_ nginx: worker process                                        
#
#
# ls -la /usr/local/nginx/logs/nginx.pid*
-rw-r--r-- 1 root  root         5 Feb  4 02:31 nginx.pid
-rw-r--r-- 1 root  root         5 Feb  4 02:29 nginx.pid.oldbin
#
```

アップグレード後nginxのmasterプロセスが起動しています。pid`4464`のものになります。
アップグレード前nginxのmasterプロセス`4388`の方も起動しているのが分かります。

### USR2を送ると
- アップグレード後masterプロセスとアップグレード前masterプロセスが混在する事に
- アップグレード後nginxのpid -\> `nginx.pid`
- アップグレード前nginxのpid -\> `nginx.pid.oldbin`

以降、`nginx.pid.oldbin`へシグナルを送信することでアップグレード前nginxを、
`nginx.pid`へシグナルを送る事でアップグレード後nginxを操作できます。  
  
  
3.WINCHシグナルの送信

- アップグレード前masterプロセスがworkerプロセスを終了し、アップグレード後のnginxのみで処理を開始  

```
# kill -WINCH `cat /usr/local/nginx/logs/nginx.pid.oldbin`
#
# ps auxwwf | grep 'ngin[x]'
root      4388  0.0  0.3 105792  6304 ?        S    02:29   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/ngin /etc/nginx.conf
root      4464  0.0  0.3 103516  6240 ?        S    02:31   0:00  \_ nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/etc/nginx.conf
nginx     4465  0.0  0.1 103944  2828 ?        S    02:31   0:00      \_ nginx: worker process                                        
nginx     4466  0.0  0.1 103944  2896 ?        S    02:31   0:00      \_ nginx: worker process                                        
nginx     4467  0.0  0.1 103944  2872 ?        S    02:31   0:00      \_ nginx: worker process                                        
#
```

アップグレード前masterプロセスであるpid`4388`が存在し、workerプロセスが無くなっています。

### WINCHシグナルを送ると
アップグレード前masterプロセスが管理下にあるworkerプロセスを終了させます。
この状態では、すべてのリクエストを新しいnginxが処理することになります。
この状態で、Web閲覧が不可能等である場合は切り戻す事になります。
切り戻し手順は後述します。

4.QUITシグナルをアップグレード前nginxに送信

- アップグレード前nginxのマスタープロセスが完全に終了

```
# kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
# ps auxwwf | grep 'ngin[x]'
root      4464  0.0  0.3 103516  6240 ?        S    02:31   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/ngin /etc/nginx.conf
nginx     4465  0.0  0.1 103944  2828 ?        S    02:31   0:00  \_ nginx: worker process
nginx     4466  0.0  0.1 103944  2896 ?        S    02:31   0:00  \_ nginx: worker process
nginx     4467  0.0  0.1 103944  2872 ?        S    02:31   0:00  \_ nginx: worker process
#
# ls -l /usr/local/nginx/logs/nginx.pid
-rw-r--r-- 1 root root 5 Feb  4 02:31 /usr/local/nginx/logs/nginx.pid
#
#
# /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.9.9
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
#
```

アップグレード前のmasterプロセスが完全に終了しています。
これでアップグレードは完了となります。


### 切り戻し手段
途中で問題が発生した場合は切り戻す事になります。方法は2つです。

- アップグレード前masterプロセスへHUPシグナルを送信
アップグレード後masterプロセスを終了し、アップグレード前masterプロセスがworkerプロセスを作成します。

- アップグレード後TERMシグナルを送信
アップグレード前masterプロセスがアップグレード後masterプロセスの終了を検知すると、workerプロセスを作成します。

```
# kill -s HUP `cat /usr/local/nginx/logs/nginx.pid.oldbin`
```