十分鐘上線-函數計算玩轉 WordPress

摘要: 衆所周知,PHP 是 Web 編程最流行的編程語言,若是有人告訴你,有 Serverless 的 PHP WEB 開發新模式,你是否是會感到好奇和興奮?本文以部署 WordPress 工程在函數計算環境中爲例,向您講解如何使用阿里雲函數計算快速構建或移植基於 PHP 框架開發的 Web, 體驗 serverless 開發web 的新姿式。

前言

這篇文章適合全部的PHP開發新手、老鳥以及想準備學習開發 PHP 的程序猿。衆所周知,PHP 是 Web 編程最流行的編程語言,若是有人告訴你,有 Serverless 的 PHP WEB 開發新模式,你是否是會感到好奇和興奮?在介紹 Serverless Web 開發新模式以前,咱們先了解下將 PHP Web Serverless 化的好處:php

  1. 無需採購和管理服務器等基礎設施
  2. 彈性伸縮,動態擴容
  3. 免運維, 極大下降人力成本
  4. 按需付費,財務成本低

本文以部署 WordPress 工程在函數計算環境中爲例,向您講解如何使用阿里雲函數計算快速構建或移植基於 PHP 框架開發的 Web ,經過本文,您將會了解如下內容:css

  • 案例概覽
  • 傳統服務器架構 VS Serverless架構
  • Serverless架構詳解
  • 函數計算運行PHP框架原理
  • 案例開發配置步驟
  • FC Web 設置自定義域名

案例概覽

在本教程中,咱們講解如何利用函數計算一步一步來構建 Web 的 Server 端,該案例是把一個 WordPress 部署到函數計算,本文旨在展現函數計算作 Web Backend 能力,具體表現爲如下幾點:nginx

  • 完善的 PHP 系統遷移到 FC 的成本不高
  • FC 打通了專有網絡 VPC 功能,用戶的函數能夠配置訪問專有網絡的雲資源,好比本案例中 MYSQL, NAS

案例體驗入口:web

傳統服務器架構 VS Serverless架構

正常來講,用戶開發 Server 端服務,經常面臨開發效率,運維成本高,機器資源彈性伸縮等痛點,而使用 Serverless 架構能夠很好的解決上述問題。下面是傳統架構和 Serverless 架構的對比:數據庫

clipboard.png

阿里雲函數計算是一個事件驅動的全託管計算服務。經過函數計算,您無需管理服務器等基礎設施,只需編寫代碼並上傳。函數計算會爲您準備好計算資源,以彈性、可靠的方式運行您的代碼,並提供日誌查詢,性能監控,報警等功能。藉助於函數計算,您能夠快速構建任何類型的應用和服務,無需管理和運維。編程

Serverless 架構詳解

clipboard.png

從上面的示例圖中,總體架構十分簡單明瞭, 用 FC 替代了 Web 服務器,可是換來的是免運維,彈性擴容,按需付費等一系列優勢安全

函數計算運行 PHP 框架原理

傳統服務器 PHP 運行原理服務器

  • 原理示意圖

clipboard.png

  • A simple nginx conf

clipboard.png

從上面原理示意圖咱們能夠看出,Web 服務器根據conf 中 location將 PHP 腳本交給 php-fpm 去解析,而後將解析後的結果返回給 client 端網絡

FC 驅動 PHP 工程原理架構

clipboard.png

  • 函數計算的執行環境至關於傳統 web 服務的 Apache/Nginx
  • 用戶函數至關於實現 Apache/Nginx 的 conf 中 location
  • 用戶將 Web 網站部署在 NAS,而後掛載 NAS 到函數的執行環境, 好比下面代碼中 /mnt/www 目錄
  • 對於 WordPress 入口函數代碼就是這麼簡單, 建議您先了解下 PHP Runtime

  • PHP 入口函數
  • PHP 執行環境
<?php
use RingCentral\Psr7\Response;

function startsWith($haystack, $needle) {
    $length = strlen($needle);
    return (substr($haystack, 0, $length) === $needle);
}

