摘要: 众所周知,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
本文为云栖社区原创内容,未经容许不得转载。