十分钟上线-函数计算玩转 WordPress

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
函数计算FC,每月15万CU 3个月
简介: 众所周知,PHP 是 Web 编程最流行的编程语言,如果有人告诉你,有 Serverless 的 PHP WEB 开发新模式,你是不是会感到好奇和兴奋?本文以部署 WordPress 工程在函数计算环境中为例,向您讲解如何使用阿里云函数计算快速构建或移植基于 PHP 框架开发的 Web, 体验 serverless 开发web 的新姿势。

这个文章介绍方案过时, 直接参考自定义镜像方案

函数计算目前已经支持了自定义镜像, 感兴趣的同学直接使用镜像体验更流畅,使用 custom-container, 和传统的 php 使用方法一致, 通过 S 工具可以一键部署

前言

这篇文章适合所有的PHP开发新手、老鸟以及想准备学习开发 PHP 的程序猿。众所周知,PHP 是 Web 编程最流行的编程语言,如果有人告诉你,有 Serverless 的 PHP WEB 开发新模式,你是不是会感到好奇和兴奋?在介绍 Serverless Web 开发新模式之前,我们先了解下将 PHP Web Serverless 化的好处:

  1. 无需采购和管理服务器等基础设施
  2. 弹性伸缩,动态扩容
  3. 免运维, 极大降低人力成本
  4. 按需付费,财务成本低

本文以部署 WordPress 工程在函数计算环境中为例,向您讲解如何使用阿里云函数计算快速构建或移植基于 PHP 框架开发的 Web ,通过本文,您将会了解以下内容:

案例概览

在本教程中,我们讲解如何利用函数计算一步一步来构建 Web 的 Server 端,该案例是把一个 WordPress 部署到函数计算,本文旨在展示函数计算做 Web Backend 能力,具体表现为以下几点:

  • 完善的 PHP 系统迁移到 FC 的成本不高
  • FC 打通了专有网络 VPC 功能,用户的函数可以配置访问专有网络的云资源,比如本案例中 MYSQL, NAS

传统服务器架构 VS Serverless架构

正常来说,用户开发 Server 端服务,常常面临开发效率,运维成本高,机器资源弹性伸缩等痛点,而使用 Serverless 架构可以很好的解决上述问题。下面是传统架构和 Serverless 架构的对比:
image

阿里云函数计算是一个事件驱动的全托管计算服务。通过函数计算,您无需管理服务器等基础设施,只需编写代码并上传。函数计算会为您准备好计算资源,以弹性、可靠的方式运行您的代码,并提供日志查询,性能监控,报警等功能。借助于函数计算,您可以快速构建任何类型的应用和服务,无需管理和运维。

Serverless 架构详解

image.png

从上面的示例图中,整体架构十分简单明了, 用 FC 替代了 Web 服务器,但是换来的是免运维,弹性扩容,按需付费等一系列优点

函数计算运行 PHP 框架原理

传统服务器 PHP 运行原理

  • 原理示意图

image.png

  • A simple nginx conf

image.png

从上面原理示意图我们可以看出,Web 服务器根据conf 中 location将 PHP 脚本交给 php-fpm 去解析,然后将解析后的结果返回给 client 端

FC 驱动 PHP 工程原理

image.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];
              $filename = rawurldecode($filename);
              $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);
          }
      }
      AI 代码解读

    其中函数计算为用户提供了一个 $GLOBALS['fcPhpCgiProxy'] 对象用来和 php-fpm 进行交互,对
    PHP 工程中的 php 文件进行解析,该对象提供了两个重要的接口:

    • requestPhpCgi

        requestPhpCgi($request, $docRoot, $phpFile = "index.php", $fastCgiParams = [], $options = [])
      AI 代码解读
      • $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 秒

案例开发配置步骤

本文编写的时候由于工具链不够完善, 后续章节的操作都是基于控制台,如果您喜欢命令行, 使用 Fun 工具可以大大提高配置部署效率。

准备工作

由于函数运行时的 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配置如下图:

image.png

2. 然后将 WordPress 工程移到上述配置的 NAS 中, www 表示 WordPress 的工程的根目录

|-- index.py
|-- www
AI 代码解读

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'
AI 代码解读

基于上述代码创一个函数 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:可以,FC Web 设置自定义域名

3. 创建入口函数 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];
          $filename = rawurldecode($filename);
          $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);
      }
  }
AI 代码解读

4. 直接通过 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/
AI 代码解读

FC Web 设置自定义域名

  • 下载 WordPress, 然后将 WordPress 工程移到上述配置的 NAS 中, www 表示 WordPress 的工程的根目录
|-- index.py
|-- www
AI 代码解读

index.py代码:

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

file = "/mnt/www/"

def mkdir(path):
  folder = os.path.exists(path)
  if not folder:                  
    os.makedirs(path)           
    
def lsDir():
  os.system("ls -ll /mnt/www/")

def handler(event, context):
  mkdir(file)  
  os.system("cp -r /code/www/* /mnt/www/")
  print(lsDir())
  return 'ok'
AI 代码解读

