どんな事でもお気軽にお問い合わせください
0120-803-656
24時間受付いたします

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>&nbsp;
<h1 class="p">PHP Version 5.4.16</h1>
</td></tr>
</table><br />

~ 中略 ~

&nbsp;
<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 license@php.net.


</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。
勿論ベータ版。
今後、どういう風に洗練されていくのか楽しみですね。

 
以上です。


お問い合わせ 採用情報 エンジニアブログ
ISO27001認証
Contact PageTop
株式会社ビヨンド

© beyond Co., Ltd. All rights reserved.