function handler($request, $context): Response{
    $uri    = $request->getAttribute("requestURI");
    $uriArr = explode("?", $uri);

    // default php / or /wp-admin/
    if (preg_match('#/$#', $uriArr[0]) && !(strpos($uri, '.php'))) {
        $uriArr[0] .= "index.php";
        $uri = implode($uriArr);
        if (startsWith($uri, "/2016-08-15/proxy/share/wp-func/wp-admin/")) {
            // wordpress admin entrypoint
            $request = $request->withAttribute("requestURI", $uri);
        }
    }

    $proxy    = $GLOBALS['fcPhpCgiProxy'];
    $root_dir = '/mnt/www';
    
    //php script
    if (preg_match('#\.php.*#', $uri)) {
        $format = '%s.%s.fc.aliyuncs.com';
        $host   = sprintf($format, $context['accountId'], $context['region']); // maybe user define domain
        $resp   = $proxy->requestPhpCgi($request, $root_dir, "index.php",
            ['SERVER_NAME' => $host, 'SERVER_PORT' => '80', 'HTTP_HOST' => $host],
            ['debug_show_cgi_params' => false, 'readWriteTimeout' => 15000]
        );
        return $resp;
    } else {
        // static files, js, css, jpg ...
        $filename = $root_dir . explode("?", $uri)[0];
        $handle   = fopen($filename, "r");
        $contents = fread($handle, filesize($filename));
        fclose($handle);
        $headers = [
            'Content-Type'  => $proxy->getMimeType($filename),
            'Cache-Control' => "max-age=8640000",
            'Accept-Ranges' => 'bytes',
        ];
        return new Response(200, $headers, $contents);
    }
}

其中函數計算爲用戶提供了一個 $GLOBALS['fcPhpCgiProxy'] 對象用來和 php-fpm 進行交互,對 PHP 工程中的 php 文件進行解析,該對象提供了兩個重要的接口:

  • requestPhpCgi
requestPhpCgi($request, $docRoot, $phpFile = "index.php", $fastCgiParams = [], $options = [])
  • $request: 跟 php http invoke 入口的參數一致
  • $docRoot: Web 工程的根目錄
  • $phpFile: 用於拼接 cgi 參數中的 SCRIPT_FILENAME 的默認參數
  • $fastCgiParams: 函數計算內部儘可能根據$request給您構造 default cgi params,
    可是若是您不是想要的,可使用$fastCgiParams覆蓋一些參數 (reference: cgi)
  • $options: array類型,可選參數, debug_show_cgi_params 設爲 true ,會打印每次請求 php
    解析時候的 cgi 參數, 默認爲 false ;readWriteTimeout 設置解析的時間, 默認爲 5 秒

案例開發配置步驟

準備工做

因爲函數運行時的 IP 是不固定的,您須要設置 RDS 容許全部 IP 訪問。可是這樣會有風險,不建議這樣作。在本教程中,咱們將建立一個 RDS MYSQL 數據庫,並將它置於一個專有網絡 VPC 環境內,函數計算支持 VPC 功能,用戶能夠經過受權的方式安全地訪問 VPC 中的資源(同時包含本示例中的 NAS )。

  1. 建立 RDS MYSQL 數據庫, 配置 VPC , 具體參考經過 VPC 訪問 RDS 實例
  2. 建立 NAS 掛接點,配置 VPC (注意:這裏跟 RDS 採用相同的 VPC), 具體參考函數計算nas使用示例
  3. 可選操做,在準備函數的 region 建立日誌,用於函數的調試, 具體參考函數計算配置日誌服務

建立函數

  1. 建立 Service (假設是 share ), 配置準備 vpc config , nas config 和日誌服務,好比案例體驗的Service配置以下圖:

clipboard.png

  1. 下載 WordPress, 而後將 WordPress 工程移到上述配置的 NAS 中, www 表示 WordPress 的工程的根目錄
|-- index.py
|-- www

index.py代碼:

# -*- coding: utf-8 -*-
import logging  
import os

file = "/mnt/www/2016-08-15/proxy/share/wp-func"

def mkdir(path):
  folder = os.path.exists(path)
  if not folder:                  
    os.makedirs(path)           
      
def lsDir():
  os.system("ls -ll /mnt/www/2016-08-15/proxy/share/wp-func/")

def handler(event, context):
  mkdir(file)  
  os.system("cp -r /code/www/* /mnt/www/2016-08-15/proxy/share/wp-func/")
  print(lsDir())
  return 'ok'

基於上述代碼創一個函數 move-wp-nas , 執行函數,將 WordPress 工程包移動到 NAS 的/mnt/www/2016-08-15/proxy/share/wp-func 目錄。

