NGINX 微服务 Unit + PHP 初探

简介

微服务大潮席卷而来,NGINX 官方也不得不做出一些改变,Unit 项目应运而生,它是一个动态的网络应用服务器,设计之初就支持运行多种编程语言,并且在运行过程中,可通过 API 动态配置已有应用的参数。
项目地址 https://github.com/nginx/unit

核心功能

  • 可使用 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

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

本文同时发布在我的 个人博客

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 5年前 自动加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 6
阿麦

马克一下 能支持 Node.js 还真的不错

6年前 评论

66666 ? ? ? ? ?

6年前 评论

微服务最重要的理念是什么?

6年前 评论

这个项目很不错,打算用Laravel 写一个管理Nginx Unit 的WebUI

6年前 评论
下载 秘钥,该秘钥用于验证 NGINX 源的签名,执行

这是公钥,不是秘钥。

6年前 评论

@summer 头像挂了一大片

6年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
1
粉丝
2
喜欢
24
收藏
3
排名:646
访问:1.2 万
私信
所有博文
社区赞助商