天天看点

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

前言

这篇文章适合所有的php开发新手、老鸟以及想准备学习开发php的程序猿。本文以部署一个wordpress在函数计算环境中为例,向您讲解如何使用阿里云函数计算快速构建或移植基于php框架开发的web,通过本文,您将会了解以下内容:

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

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

    mysql

    ,

    nas

  • fun工具自动化部署函数计算及相关资源的能力
案例体验入口:

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

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

阿里云

函数计算

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

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

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

传统服务器php运行原理

  • 原理示意图
    十分钟上线-函数计算玩转wordpress
  • A simple nginx conf
    十分钟上线-函数计算玩转wordpress

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

FC驱动php工程原理

十分钟上线-函数计算玩转wordpress
  • 函数计算的执行环境相当于传统web服务的Apache/Nginx
  • 用户函数相当于实现Apache/Nginx的conf中location
  • 用户将web网站部署在nas,然后挂载nas到函数的执行环境, 比如下面代码中

    /mnt/www

    目录
  • 对于wordpress入口函数代码就是这么简单, 建议您先了解下php runtime
    <?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
  1. requestPhpCgi($request, $docRoot, $phpFile = "index.php", $fastCgiParams = [], $options = []): Response
    - `$request`: 跟`php http invoke`入口的参数一致
    - `$docRoot`: web 工程的根目录
    - `$phpFile`: 用于拼接cgi参数中的SCRIPT_FILENAME的默认参数
    - `$fastCgiParams`: 函数计算内部尽量根据$request给您构造default cgi params, 但是如果您不是想要的,可以使用$fastCgiParams覆盖一些参数 (reference: [cgi](https://en.wikipedia.org/wiki/Common_Gateway_Interface))
    - `$options`: array类型, debug_show_cgi_params 设为true,会打印每次请求php解析时候的cgi参数;readWriteTimeout 设置解析的时间           

准备工作

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

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

2. 下载 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:可以,等函数计算自定义域名功能上线,可以解决这个问题,具体操作后续会在此文中更新。

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];
          $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);
      }
  }           

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/           

未完待更新...

总结

函数计算有如下优势:

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

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

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

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

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