PHP, Python, Golang を NGINX Unit で動かしてみた
NGINX Unit
ホームページは以下
もしくはミラーだけどGitHubが以下となる
RestAPIやJSONで設定できる、phpのPHP-FPMやpythonのwsgiサーバーなど言語ごとのアプリケーション・サーバーを集約したアプリケーションサーバーという感じ。なのでNginxの後ろで動くサーバーという認識で大丈夫なのかな?
まだversionは0.1なので、今後どんどん成長していくはず。
現状は以下に対応しているとのこと
Python 2.6, 2.7, 3
PHP 5, 7
Go 1.6 or later
ざっくりとした所感
- プロダクトに関して
- 現状のドキュメントに関して
と、言うことで、3つの言語で動かした際の動かし方を残しておく (最初にドキュメントを読んで、詰まった際の補助資料くらいに思うと良いはずです。)
動かし方
インストール後のサービスの動かし方
systemctl enable unitd.service systemctl start unitd.service
気づき
curl --unix-socket /run/control.unit.sock http://localhost/
で設定を確認できる.systemctl restart unitd.service
をしたら設定が揮発する模様?
各言語ごとの動かし方をまとめ
要点だけ
PHP
設定で指定する root
に index
で指定するファイルを置くだけ
Python
設定で指定するpath
に wsgi.py
を設置, wsgi.py
の中で application
がwsgiアプリケーションになっていればOK
例えばFlaskなら以下の様な感じ
#!/usr/bin/env python from flask import Flask application = Flask(__name__) @application.route("/") def index(): return "<h1>Hello NGINX Unit</h1>"
Golang
こっちが一筋縄では行かなかった。
まず、unit
をインストールしているだけではダメでCentOSでは unit-devel
をインストールしておく必要があることと、
export GOPATH=/home/user/go_apps
をしておいた後に、 unit
パッケージをインポートして使う。
上記の状態で、以下のようなソースをビルドし、設定の executable
で指定したパスに配置する。
package main import ( "fmt" "net/http" "unit" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "<h1>Hello NGINX Unit</h1>") }) unit.ListenAndServe(":8000", nil) }
普通のgolangのアプリと違うのは、 ListenAndServe
するのが、httpではなく unit
な点だと思う
個人的感想
NGINXが新しくサーバーをリリースする!というのは個人的に驚き。
ApacheよりもNGINXに慣れ親しんでいる世代ということもあり、頑張ればソースコードを読み切る事ができそうな気がする規模なので読みたい。
以下は全部この記事を書いた際のメモ
とりあえず動かしてみる
CentOS7でやってみる
[root@mycentos7 go-app]# cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core)
↑のインストールにそって yum -y install unit
で問題なくうまくいく
ドキュメント的にはインストールで終わっているので動かし方を探ると以下の感じで動き出す。定石どおり。
[root@mycentos7 unit]# systemctl status unitd ● unitd.service - NGINX Unit Loaded: loaded (/usr/lib/systemd/system/unitd.service; disabled; vendor preset: disabled) Active: inactive (dead)
systemctl enable unitd systemctl start unitd
[root@mycentos7 unit]# systemctl status unitd ● unitd.service - NGINX Unit Loaded: loaded (/usr/lib/systemd/system/unitd.service; enabled; vendor preset: disabled) Active: active (running) since Fri 2017-09-08 00:42:25 JST; 6s ago Process: 2502 ExecStart=/usr/sbin/unitd $UNITD_OPTIONS (code=exited, status=0/SUCCESS) Main PID: 2503 (unitd) CGroup: /system.slice/unitd.service ├─2503 unit: main [/usr/sbin/unitd --log /var/log/unitd.log --pid /run/unitd.pid] ├─2505 unit: controller └─2506 unit: router
プロセスとしては動いていそう。
[root@mycentos7 unit]# ps aux | grep unitd root 2503 0.0 0.0 16168 632 ? Ss 00:42 0:00 unit: main [/usr/sbin/unitd --log /var/log/unitd.log --pid /run/unitd.pid] root 2516 0.0 0.0 112644 964 pts/0 R+ 00:44 0:00 grep --color=auto unitd
lsofを叩いてもunitdが掴んでいるポートはなさそう?
[root@mycentos7 log]# lsof -i COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME chronyd 715 chrony 1u IPv4 13918 0t0 UDP localhost:323 chronyd 715 chrony 2u IPv6 13919 0t0 UDP localhost:323 sshd 1038 root 3u IPv4 16617 0t0 TCP *:ssh (LISTEN) sshd 1038 root 4u IPv6 16626 0t0 TCP *:ssh (LISTEN) master 1648 root 13u IPv4 17586 0t0 TCP localhost:smtp (LISTEN) master 1648 root 14u IPv6 17587 0t0 TCP localhost:smtp (LISTEN) dhclient 2260 root 6u IPv4 18318 0t0 UDP *:bootpc dhclient 2260 root 20u IPv4 18307 0t0 UDP *:46788 dhclient 2260 root 21u IPv6 18308 0t0 UDP *:gilatskysurfer
ドキュメントを読むと
By default, the Unit API is available in the control socket file unit.control.sock.
と書いてあるので、探すと /run/control.unit.sock
があることがわかった。
[root@mycentos7 log]# find / -name 'control.unit.sock' /run/control.unit.sock
ミニマルと呼ばれている設定を投げつけることにする
ドキュメントどおり以下の設定ファイルを
{ "listeners": { "*:8300": { "application": "blogs" } }, "applications": { "blogs": { "type": "php", "workers": 20, "root": "/www/blogs/scripts", "index": "index.php" } } }
curl -X PUT -d @./start.json --unix-socket /run/control.unit.sock http://localhost/
で投げつける
レスポンスは以下の様
{ "success": "Reconfiguration done." }
ではphpを設置してみる。
[root@mycentos7 ~]# mkdir -p /www/blogs/scripts [root@mycentos7 ~]# touch /www/blogs/scripts/index.php [root@mycentos7 ~]# echo -e "<?php\n\nphpinfo();" > /www/blogs/scripts/index.php [root@mycentos7 ~]# cat /www/blogs/scripts/index.php <?php phpinfo();
curl localhost:8300
できちんと反応する
自分のホストのIPだと反応がないと思ったが、firewalldを切ったらきちんと反応した.
ちなみにドキュメントの何処かに書いて有りそうだが、 curl --unix-socket /run/control.unit.sock http://localhost/
で設定を確認できる.
また systemctl restart unitd.service
をしたら設定が揮発した。たぶんココらへんは今後改良される点なはず。
Python 編
こうなったらpythonもためしたい。
またしてもドキュメントどおりの設定を投げつけ、
{ "applications": { "blogs": { "type": "php", "user": "nobody", "group": "nobody", "workers": 20, "root": "/www/blogs/scripts", "index": "index.php" }, "wiki": { "type": "python", "user": "nobody", "group": "nobody", "workers": 10, "path": "/www/wiki", "module": "wsgi" } }, "listeners": { "*:8300": { "application": "blogs" }, "*:8400": { "application": "wiki" } } }
/www/wiki/wsgi.py
を以下のように作る
[root@mycentos7 wiki]# cat wsgi.py #!/usr/bin/env python from flask import Flask application = Flask(__name__) @application.route("/") def index(): return "<h1>Hello NGINX Unit</h1>"
こちらもそつなく動く
golang 編
ついでだからgolangも書いておく。今度はドキュメントからチョット変更して以下のような設定を投げつける
{ "applications": { "blogs": { "type": "php", "user": "nobody", "group": "nobody", "workers": 20, "root": "/www/blogs/scripts", "index": "index.php" }, "wiki": { "type": "python", "user": "nobody", "group": "nobody", "workers": 10, "path": "/www/wiki", "module": "wsgi" }, "go_server": { "type": "go", "executable": "/www/server/bin/server", "user": "nobody", "group": "nobody" } }, "listeners": { "*:8300": { "application": "blogs" }, "*:8400": { "application": "wiki" }, "*:8500": { "application": "go_server" } } }
でもって以下のようなコードを作って... と思ったら、golangは普通にnet/http
を使うのではダメな模様
https://github.com/nginx/unit/issues/8/ に書いてある/usr/share/doc/unit/examples/go-app/let-my-people.go
を覗くと unit
というパッケージがある
package main import ( "fmt" "net/http" "unit" ) func handler(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "text/plain"); fmt.Fprintf(w, "Method : %s\n", r.Method) fmt.Fprintf(w, "URL : %s\n", r.URL.Path) fmt.Fprintf(w, "Host : %s\n", r.Host) } func main() { http.HandleFunc("/", handler) unit.ListenAndServe("8000", nil) }
上記をissue真似て, sudo yum -y install unit-devel
をしたあとexport GOPATH=/home/user/go_apps
, 以下のファイルを go build
して /www/server/bin/server
としてファイルを設置したら curl localhost:8500
が上手くいった.
package main import ( "fmt" "net/http" "unit" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "<h1>Hello NGINX Unit</h1>") }) unit.ListenAndServe(":8000", nil) }