Q1: 爲何建立 /2016-08-15/proxy/share/wp-func 這麼奇怪的目錄?

A:由於http trigger, 函數訪問的格式爲下面的url: http://${account_id}.${region}.fc.aliyuncs.com/2016-08-15/proxy/$(seevice_name}/{function_name}/,爲了保證從一個頁面跳轉到另一個頁面的時候,能自動帶上/2016-08-15/proxy/$(seevice_name}/{function_name}/,咱們須要創建這樣目錄和設置 cgi 相關參數達到 PHP 框架內部自動跳轉正確的問題。

Q2: 可不能夠不用/2016-08-15/proxy/share/wp-func這麼奇怪的目錄?

A:能夠,等函數計算自定義域名功能上線,能夠解決這個問題,具體操做後續會在此文中更新。

  1. 建立入口函數 wp-func (對應上面步驟中的 /mnt/www/2016-08-15/proxy/share/wp-func ), 給函數設置 http trigger ,類型爲 anonymous , 類型都選上。
<?php
  use RingCentral\Psr7\Response;

  function startsWith($haystack, $needle) {
      $length = strlen($needle);
      return (substr($haystack, 0, $length) === $needle);
  }

  function handler($request, $context): Response{
      $uri    = $request->getAttribute("requestURI");
      $uriArr = explode("?", $uri);

      // default php / or /wp-admin/
      if (preg_match('#/$#', $uriArr[0]) && !(strpos($uri, '.php'))) {
          $uriArr[0] .= "index.php";
          $uri = implode($uriArr);
          if (startsWith($uri, "/2016-08-15/proxy/share/wp-func/wp-admin/")) {
              // wordpress admin entrypoint
              $request = $request->withAttribute("requestURI", $uri);
          }
      }

      $proxy    = $GLOBALS['fcPhpCgiProxy'];
      $root_dir = '/mnt/www';
      
      //php script
      if (preg_match('#\.php.*#', $uri)) {
          $format = '%s.%s.fc.aliyuncs.com';
          $host   = sprintf($format, $context['accountId'], $context['region']); // maybe user define domain
          $resp   = $proxy->requestPhpCgi($request, $root_dir, "index.php",
              ['SERVER_NAME' => $host, 'SERVER_PORT' => '80', 'HTTP_HOST' => $host],
              ['debug_show_cgi_params' => false, 'readWriteTimeout' => 15000]
          );
          return $resp;
      } else {
          // static files, js, css, jpg ...
          $filename = $root_dir . explode("?", $uri)[0];
          $handle   = fopen($filename, "r");
          $contents = fread($handle, filesize($filename));
          fclose($handle);
          $headers = [
              'Content-Type'  => $proxy->getMimeType($filename),
              'Cache-Control' => "max-age=8640000",
              'Accept-Ranges' => 'bytes',
          ];
          return new Response(200, $headers, $contents);
      }
  }
  1. 直接經過 url 訪問首頁,第一次訪問會提示您安裝 WordPress, 安裝過程當中配置以前準備好的數據庫、管理員等相關信息, 安裝成功後,就能夠成功訪問首頁,登陸後臺管理 WordPress 網站了。
http://${account_id}.${region}.fc.aliyuncs.com/2016-08-15/proxy/$(seevice_name}/{function_name}/

for example:
http://1986114430573743.cn-hangzhou.fc.aliyuncs.com/2016-08-15/proxy/share/wp-func/

FC Web 設置自定義域名

未完待更新...

總結

函數計算有以下優點:

  • 無需採購和管理服務器等基礎設施
  • 專一業務邏輯的開發
  • 提供日誌查詢、性能監控、報警等功能快速排查故障
  • 以事件驅動的方式觸發應用響應用戶請求
  • 毫秒級別彈性伸縮,快速實現底層擴容以應對峯值壓力
  • 按需付費。只需爲實際使用的計算資源付費,適合有明顯波峯波谷的用戶訪問場景

除了上面所列的優點,FC 能夠作爲 Web Backend,只須要編寫一個函數實現傳統 Web 服務器中的 conf 中的邏輯,就能夠將一個完整的 Web 工程遷移到 FC ,從而從傳統的 Web 網站運維,監控等繁瑣的事務中解放出來。

本文做者:rsong

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索