NGINX 微服务 Unit + PHP 初探
简介
NGINX Unit 是一个动态的网络应用服务器,它的设计初衷是为了运行多种编程语言。如有需要,通过 API 可以动态配置已有应用的参数。
核心功能
- 可使用 RESTful JSON API 动态配置服务器
- 可同时运行多语言及多版本的应用
- 动态语言的进程管理功能(开发中)
- TLS 支持(开发中)
- TCP, HTTP, HTTPS, HTTP/2 路由和代理(开发中)
支持的语言
- Python
- PHP
- Go
- JavaScript / Node.js(开发中)
- Java(开发中)
- Ruby(开发中)
使用包管理器安装
目前只支持 CentOS 7.0 和 Ubuntu 16.04。
CentOS
- 创建 /etc/yum.repos.d/unit.repo,内容如下:
[unit] name=unit repo baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/ gpgcheck=0 enabled=1
- 安装
yum install unit
Ubuntu
- 下载 秘钥,该秘钥用于验证 NGINX 源的签名,执行
sudo apt-key add nginx_signing.key
- 在 /etc/apt/sources.list 增加如下内容:
deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx
- 安装
apt-get update apt-get install unit
从源码编译安装
安装依赖
- Ubuntu
apt-get install build-essential php-dev libphp-embed
- CentOS
yum install gcc make php-devel php-embedded
配置 PHP 模块,最终会生成名为 php.unit.so
的文件
git clone https://github.com/nginx/unit
cd unit
./configure
./configure php
如果是自定义安装的 PHP,需要用如下命令:
./configure php --module=<prefix> --config=<script-name> --lib-path=<pathname>
其中的参数含义如下:
- --module
设置 php 模块的文件名前缀,最终生成的文件名为<prefix>.unit.so
- --config
php-config 脚本所在的路径 - --lib-path
PHP library 所在的路径
以 PHP7.0 为例,命令如下:
./configure php --module=php70 \
--config=/usr/lib64/php7.0/php-config \
--lib-path=/usr/lib64/php7.0/lib64
得到如下输出:
configuring PHP module
checking for PHP ... found
+ PHP version: 7.0.22-0ubuntu0.16.04.1
+ PHP SAPI: [apache2handler embed cgi cli fpm]
checking for PHP embed SAPI ... found
+ PHP module: php70.unit.so
编译安装
make all
make install
从 Docker 安装
docker pull airycanon/nginx-unit-php
配置和运行
配置文件
一个基础的配置文件必须包含以下两部分:
-
应用
下面的示例描述了一个名为 blog 的 PHP 应用
{ "applications": { "blog": { "type": "php", "workers": 20, "root": "/www/blogs/scripts", "index": "index.php" } } }
配置项 描述 type 应用的编程语言 workers workers 的数量 root 应用的根目录 index 应用入口文件 working_directory (可选) 应用的工作目录 script(可选) 脚本路径,基于应用根目录的相对路径,访问应用内的任意 URL 均会运行该脚本 user (可选) 运行进程的用户,默认为 nobody group (可选) 用户所在的用户组,默认为 user 的用户组 -
监听器
监听器指定了 IP 和 端口以及绑定的应用,下面的示例中,端口 8300 的请求全部会被发送至 blogs 这个应用:
{ "listeners": { "*:8300": { "application": "blog" } }, ... }
创建应用
这里为了简化步骤,采用了 Docker
的方式运行。
-
首先创建两个目录
applications
run
作为容器的 Volume 挂载mkdir applications run docker run -v `pwd`/applications:/applications -v `pwd`/run:/var/run:rw -p 8300:8300 -d airycanon/nginx-unit-php
-
创建一个配置文件
json/config.json
,内容如下:{ "listeners": { "*:8300": { "application": "blog" } }, "applications": { "blog": { "type": "php", "workers": 20, "root": "/applications/blog", "index": "index.php" } } }
-
创建一个
applications/blog/index.php
,内容如下<?php phpinfo(); ?>
-
默认情况下,Unit 通过
Unix domain socket
文件unit.control.sock
提供 API,通过如下命令创建应用:curl -X PUT -d @./json/config.json --unix-socket ./run/control.unit.sock http://localhost/
访问 http://localhost:8300 可以看到 phpinfo 的页面
查看应用配置
-
查看所有应用的配置:
curl --unix-socket ./run/control.unit.sock http://localhost/ { "applications": { "blogs": { "type": "php", "user": "nobody", "group": "nobody", "workers": 20, "root": "/applications/blog", "index": "index.php" } }, "listeners": { "*:8300": { "application": "blog" }, } }
-
查看某个应用的配置:
curl --unix-socket ./run/control.unit.sock http://localhost/applications/blog { "type": "php", "user": "nobody", "group": "nobody", "workers": 20, "root": "/applications/blog", "index": "index.php" }
修改应用
- 修改 *:8300 监听绑定的应用:
curl -X PUT -d '"blog-dev"' --unix-socket ./run/control.unit.sock http://localhost/listeners/*:8300/application { "success": "Reconfiguration done." }
- 修改应用的根目录:
curl -X PUT -d '"/applications/blog-dev"' --unix-socket ./run/control.unit.sock http://localhost/applications/blog/root { "success": "Reconfiguration done." }
删除应用
- 删除对 *:8300 端口的监听:
curl -X DELETE --unix-socket ./run/control.unit.sock http://localhost/listeners/*:8300 { "success": "Reconfiguration done." }
- 删除应用:
curl -X DELETE --unix-socket ./run/control.unit.sock http://localhost/applications/blog { "success": "Reconfiguration done." }
与 NGINX 一起使用
使用 NGINX 作为代理
upstream unit_backend {
server 127.0.0.1:8300;
}
示例 1
server {
location / {
root /var/www/static-data;
}
location ~ \.php$ {
proxy_pass http://unit_backend;
proxy_set_header Host $host;
}
}
示例 2
server {
location /static {
root /var/www/files;
}
location / {
proxy_pass http://unit_backend;
proxy_set_header Host $host;
}
}
设置 Unix domain socket
的 API 可以被远程访问
由于 API 可以动态修改应用配置,请注意增加安全认证
server {
# Configure SSL encryption
server 443 ssl;
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/cert.key;
# Configure SSL client certificate validation
ssl_client_certificate /path/to/ca.pem;
ssl_verify_client on;
# Configure network ACLs
#allow 1.2.3.4; # Uncomment and change to the IP addresses and networks
# of the administrative systems.
deny all;
# Configure HTTP Basic authentication
auth_basic on;
auth_basic_user_file /path/to/htpasswd.txt;
location / {
proxy_pass http://unix:/var/run/control.unit.sock
}
}