【译】在AWS Lambda上运行脚本语言:PHP、Ruby和Go

字数 2181阅读 425

本文来自Mobingi官方技术专栏,欢迎关注

本文翻译自Scripting Languages for AWS Lambda: Running PHP, Ruby, and Go

备注:Go已经在2018/01/15成为了AWS Lambda原生支持的语言,你可以从这里了解到更多信息https://aws.amazon.com/blogs/compute/announcing-go-support-for-aws-lambda/

在与合作伙伴与顾客一起的日常工作中,我们看到过很多不同领域、不同寻常的专业技能和经验,以及很多不同的编程语言。这些语言有些很老旧,而有一些非常前沿,很多团队都对它们的其中之一专研颇深,他们很可能想,在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

https://xkcd.com/303/

编译完成后,可以通过运行以下命令快速确认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。

<?php
 $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方式大同小异,所以在此就不做翻译,感兴趣的读者请阅读原文。

推荐阅读更多精彩内容