基于上述代码创一个函数 move-wp-nas , 执行函数,将 WordPress 工程包移动到 NAS 的/mnt/www/ 目录。

  • 同时入口函数做下小改动,改成如下代码:

    <?php
    use RingCentral\Psr7\Response;
    
    function endsWith($haystack, $needle) {
        $length = strlen($needle);
    
        return $length === 0 ||
            (substr($haystack, -$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);
        }
    
        $proxy    = $GLOBALS['fcPhpCgiProxy'];
        $root_dir = '/mnt/www';
      
        //php script
        if (preg_match('#\.php.*#', $uri)) {
            $host   = "fcdemo.mofangdegisn.cn"; // your define domain
            $resp   = $proxy->requestPhpCgi($request, $root_dir, "index.php",
                ['HTTP_HOST' => $host, 'SERVER_NAME' => $host, 'SERVER_PORT' => '80'],
                ['debug_show_cgi_params' => false, 'readWriteTimeout' => 60000]
            );
            return $resp;
        } else {
            // static files, js, css, jpg ...
            $filename = $root_dir . explode("?", $uri)[0];
            $filename = rawurldecode($filename);
            $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);
        }
    }
    AI 代码解读
  • 给函数入口配置自定义域名(操作过程请参考:绑定自定义域名示例), 具体配置假设如下:

image

注意: 绑定自定义域名之后,不用使用控制台来进行调试,就只能使用浏览器来触发函数,日志服务来进行调试。

总结

函数计算有如下优势:

  • 无需采购和管理服务器等基础设施
  • 专注业务逻辑的开发
  • 提供日志查询、性能监控、报警等功能快速排查故障
  • 以事件驱动的方式触发应用响应用户请求
  • 毫秒级别弹性伸缩,快速实现底层扩容以应对峰值压力
  • 按需付费。只需为实际使用的计算资源付费,适合有明显波峰波谷的用户访问场景

除了上面所列的优势,FC 可以做为 Web Backend,只需要编写一个函数实现传统 Web 服务器中的 conf 中的逻辑,就可以将一个完整的 Web 工程迁移到 FC ,从而从传统的 Web 网站运维,监控等繁琐的事务中解放出来。

最后欢迎大家通过扫码加入我们用户群中,搭建过程中有问题或者有其他问题可以在群里提出来。

函数计算官网客户群(11721331)。
image

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
rsong
+关注
目录
打赏
0
0
0
4
184
分享
相关文章
云大使 X 函数计算 FC 专属活动上线!享返佣,一键打造 AI 应用
如今,AI 技术已经成为推动业务创新和增长的重要力量。但对于许多企业和开发者来说,如何高效、便捷地部署和管理 AI 应用仍然是一个挑战。阿里云函数计算 FC 以其免运维的特点,大大降低了 AI 应用部署的复杂性。用户无需担心底层资源的管理和运维问题,可以专注于应用的创新和开发,并且用户可以通过一键部署功能,迅速将 AI 大模型部署到云端,实现快速上线和迭代。函数计算目前推出了多种规格的云资源优惠套餐,用户可以根据实际需求灵活选择。
新书上线 |《零门槛AIGC应用实战——Serverless+AI 轻松玩转高频AIGC场景》免费下载
新书上线 |《零门槛AIGC应用实战——Serverless+AI 轻松玩转高频AIGC场景》免费下载
新书上线 |《零门槛AIGC应用实战——Serverless+AI 轻松玩转高频AIGC场景》免费下载
《零门槛AIGC应用实战——Serverless+AI 轻松玩转高频AIGC场景》电子书正式上线!多种精选 AI 部署方案带你深入了解 Serverless+AI 最新趋势、AI 应用的架构设计与详细的部署教程等。函数计算 AI 技术解决方案助您一键上云,高效部署。
函数计算×百炼新春活动正式上线!三步赢取蛇年精美好礼
本次场景利用函数计算 FC 构建 Web 服务,由其提供函数计算资源以及工作流能力,您无需管理服务器等基础设施,函数计算 FC 能够根据需求自动扩展,按需计算,结合百炼模型服务实现了从文案、声音、字幕、图像生成到视频合成的一站式自动化流程,大幅简化使用 AI 创作的流程,降低了技术要求,使创作者能够更高效地生产出高质量的内容,快速响应市场需求,同时保证了作品的专业水准和创意表达。
108 24
函数计算×百炼新春活动正式上线!三步赢取蛇年精美好礼
函数计算×百炼新春活动正式上线!三步赢取蛇年精美好礼
新书上线 |《零门槛AIGC应用实战——Serverless+AI 轻松玩转高频AIGC场景》免费下载
新书上线 |《零门槛AIGC应用实战——Serverless+AI 轻松玩转高频AIGC场景》免费下载
Serverless痛点解决问题之将 WordPress 工程部署到函数计算中如何解决
Serverless痛点解决问题之将 WordPress 工程部署到函数计算中如何解决
72 1
详解基于百炼平台及函数计算快速上线网页AI助手
通过阿里云百炼平台,企业可在10分钟内为其网站添加智能客服系统,提升用户体验并降低成本。流程包括:创建大模型应用、配置参数(如温度系数以控制回复的随机性)、发布应用获取API密钥;使用函数计算快速搭建示例网站,并通过简单的代码更改启用AI助手功能;还可导入私有知识库增强助手的能力。前端基于NLUX开发,支持定制化需求如样式调整和历史会话管理。服务端代码提供了调用大模型获取答案的接口。借助百炼平台,企业能迅速部署即时且个性化的在线服务,适应数字化转型的需求。
函数计算产品使用问题之wordpress应用模板在什么地方
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
报名开启!2024 开源之夏丨Serverless Devs 课题已上线!
2024 年,Serverless Devs 再次加入中国科学院软件研究所开源软件供应链点亮计划支持下的系列高校开源活动——开源之夏 2024。

热门文章

最新文章

相关产品

  • 函数计算