5 min read

NGINX 微服务 Unit + PHP 初探

NGINX 微服务 Unit + PHP 初探
Photo by KOBU Agency / Unsplash

简介

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

安装

yum install unit

创建 /etc/yum.repos.d/unit.repo,内容如下:

[unit]
name=unit repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1

Ubuntu

安装

apt-get update
apt-get install unit

在 /etc/apt/sources.list 增加如下内容:

deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx
deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx

下载 秘钥,该秘钥用于验证 NGINX 源的签名,执行

sudo apt-key add nginx_signing.key

从源码编译安装

安装依赖

CentOS

yum install gcc make php-devel php-embedded

Ubuntu

apt-get install build-essential php-dev libphp-embed

配置 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

配置和运行

配置文件

一个基础的配置文件必须包含以下两部分:

监听器监听器指定了 IP 和 端口以及绑定的应用,下面的示例中,端口 8300 的请求全部会被发送至 blogs 这个应用:

{
     "listeners": {
         "*:8300": {
             "application": "blog"
         }
     },
     ...
}

应用下面的示例描述了一个名为 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 的用户组

创建应用

这里为了简化步骤,采用了 Docker 的方式运行。

默认情况下,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 的页面

创建一个 applications/blog/index.php,内容如下

<?php phpinfo(); ?>

创建一个配置文件 json/config.json,内容如下:

{
     "listeners": {
         "*:8300": {
             "application": "blog"
         }
     },
     "applications": {
         "blog": {
             "type": "php",
             "workers": 20,
             "root": "/applications/blog",
             "index": "index.php"
         }
     }
}

首先创建两个目录 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

查看应用配置

查看某个应用的配置:

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"
}

查看所有应用的配置:

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 -X PUT -d '"/applications/blog-dev"' --unix-socket
./run/control.unit.sock http://localhost/applications/blog/root

{
    "success": "Reconfiguration done."
}

修改 *:8300 监听绑定的应用:

curl -X PUT -d '"blog-dev"' --unix-socket 
./run/control.unit.sock http://localhost/listeners/*:8300/application

{
    "success": "Reconfiguration done."
}

删除应用

删除应用:

curl -X DELETE --unix-socket ./run/control.unit.sock  http://localhost/applications/blog

{
    "success": "Reconfiguration done."
}

删除对 *:8300 端口的监听:

curl -X DELETE --unix-socket ./run/control.unit.sock
http://localhost/listeners/*:8300

{
    "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 可以动态修改应用配置,请注意增加安全认证 https://1winkenya.top

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
    }
}
ссс