nginxでUNIXドメインソケットを使っていると、restart
に失敗する場合があります。
# systemctl restart nginx
Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xe" for details.
この現象が発生すると、ソケットファイルを削除するまで起動できなくなります。
status
を見ると、UNIXドメインソケット関連の問題である事が分かります。
# systemctl status nginx
(中略)
nginx[1527]: nginx: [emerg] bind() to unix:/var/run/nginx.sock failed (98: Address already in use)
nginx[1527]: nginx: [emerg] bind() to unix:/var/run/nginx.sock failed (98: Address already in use)
nginx[1527]: nginx: [emerg] bind() to unix:/var/run/nginx.sock failed (98: Address already in use)
nginx[1527]: nginx: [emerg] bind() to unix:/var/run/nginx.sock failed (98: Address already in use)
nginx[1527]: nginx: [emerg] bind() to unix:/var/run/nginx.sock failed (98: Address already in use)
nginx[1527]: nginx: [emerg] still could not bind()
CentOS 6.x特有の問題かと思っていたのですが、CentOS 7.1でも発生しました。
困ったときのStack Exchange。下記が参考になりました。
http://unix.stackexchange.com/questions/164866/nginx-leaves-old-socket
At least as of version 1.8.0, Nginx will leave stale UNIX domain sockets when it is stopped using the SIGQUIT signal.
なるほど、graceful shutdownではUNIXドメインソケットが削除されなくなってしまったようです。本家のtracにも記載がありました。
SIGQUIT
でなくSIGTERM
を使えば良いので、起動スクリプトまたはサービス設定ファイルを変更します。処理中のリクエストが失敗してしまう事になりますが、無停止にしたければrestart
でなくreload
にすれば良いので、まあ問題ないでしょう。
stop() {
echo -n $"Stopping $prog: "
- killproc $prog -QUIT
+ killproc $prog -TERM
-ExecStop=/bin/kill -s QUIT $MAINPID
+ExecStop=/bin/kill -s TERM $MAINPID
これはnginx+systemd特有の問題なのですが、statusにエラーっぽいものが記録されています。
# systemctl status nginx
(中略)
systemd[1]: Failed to read PID from file /run/nginx.pid: Invalid argument
nginx.serviceのPIDFile=/run/nginx.pid
を消せば出なくなるのですが、実害は無いようなので放置で。