NGINX 微服務 Unit + PHP 初探

airycanon發表於2017-09-22

簡介

微服務大潮席捲而來,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
        }
}

本文同時釋出在我的 個人部落格

相關文章