摘要: 衆所周知,PHP 是 Web 編程最流行的編程語言,若是有人告訴你,有 Serverless 的 PHP WEB 開發新模式,你是否是會感到好奇和興奮?本文以部署 WordPress 工程在函數計算環境中爲例,向您講解如何使用阿里雲函數計算快速構建或移植基於 PHP 框架開發的 Web, 體驗 serverless 開發web 的新姿式。
這篇文章適合全部的PHP開發新手、老鳥以及想準備學習開發 PHP 的程序猿。衆所周知,PHP 是 Web 編程最流行的編程語言,若是有人告訴你,有 Serverless 的 PHP WEB 開發新模式,你是否是會感到好奇和興奮?在介紹 Serverless Web 開發新模式以前,咱們先了解下將 PHP Web Serverless 化的好處:php
本文以部署 WordPress 工程在函數計算環境中爲例,向您講解如何使用阿里雲函數計算快速構建或移植基於 PHP 框架開發的 Web ,經過本文,您將會了解如下內容:css
在本教程中,咱們講解如何利用函數計算一步一步來構建 Web 的 Server 端,該案例是把一個 WordPress 部署到函數計算,本文旨在展現函數計算作 Web Backend 能力,具體表現爲如下幾點:nginx
案例體驗入口:web
正常來講,用戶開發 Server 端服務,經常面臨開發效率,運維成本高,機器資源彈性伸縮等痛點,而使用 Serverless 架構能夠很好的解決上述問題。下面是傳統架構和 Serverless 架構的對比:數據庫
阿里雲函數計算是一個事件驅動的全託管計算服務。經過函數計算,您無需管理服務器等基礎設施,只需編寫代碼並上傳。函數計算會爲您準備好計算資源,以彈性、可靠的方式運行您的代碼,並提供日誌查詢,性能監控,報警等功能。藉助於函數計算,您能夠快速構建任何類型的應用和服務,無需管理和運維。編程
從上面的示例圖中,總體架構十分簡單明瞭, 用 FC 替代了 Web 服務器,可是換來的是免運維,彈性擴容,按需付費等一系列優勢安全
傳統服務器 PHP 運行原理服務器
從上面原理示意圖咱們能夠看出,Web 服務器根據conf 中 location將 PHP 腳本交給 php-fpm 去解析,而後將解析後的結果返回給 client 端網絡
FC 驅動 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($request, $docRoot, $phpFile = "index.php", $fastCgiParams = [], $options = [])
準備工做
因爲函數運行時的 IP 是不固定的,您須要設置 RDS 容許全部 IP 訪問。可是這樣會有風險,不建議這樣作。在本教程中,咱們將建立一個 RDS MYSQL 數據庫,並將它置於一個專有網絡 VPC 環境內,函數計算支持 VPC 功能,用戶能夠經過受權的方式安全地訪問 VPC 中的資源(同時包含本示例中的 NAS )。
建立函數
|-- 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:能夠,等函數計算自定義域名功能上線,能夠解決這個問題,具體操做後續會在此文中更新。
<?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); } }
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 Backend,只須要編寫一個函數實現傳統 Web 服務器中的 conf 中的邏輯,就能夠將一個完整的 Web 工程遷移到 FC ,從而從傳統的 Web 網站運維,監控等繁瑣的事務中解放出來。
本文做者:rsong
本文爲雲棲社區原創內容,未經容許不得轉載。