前言
首先介绍下在本文出现的几个比较重要的概念:
__函数计算(Function Compute)__: 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。函数计算更多信息 参考。
__Fun__: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。Fun 的更多文档 参考。
__Fun Local__: Fun Local 作为 Fun 的一个子命令存在,可以直接通过
fun local
命令使用。Fun Local 工具可以将函数计算中的函数在本地完全模拟运行,并提供单步调试的功能,旨在弥补函数计算相对于传统应用开发体验上的短板,并为用户提供一种解决函数计算问题排查的新途径。
备注: 本文介绍的技巧需要 Fun 版本大于等于 2.8.0。
声明:本文基于 十分钟上线-函数计算玩转 WordPress 提供的思路开发 wordpress 应用。
创建 fun 项目
创建一个目录作为 fun 项目的根目录,然后创建一个 index.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);
}
}
然后创建 template.yml:
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
share:
Type: 'Aliyun::Serverless::Service'
Properties:
Description: 'fc wordpress test'
Policies:
- AliyunECSNetworkInterfaceManagementAccess
VpcConfig:
VpcId: 'vpc-bp12hm92gdpcjtai7ua82'
VSwitchIds: [ 'vsw-bp1gitru7oicyyb4uiylj' ]
SecurityGroupId: 'sg-bp1243pi65bw4cjj4bks'
NasConfig:
UserId: -1
GroupId: -1
MountPoints:
- ServerAddr: '012194b28f-ujc20.cn-hangzhou.nas.aliyuncs.com:/'
MountDir: '/mnt/www'
wp-func:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler
Runtime: php7.2
CodeUri: './index.php'
Timeout: 100
Events:
http-test: # trigger name
Type: HTTP # http trigger
Properties:
AuthType: ANONYMOUS
Methods: ['GET', 'POST', 'PUT']
我们在 template.yml 中描述了 VPC、NAS 服务,以及 HTTP Trigger。至此,我们的函数就开发完了,在发布到线上前,我们需要先在本地调通。
通过执行 fun local start 可以将函数计算在本地模拟启动:
打开提示的 url,会得到错误提示:
这是因为我们没有安装 wordpress 的缘故。我们需要将 wordpress 安装到 NAS 挂载的目录上。fun local 对 NAS 的支持可以 参考。我们需要通过以下几步来让函数能够访问到 wordpress 应用:
- 下载 wordpress。
- 解压下载的 wordpress。
- 将解压后的 wordpress 内容复制到本地模拟的 NAS 目录。
对于我们的项目,本地模拟的 NAS 目录为:.fun/nas/012194b28f-ujc20.cn-hangzhou.nas.aliyuncs.com/
。这个目录在函数运行时,会被挂载到容器的 /mnt/www 下。函数可以直接访问该目录。
对于 wordprss 应用,我们需要在 .fun/nas/012194b28f-ujc20.cn-hangzhou.nas.aliyuncs.com/
下依次创建子目录:2016-08-15/proxy/share/wp-func
。
可以直接通过命令完成:
mkdir -p .fun/nas/012194b28f-ujc20.cn-hangzhou.nas.aliyuncs.com/2016-08-15/proxy/share/wp-func
然后将解压后的 wordpress 的内容复制进来,也可以通过类似的命令完成:
cp -r wordpress/ .fun/nas/012194b28f-ujc20.cn-hangzhou.nas.aliyuncs.com/2016-08-15/proxy/share/wp-func/
操作完成后,不需要重启服务,直接刷新页面即可。
打开页面会显示配置向导,按照向导提示配置数据库、用户信息即可。
注意: 本地开发时,如果使用的 RDS,需要申请外网地址,并设置 IP 白名单为:0.0.0.0/0。但由于 0.0.0.0/0 表示允许任何设备访问 RDS 实例,除非是测试,否则不太推荐这么做。更好的做法是在本地使用 mysql 进行开发。由于函数是运行在 docker container 中的,网络环境与宿主机是隔离的,因此需要将本地 mysql 配置为允许任何 ip 访问。可以 参考。
以下是一个 wordpress 本地启动后的效果演示:
本文作者:小默