Nginx UnitをCentOS7で動かしてみる
目次
こんにちは。
開発チームのワイルド担当、まんだいです。
みんな大好き、Nginxのニューファミリー、「Nginx Unit」が少し前に登場しましたね。
Nginx Unitはどんな風に使うのか、色々調べてみました。
目次
Nginx Unitとは?
Nginx Unitは、Nginxと同じくWebアプリケーションサーバーを担うミドルウェアです。
Nginx Unitの特長を挙げると
- 動的に設定ファイルの修正ができる(リスタート不要)
- 単一のNginxで複数のプログラミング言語のサービスが稼働可能
というところがあると言われています。
今回は、実際にインストールしてみてどんな感じかつかめればと思っています。
インストール方法
CentOSの場合、yum経由でインストールが可能なので、非常にお手軽です。
ほぼ公式ドキュメントの手順をなぞっただけですが、とにかくインストールしてみましょう。
まずはNginx Unitのリポジトリを登録します。
sudo vi /etc/yum.repos.d/unit.repo # 以下の内容を貼り付け [unit] name=unit repo baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/ gpgcheck=0 enabled=1
以上で下準備は完了です。
続いてyumコマンドを流します。
yum install unit 読み込んだプラグイン:fastestmirror, langpacks Loading mirror speeds from cached hostfile * base: ftp.riken.jp * epel: mirror.dmmlabs.jp * extras: ftp.riken.jp * nux-dextop: li.nux.ro * remi-safe: mirror.bebout.net * updates: ftp.riken.jp 依存性の解決をしています --> トランザクションの確認を実行しています。 ---> パッケージ unit.x86_64 0:0.1-1.el7.ngx を インストール --> 依存性の処理をしています: libphp5-5.4.so()(64bit) のパッケージ: unit-0.1-1.el7.ngx.x86_64 --> トランザクションの確認を実行しています。 ---> パッケージ php-embedded.x86_64 0:5.4.16-42.el7 を インストール --> 依存性の処理をしています: php-common(x86-64) = 5.4.16-42.el7 のパッケージ: php-embedded-5.4.16-42.el7.x86_64 --> トランザクションの確認を実行しています。 ---> パッケージ php-common.x86_64 0:5.4.16-42.el7 を インストール --> 依存性の処理をしています: libzip.so.2()(64bit) のパッケージ: php-common-5.4.16-42.el7.x86_64 --> トランザクションの確認を実行しています。 ---> パッケージ libzip.x86_64 0:0.10.1-8.el7 を インストール --> 依存性解決を終了しました。 依存性を解決しました ~ 中略 ~ Thank you for installing NGINX Unit! You may want to load demo configuration and check a couple of apps: # service unitd start # service unitd restoreconfig /usr/share/doc/unit/examples/example.config # curl http://localhost:8300/ # curl http://localhost:8400/ Online documentation is available at http://unit.nginx.org/ ---------------------------------------------------------------------- 検証中 : php-embedded-5.4.16-42.el7.x86_64 1/4 検証中 : libzip-0.10.1-8.el7.x86_64 2/4 検証中 : php-common-5.4.16-42.el7.x86_64 3/4 検証中 : unit-0.1-1.el7.ngx.x86_64 4/4 インストール: unit.x86_64 0:0.1-1.el7.ngx 依存性関連をインストールしました: libzip.x86_64 0:0.10.1-8.el7 php-common.x86_64 0:5.4.16-42.el7 php-embedded.x86_64 0:5.4.16-42.el7 完了しました!
PHP(しかもVer.5!)が依存チェックで上がってくるのは謎です(恐らく実行環境も合わせて提供するため、baseリポジトリから引っ張ってきている)。
既にPHPがインストールされている場合や、PHP7環境で利用したい場合は、ソースインストールの方が良さそうです。
ソースインストールの場合、実行環境に合わせもライブラリを用意し、コンパイルする必要があります。
特にPHP7を利用する場合はyumでインストールは難しそうなので、この辺りの手順に沿ってトライしてみてください。
とりあえずサービスを起動
先ほどのyumでのインストール画面の最後に、サービスの起動用のコマンドが書かれていましたので、まずはこれを流してみようと思います。
CentOS7必須の割には、serviceコマンドで書いてあるので、最近覚えてsystemctlコマンドを披露しますよ!
# まずはサービスの起動 sudo systemctl start unitd # コンフィグファイルのリストア $ service unitd restoreconfig /usr/share/doc/unit/examples/example.config Restoring configuration from /usr/share/doc/unit/examples/example.config... { "success": "Reconfiguration done." }
2つ目のコマンドは、systemctlコマンドにどう書き換えればいいかさっぱりわからなかったので、素直にserviceコマンドを利用しました。
ちなみにですが、一つ目のコマンドをserviceコマンドのまま実行すると、以下のようになります。
sudo service unitd start Redirecting to /bin/systemctl start unitd.service
ちゃんと実行されますが、systemctlコマンドで実行したよといちいち言ってくる訳ですね。
ですが、restoreconfigを付けて実行した場合は、こういった注意書きは一切なかったので、serviceコマンドが正攻法なのでは?という気もしています。
ここまでやれば、正常に起動しているので、curlコマンドで動作確認...と行きたいところですが、ここがポイントなんですが、Nginxの場合、上のコマンドって実行順序が逆ですよね。
Nginxは、設定ファイルの更新をした場合、必ずリスタートがセットになるので、運用中の設定変更がしにくいという場面がどうしても出てきます。
さらっと流してしまいそうなところですが、Nginx Unitの恩恵がチラリと垣間見れる瞬間です。
では改めて、webサーバーにアクセスしてみます。
$ curl http://localhost:8300/ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head> <style type="text/css"> body {background-color: #ffffff; color: #000000;} body, td, th, h1, h2 {font-family: sans-serif;} pre {margin: 0px; font-family: monospace;} a:link {color: #000099; text-decoration: none; background-color: #ffffff;} a:hover {text-decoration: underline;} table {border-collapse: collapse;} .center {text-align: center;} .center table { margin-left: auto; margin-right: auto; text-align: left;} .center th { text-align: center !important; } td, th { border: 1px solid #000000; font-size: 75%; vertical-align: baseline;} h1 {font-size: 150%;} h2 {font-size: 125%;} .p {text-align: left;} .e {background-color: #ccccff; font-weight: bold; color: #000000;} .h {background-color: #9999cc; font-weight: bold; color: #000000;} .v {background-color: #cccccc; color: #000000;} .vr {background-color: #cccccc; text-align: right; color: #000000;} img {float: right; border: 0px;} hr {width: 600px; background-color: #cccccc; border: 0px; height: 1px; color: #000000;} </style> <title>phpinfo()</title><meta name="ROBOTS" content="NOINDEX,NOFOLLOW,NOARCHIVE" /></head> <body><div class="center"> <table border="0" cellpadding="3" width="600"> <tr class="h"><td> <a href="http://www.php.net/"><img border="0" src="/?=PHPE9568F34-D428-11d2-A769-00AA001ACF42" alt="PHP Logo" /></a> <h1 class="p">PHP Version 5.4.16</h1> </td></tr> </table><br /> ~ 中略 ~ <h3>PHP License</h3><table border="0" cellpadding="3" width="600"> <tr class="v"><td> This program is free software; you can redistribute it and/or modify it under the terms of the PHP License as published by the PHP Group and included in the distribution in the file: LICENSE This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. If you did not receive a copy of the PHP license, or have any questions about PHP licensing, please contact [email protected]. </td></tr> </table><br /> $ curl http://localhost:8400/ 2017-10-17 02:11:15 AM ENV Variables: LANG ja_JP.utf8 PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin UNITD_OPTIONS --log /var/log/unitd.log --pid /run/unitd.pid
8300番ポートは、通常のWebサーバーの動きをしていて、phpinfo()が実行されているようです。
8400番ポートは今のところよくわからないですが、実行環境の設定を表示しているように見えますね。
このポートの謎は、後ほど。
うまくインストールできたようなので、次は設定周りを確認します。
Nginx Unitの設定を確認する
今のところ、Nginx Unitの設定ファイルっぽいのは、/usr/share/doc/unit/examples/example.config しか出てきていませんので、これを見てましょう。
less /usr/share/doc/unit/examples/example.config { "applications": { "example_php": { "type": "php", "user": "nobody", "workers": 2, "root": "/usr/share/doc/unit/examples/php-app", "index": "index.php" }, "example_python": { "type": "python", "user": "nobody", "workers": 2, "path": "/usr/share/doc/unit/examples/python-app", "module": "wsgi" }, "example_go": { "type": "go", "user": "nobody", "executable": "/tmp/go-app" } }, "listeners": { "*:8300": { "application": "example_php" }, "*:8400": { "application": "example_python" }, "*:8500": { "application": "example_go" } } }
ファイルを開いてみると、JSONファイルでした。
JSONファイルなら、設定構造が分かりやすいですね。
先ほどでてきた、「http://localhost:8400」の正体は、pythonプログラム用の待受URLだったようです。
ドキュメントを読んでみると、ソケット通信経由で設定の確認ができるよう。
こんな感じです。
curl --unix-socket /path/to/socket http://localhost/
ただ、そのためには、ソケットファイルの場所がわからないといけないので、少しプロセス側の動きから、この辺りを追っていきたいと思います。
まずは、psコマンドで、Nginx Unitのプロセスを特定します。
ps auxwwwf | grep [u]nit root 5821 0.0 0.0 18256 636 ? Ss 00:21 0:00 unit: main [/usr/sbin/unitd --log /var/log/unitd.log --pid /run/unitd.pid] nobody 5824 0.0 0.0 18256 680 ? S 00:21 0:00 \_ unit: controller nobody 5825 0.0 0.0 18256 680 ? S 00:21 0:00 \_ unit: router
Nginx Unitは、デーモン・コントローラー・ルーターの3プロセスで稼働しているようです。
設定によっては、増減するかも知れませんが、今のところはこんな感じの立て付けになっています。
次に、lsofコマンドで、5821番プロセスが掴んでいるファイルを調べます。
lsof -p 5821 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME unitd 5821 root cwd DIR 253,0 4096 2 / unitd 5821 root rtd DIR 253,0 4096 2 / unitd 5821 root txt REG 253,0 397232 806046 /usr/sbin/unitd unitd 5821 root mem REG 253,0 37352 805753 /usr/lib64/libnss_sss.so.2 unitd 5821 root mem REG 253,0 62184 787847 /usr/lib64/libnss_files-2.17.so unitd 5821 root mem REG 253,0 2118128 787829 /usr/lib64/libc-2.17.so unitd 5821 root mem REG 253,0 143944 787855 /usr/lib64/libpthread-2.17.so unitd 5821 root mem REG 253,0 19776 787835 /usr/lib64/libdl-2.17.so unitd 5821 root mem REG 253,0 44448 787859 /usr/lib64/librt-2.17.so unitd 5821 root mem REG 253,0 1141928 787837 /usr/lib64/libm-2.17.so unitd 5821 root mem REG 253,0 155464 806682 /usr/lib64/ld-2.17.so unitd 5821 root 0u CHR 1,3 0t0 1028 /dev/null unitd 5821 root 1u CHR 1,3 0t0 1028 /dev/null unitd 5821 root 2w REG 253,0 258231 136119 /var/log/unitd.log unitd 5821 root 3u a_inode 0,9 0 5832 [eventpoll] unitd 5821 root 4u a_inode 0,9 0 5832 [signalfd] unitd 5821 root 5u a_inode 0,9 0 5832 [eventfd] unitd 5821 root 6u unix 0xffff8800783ba400 0t0 48362 /var/run/control.unit.sock # <- これ unitd 5821 root 7w REG 253,0 258231 136119 /var/log/unitd.log unitd 5821 root 8u unix 0xffff880023ebb400 0t0 49423 socket unitd 5821 root 9u unix 0xffff880023ebb800 0t0 49424 socket unitd 5821 root 12u unix 0xffff8800b1954800 0t0 49428 socket unitd 5821 root 13u unix 0xffff880023eb9c00 0t0 49430 socket
どうやら「/var/run/control.unit.sock」がソケットファイルになるようなので、設定確認用のコマンドは、以下のようになります。
curl --unix-socket /var/run/control.unit.sock http://localhost/ { "applications": { "example_php": { "type": "php", "user": "nobody", "workers": 2, "root": "/usr/share/doc/unit/examples/php-app", "index": "index.php" }, "example_python": { "type": "python", "user": "nobody", "workers": 2, "path": "/usr/share/doc/unit/examples/python-app", "module": "wsgi" }, "example_go": { "type": "go", "user": "nobody", "executable": "/tmp/go-app" } }, "listeners": { "*:8300": { "application": "example_php" }, "*:8400": { "application": "example_python" }, "*:8500": { "application": "example_go" } } }
curlコマンドでWebサーバーの設定を確認するっていうのがかなり新鮮な気がするのですが、内容は「/usr/share/doc/unit/examples/example.config」と同じものが返ってきました。
無事、テスト用のコンフィグファイルが読み込まれているということですね。
次は、設定の変更をしてみたいと思います。
Nginx Unitの設定を変更する
公式ドキュメントを見てみると、設定の変更もcurlコマンドでやるようです。
ドキュメントから引用してみると、
# Example: Create a Full Configuration curl -X PUT -d @/path/to/start.json \ --unix-socket ./control.unit.sock http://localhost/ # Example: Create an Application Object curl -X PUT -d @/path/to/wiki.json \ --unix-socket ./control.unit.sock http://localhost/applications/wiki
一つ目のJSONファイルを適用する場合はすうっと理解できたのですが、2つ目の設定方法はやばいですね。
一部分だけJSONの適用ができる訳ですが、どの部分に適用するかをURLで指定するなんて……!!
自分で作ったJSONファイルを読み込むテストもやってみたいと思います。
簡単に、以下のようなJSONファイルを用意しました。
{
"type": "php",
"user": "nobody",
"workers": 4,
"root": "/var/www/html",
"index": "index.php"
}
一般的な「/var/www/html」以下をドキュメントルートにする簡易な設定ですが、うまくいくでしょうか。
このファイルを、「/home/hogehoge/test-php.json」として保存します。
これを、curlコマンドを使って、Nginx Unitに送信してみましょう!
追加位置は、applications直下にします。
curl -X PUT -d @/home/hogehoge/test-php.json --unix-socket /var/run/control.unit.sock http://localhost/applications/test { "success": "Reconfiguration done." }
うまく登録できたようです。
合わせて現在の設定状況を確認しましょう。
curl --unix-socket /var/run/control.unit.sock http://localhost/ { "applications": { "example_php": { "type": "php", "user": "nobody", "workers": 2, "root": "/usr/share/doc/unit/examples/php-app", "index": "index.php" }, "example_python": { "type": "python", "user": "nobody", "workers": 2, "path": "/usr/share/doc/unit/examples/python-app", "module": "wsgi" }, "example_go": { "type": "go", "user": "nobody", "executable": "/tmp/go-app" }, "test": { "type": "php", "user": "nobody", "workers": 4, "root": "/var/www/html", "index": "index.php" } }, "listeners": { "*:8300": { "application": "example_php" }, "*:8400": { "application": "example_python" }, "*:8500": { "application": "example_go" } } }
うまく追加できているようです。
それでは、curlコマンドでうまく動くか確認したい……ところですが、Listenerが登録されていないとルーティングされないので、ルーティング用のJSONファイルも合わせて追加します。
{
"application": "test"
}
上のJSONを先ほどと同じようにcurlを使って登録していきます。
curl -X PUT -d @/home/hogehoge/test-php-listener.json --unix-socket /var/run/control.unit.sock http://localhost/listeners/*:8301 { "success": "Reconfiguration done." }
最後のURLは、普通はありえないですが、厳密にはこれはURLではないのであまり気にしないようにします。
successが返ってきたら、設定全体を確認してみます。
curl --unix-socket /var/run/control.unit.sock http://localhost/ { "applications": { "example_php": { "type": "php", "user": "nobody", "workers": 2, "root": "/usr/share/doc/unit/examples/php-app", "index": "index.php" }, "example_python": { "type": "python", "user": "nobody", "workers": 2, "path": "/usr/share/doc/unit/examples/python-app", "module": "wsgi" }, "example_go": { "type": "go", "user": "nobody", "executable": "/tmp/go-app" }, "test": { "type": "php", "user": "nobody", "workers": 4, "root": "/var/www/html", "index": "index.php" } }, "listeners": { "*:8300": { "application": "example_php" }, "*:8400": { "application": "example_python" }, "*:8500": { "application": "example_go" }, "*:8301": { "application": "test" } } }
うまく設定が反映されているようです。
curlコマンド、もしくはブラウザで「http://localhost:8301」を確認してみると、うまく表示されていました。
(このドキュメントルート以下には、fuelPHPで開発していたコンテンツが残っていたのですが、問題なしです)。
Nginx Unitの設定を削除する
変更の場合は、curlのHTTPメソッドをPUTで送ったので、削除する場合は、もちろんDELETEメソッドですよね。
公式ドキュメントを見ずとも、何となく当たりは付きそうですが、ここは念のため確認しておきます。
削除をcurlで行う場合のcurlコマンドは、以下の形です。
curl -X DELETE --unix-socket ./control.unit.sock \ 'http://localhost/listeners/*:8400'
先ほど追加したListenerの設定を削除してみたいと思います。
curl -X DELETE --unix-socket /var/run/control.unit.sock http://localhost/listeners/*:8301 { "success": "Reconfiguration done." }
はい、無事に削除できたようです。
この辺りは非常に簡単ですね。
ちなみにですが、インプット、アウトプットともにJSONなので、設定の保存も非常に簡単です。
# curlの結果をファイルに書き落とす curl --unix-socket /var/run/control.unit.sock http://localhost/ > /path/to/unitd.conf.json # 書き込めているか確認 cat /path/to/unitd.conf.json { "applications": { "example_php": { "type": "php", "user": "nobody", "workers": 2, "root": "/usr/share/doc/unit/examples/php-app", "index": "index.php" }, "example_python": { "type": "python", "user": "nobody", "workers": 2, "path": "/usr/share/doc/unit/examples/python-app", "module": "wsgi" }, "example_go": { "type": "go", "user": "nobody", "executable": "/tmp/go-app" }, "test": { "type": "php", "user": "nobody", "workers": 4, "root": "/var/www/html", "index": "index.php" } }, "listeners": { "*:8300": { "application": "example_php" }, "*:8400": { "application": "example_python" }, "*:8500": { "application": "example_go" } } } # Nginx Unitを再起動 systemctl restart unitd # 設定を確認すると、何も入っていない curl --unix-socket /var/run/control.unit.sock http://localhost/ { "listeners": {}, "applications": {} } # 先ほどファイルに出力したJSONデータを投入 curl -X PUT -d @/root/unitd.conf.json --unix-socket /var/run/control.unit.sock http://localhost { "success": "Reconfiguration done." } # 設定が反映されているか確認 curl --unix-socket /var/run/control.unit.sock http://localhost/ { "applications": { "example_php": { "type": "php", "user": "nobody", "workers": 2, "root": "/usr/share/doc/unit/examples/php-app", "index": "index.php" }, "example_python": { "type": "python", "user": "nobody", "workers": 2, "path": "/usr/share/doc/unit/examples/python-app", "module": "wsgi" }, "example_go": { "type": "go", "user": "nobody", "executable": "/tmp/go-app" }, "test": { "type": "php", "user": "nobody", "workers": 4, "root": "/var/www/html", "index": "index.php" } }, "listeners": { "*:8300": { "application": "example_php" }, "*:8400": { "application": "example_python" }, "*:8500": { "application": "example_go" } } }
うまくいきました!
まとめ
期待のニューカマー、Nginx Unitはいかがだったでしょうか?
公式ドキュメントには、Nginxでリバースプロキシを行って、Nginx Unitにソケット通信でリクエストを流す組み合わせについても書かれていたり、単独で使うには設定の書き換えが簡単すぎたり起動時の設定反映にクセがありますが、Nginxの融通が効かないところをうまく補完する存在なのではないかと思います。
バージョンは0.1。
勿論ベータ版。
今後、どういう風に洗練されていくのか楽しみですね。
以上です。