在与合作伙伴与顾客一起的日常工作中,我们看到过很多不同领域、不同寻常的专业技能和经验,以及很多不同的编程语言。这些语言有些很老旧,而有一些非常前沿,很多团队都对它们的其中之一专研颇深,他们很可能想,在AWS上的新组件,比如AWS Lambda上也使用这些语言。
Lambda本身对很多语言提供原生支持,例如Java、Node.js、Python和C#。在这篇文章中我们想描述如何在Lambda中使用其他的脚本语言(非原生支持的)。
对于每一个你想要使用的语言,你需要完成下面的任务:
准备: 从AMI启动一个实例,然后用SSH登陆。
编译: 打包你要在Lambda使用的语言
安装: 创建Lambda包并测试代码运行
每个编程语言的准备和安装步骤基本相同,所以我们在这里只提供PHP、Go、和Ruby的,一步一步编译打包的例子。
准备开始前共通步骤
Lambda允许你在Lambda运行环境中执行任何可执行文件。下面的步骤只是一个如何运行PHP、Go、Ruby在Lambda上面的大框。不管怎么说,你还是可以用这个方法,添加一些特定的库,扩展编译范围,使用JSON将你的Lambda函数和Amazon API Gateway或者其它服务互联。
在编译好二级制文件,并设定好基础文件结构之后,你就不需要再新建项目或者修改代码的时候重复做这些步骤。只需要简单编写代码接受STDIN的标准输入,然后输出结果到标准输出STDOUT,写好的Node.js包装器将会负责连接你的输入输出到运行环境。
为了简单起见,我们仅演示准备PHP的步骤,但这些步骤同样适用于后面描述的其他运行环境。
在EC2控制台,选择Lanch instance,选择AMI时,请使用在Lambda Execution Environment and Available Libraries中的一个AMI,请设定你想要运行PHP代码和启动EC2的区域。有关更多信息,请参阅Step 1: Launch an Instance。
选择t2.large实例类型,它具有两个内核和8 GB内存,可以缩短PHP编译时间。
image
选择Review and Launch,使用存储的默认值,并且把实例加入到一个只开放SSH访问的由向导生成的安全组中。
选择Launch继续;在启动对话框中,您可以为登录选择现有的密钥对值,也可以创建一个新的密钥对值。在这个例子中,我们创建一个名为php的新密钥对并下载它。
image
下载密钥后,命令行进入到文件所在的文件夹并运行以下命令:
chmod 400 php.pem
基于SSH的安全标准,我们必须修改秘钥权限。现在可以使用EC2的公共DNS连接到实例。在控制台中选择实例并在屏幕右下方的公共DNS下查找实例,获得地址。
ssh -i php.pem ec2-user@[PUBLIC DNS]
当实例启动并运行后,你就在一个适当的区域中有了一个适当AMI,你可以用上面的命令登陆实例,继续执行其他步骤。
准备PHP运行环境
登录到正在运行的AMI后,你可以从源代码编译PHP7环境,并准备好为Lambda环境打包。
给实例配置PHP
下一步是编译PHP7,将PHP7编译器的输出配置到指定目录,最后编译PHP7到Lambda AMI。
运行以下命令更新程序包管理器:
sudo yum update –y
安装最少的必要的库,用于编译PHP7:
sudo yum install gcc gcc-c++ libxml2-devel -y
安装依赖项后,您需要从PHP Downloads下载可用的PHP 7源代码。
在这个例子中,我们在爱尔兰运行一台EC2,因此我们选择了http://ie1.php.net/get/php-7.0.7.tar.bz2/from/this/mirror作为我们的镜像。运行以下命令将源下载到实例,读者可以根据你的Instance所在的区域选择自己的镜像。
cd ~
wget http://ie1.php.net/distributions/php-7.0.7.tar.bz2 .
使用以下命令提取文件:
tar -jxvf php-7.0.7.tar.bz2
上面的命令在你的home目录中创建php-7.0.7文件夹,然后通过下面的命令,创建一个专用的php-7二进制文件。
mkdir /home/ec2-user/php-7-bin
cd php-7.0.7
./configure --prefix=/home/ec2-user/php-7-bin/
这可以确保PHP编译很好地打包到您在home目录中创建的指定PHP文件夹中。请记住,我们只在此处编译最基本PHP以减少Lambda函数的依赖。
你可以使用./configure中提供的选项为Lambda中PHP二进制文件加入更多依赖项或者编译器选项。 运行./configure -h可以获取有关可以打包到PHP发行版中的内容的更多信息。但请记住,这将增加PHP二进制包的整体大小(可能影响PHP Lambda代码的整体启动时间,译者注)。
最后,运行以下命令,开始编译:
make install
image
编译完成后,可以通过运行以下命令快速确认PHP是否正常运行:
cd ~/php-7-bin/bin/
./php -v
PHP 7.0.7 (cli) (built: Jun 16 2016 09:14:04) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
代码时间
使用你最喜欢的编辑器,创建一个入口PHP文件,在这个例子中,我们从Linux管道读取输入,获取一个简单的JSON文档,并计算此JSON数据的顶层节点数量,将结果输出stdout。
$data = stream_get_contents(STDIN);
$json = json_decode($data, true);
$result = json_encode(array('result' => count($json)));
echo $result."\n";
?>
创建Lambda包
既然PHP的编译和准备已经就绪了,现在需要做的就是创建Lambda包,然后将Node.js包装器作为入口点。
首先,使用以下命令对二进制文件所在的php-7-bin文件夹进行tar压缩:
tar -zcvf php-7-bin.tar.gz php-7-bin/
然后,退出远程主机,x运行下面的命令以下载压缩文件到本地计算机(Linux、OSX或者在windows上用类似WinSCP的工具)
scp -i php.pem ec2-user@[EC2_HOST]:~/php-7-bin.tar.gz .
下载玩压缩包之后,新建一个Lambda项目,将所有文件解压缩到此文件夹中,项目的目录结构如下:
php-lambda
+-- php-7-bin
下一步是创建一个Node.js包装器文件。该文件接受Lambda调用的输入,使用helloLambda.php作为参数调用PHP可执行文件,并通过Linux管道向PHP提供输入以进行处理。复制如下内容到php.js:
// Javascript
process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'];
const spawn = require('child_process').spawn;
exports.handler = function(event, context) {
//var php = spawn('php',['helloLambda.php']); //local debug only
var php = spawn('php-7-bin/bin/php',['helloLambda.php']);
var output = "";
//send the input event json as string via STDIN to php process
php.stdin.write(JSON.stringify(event));
//close the php stream to unblock php process
php.stdin.end();
//dynamically collect php output
php.stdout.on('data', function(data) {
output+=data;
});
//react to potential errors
php.stderr.on('data', function(data) {
console.log("STDERR: "+data);
});
//finalize when php process is done.
php.on('close', function(code) {
context.succeed(JSON.parse(output));
});
}
//local debug only
//exports.handler(JSON.parse("{"hello":"world"}"));
最终,所有文件结构如下:
php-lambda
+-- php-7-bin
-- helloLambda.php
-- php.js
部署之前的最后一步是将项目压缩成可以上传到Lambda上的压缩包LambdaPHP.zip。如果你想,可以从php-7-bin / bin文件夹中删除不必要的文件,如phpdebug,以减少压缩包的大小。 有关如何创建部署包的更多详细信息,请参阅文档。
译者总结
其实,使用Lambda运行PHP的原理很简单,Lambda本身不原生支持PHP,但其实Lambda的背后也是一台Linux的Instance。那么你要做的就是,用一台和Lambda运行环境一样的机器来编译PHP可执行文件,它可以执行PHP代码,然后在你的Lambda项目中包含这个PHP可执行文件。然后再以node.js为入口,启动PHP可执行文件,这个可执行文件会运行你指定的PHP脚本。在node.js的包装器中,将Lambda参数传递给标准输入,并等待标准输出的结果,得到结果后,将其作为Lambda的运行结果返回。 而在这个过程中PHP代码会等待标准输入,处理,并将结果输出到标准输出。
原文还写了如何运行Go和Ruby在方法,因为跟运行PHP方式大同小异,所以在此就不做翻译,感兴趣的读者请阅读原文。