AWS Lambda
开发人员指南
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。点 击 Getting Started with Amazon AWS to see specific differences applicable to the China (Beijing) Region.

步骤 2.1:创建部署程序包

Filter View 列表中,选择要用于 Lambda 函数的语言。适当的部分随即出现,其中包含创建部署程序包的代码和具体说明。

Node.js

部署程序包是包含 Lambda 函数代码和依赖项的 .zip 文件。

  1. 创建文件夹 (examplefolder),然后创建子文件夹 (node_modules)。

  2. 安装 Node.js 平台。有关更多信息,请参阅 Node.js 网站。

  3. 安装依赖项。本代码示例使用以下库:

    • 适用于 Node.js 中 JavaScript 的 AWS 开发工具包

    • gm,GraphicsMagick for node.js

    • Async 实用程序模块

    AWS Lambda 运行时已具有用 Node.js 编写的适用于 JavaScript 的 AWS 开发工具包,因此您只需安装其他库。打开命令提示符,导航到 examplefolder,使用 npm 命令(Node.js 的一部分)安装这些库。

    Copy
    npm install async gm
  4. 打开文本编辑器,然后复制以下代码。

    Copy
    // dependencies var async = require('async'); var AWS = require('aws-sdk'); var gm = require('gm') .subClass({ imageMagick: true }); // Enable ImageMagick integration. var util = require('util'); // constants var MAX_WIDTH = 100; var MAX_HEIGHT = 100; // get reference to S3 client var s3 = new AWS.S3(); exports.handler = function(event, context, callback) { // Read options from the event. console.log("Reading options from event:\n", util.inspect(event, {depth: 5})); var srcBucket = event.Records[0].s3.bucket.name; // Object key may have spaces or unicode non-ASCII characters. var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); var dstBucket = srcBucket + "resized"; var dstKey = "resized-" + srcKey; // Sanity check: validate that source and destination are different buckets. if (srcBucket == dstBucket) { callback("Source and destination buckets are the same."); return; } // Infer the image type. var typeMatch = srcKey.match(/\.([^.]*)$/); if (!typeMatch) { callback("Could not determine the image type."); return; } var imageType = typeMatch[1]; if (imageType != "jpg" && imageType != "png") { callback('Unsupported image type: ${imageType}'); return; } // Download the image from S3, transform, and upload to a different S3 bucket. async.waterfall([ function download(next) { // Download the image from S3 into a buffer. s3.getObject({ Bucket: srcBucket, Key: srcKey }, next); }, function transform(response, next) { gm(response.Body).size(function(err, size) { // Infer the scaling factor to avoid stretching the image unnaturally. var scalingFactor = Math.min( MAX_WIDTH / size.width, MAX_HEIGHT / size.height ); var width = scalingFactor * size.width; var height = scalingFactor * size.height; // Transform the image buffer in memory. this.resize(width, height) .toBuffer(imageType, function(err, buffer) { if (err) { next(err); } else { next(null, response.ContentType, buffer); } }); }); }, function upload(contentType, data, next) { // Stream the transformed image to a different S3 bucket. s3.putObject({ Bucket: dstBucket, Key: dstKey, Body: data, ContentType: contentType }, next); } ], function (err) { if (err) { console.error( 'Unable to resize ' + srcBucket + '/' + srcKey + ' and upload to ' + dstBucket + '/' + dstKey + ' due to an error: ' + err ); } else { console.log( 'Successfully resized ' + srcBucket + '/' + srcKey + ' and uploaded to ' + dstBucket + '/' + dstKey ); } callback(null, "message"); } ); };

    注意

    代码示例与 Node.js 运行时 v6.10 或 v4.3 兼容。有关更多信息,请参阅编程模型 (Node.js)

  5. 查看上述代码并注意以下内容:

    • 函数通过作为参数接收的事件数据获知源存储桶名称和对象键名称。如果对象为 .jpg,则该代码会创建一个缩略图并将其保存到目标存储桶。

    • 该代码假定目标存储桶已存在,且其名称为源存储桶名称后跟字符串 resized。例如,如果在事件数据中识别的源存储桶为 examplebucket,则代码假定您具有目标存储桶 examplebucketresized

    • 对于所创建的缩略图,该代码会将其键名称派生为后跟源对象键名称的字符串 resized-。例如,如果源对象键为 sample.jpg,则代码会创建具有键 resized-sample.jpg 的缩略图对象。

  6. 将该文件保存到 CreateThumbnail.js 中,文件名为 examplefolder。完成此步骤后,文件夹结构如下:

    Copy
    CreateThumbnail.js /node_modules/gm /node_modules/async
  7. 将 CreateThumbnail.js 文件和 node_modules 文件夹压缩为 CreateThumbnail.zip

    此即 Lambda 函数部署程序包。

下一步

步骤 2.2:创建执行角色(IAM 角色)

Java

下面是读取传入的 Amazon S3 事件并创建缩略图的示例 Java 代码。请注意,它实现了 aws-lambda-java-core 库中提供的 RequestHandler 接口。因此,在创建 Lambda 函数时,您可以将该类指定为处理程序(即 example.S3EventProcessorCreateThumbnail)。有关使用接口提供处理程序的更多信息,请参阅利用预定义接口创建处理程序 (Java)

被该处理程序用作输入类型的 S3Event 类型是 aws-lambda-java-events 库中的一个预定义类,它为您提供了一些方便地从传入的 Amazon S3 事件读取信息的方法。该处理程序返回字符串作为输出。

Copy
package example; import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLDecoder; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.S3Event; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.event.S3EventNotification.S3EventNotificationRecord; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.S3Object; public class S3EventProcessorCreateThumbnail implements RequestHandler<S3Event, String> { private static final float MAX_WIDTH = 100; private static final float MAX_HEIGHT = 100; private final String JPG_TYPE = (String) "jpg"; private final String JPG_MIME = (String) "image/jpeg"; private final String PNG_TYPE = (String) "png"; private final String PNG_MIME = (String) "image/png"; public String handleRequest(S3Event s3event, Context context) { try { S3EventNotificationRecord record = s3event.getRecords().get(0); String srcBucket = record.getS3().getBucket().getName(); // Object key may have spaces or unicode non-ASCII characters. String srcKey = record.getS3().getObject().getKey() .replace('+', ' '); srcKey = URLDecoder.decode(srcKey, "UTF-8"); String dstBucket = srcBucket + "resized"; String dstKey = "resized-" + srcKey; // Sanity check: validate that source and destination are different // buckets. if (srcBucket.equals(dstBucket)) { System.out .println("Destination bucket must not match source bucket."); return ""; } // Infer the image type. Matcher matcher = Pattern.compile(".*\\.([^\\.]*)").matcher(srcKey); if (!matcher.matches()) { System.out.println("Unable to infer image type for key " + srcKey); return ""; } String imageType = matcher.group(1); if (!(JPG_TYPE.equals(imageType)) && !(PNG_TYPE.equals(imageType))) { System.out.println("Skipping non-image " + srcKey); return ""; } // Download the image from S3 into a stream AmazonS3 s3Client = new AmazonS3Client(); S3Object s3Object = s3Client.getObject(new GetObjectRequest( srcBucket, srcKey)); InputStream objectData = s3Object.getObjectContent(); // Read the source image BufferedImage srcImage = ImageIO.read(objectData); int srcHeight = srcImage.getHeight(); int srcWidth = srcImage.getWidth(); // Infer the scaling factor to avoid stretching the image // unnaturally float scalingFactor = Math.min(MAX_WIDTH / srcWidth, MAX_HEIGHT / srcHeight); int width = (int) (scalingFactor * srcWidth); int height = (int) (scalingFactor * srcHeight); BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = resizedImage.createGraphics(); // Fill with white before applying semi-transparent (alpha) images g.setPaint(Color.white); g.fillRect(0, 0, width, height); // Simple bilinear resize // If you want higher quality algorithms, check this link: // https://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(srcImage, 0, 0, width, height, null); g.dispose(); // Re-encode image to target format ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(resizedImage, imageType, os); InputStream is = new ByteArrayInputStream(os.toByteArray()); // Set Content-Length and Content-Type ObjectMetadata meta = new ObjectMetadata(); meta.setContentLength(os.size()); if (JPG_TYPE.equals(imageType)) { meta.setContentType(JPG_MIME); } if (PNG_TYPE.equals(imageType)) { meta.setContentType(PNG_MIME); } // Uploading to S3 destination bucket System.out.println("Writing to: " + dstBucket + "/" + dstKey); s3Client.putObject(dstBucket, dstKey, is, meta); System.out.println("Successfully resized " + srcBucket + "/" + srcKey + " and uploaded to " + dstBucket + "/" + dstKey); return "Ok"; } catch (IOException e) { throw new RuntimeException(e); } } }

Amazon S3 使用 Event 调用类型调用您的 Lambda 函数,其中 AWS Lambda 以异步方式执行代码。返回什么不重要。但在本示例中,我们实现的接口要求指定返回类型,因此,本示例中的处理程序使用了 String 作为返回类型。

使用之前的代码 (在名为 S3EventProcessorCreateThumbnail.java 的文件中) 创建一个部署程序包。确保添加以下依赖项:

  • aws-lambda-java-core

  • aws-lambda-java-events

这些内容可以在 aws-lambda-java-libs 中找到。

有关更多信息,请参阅 使用 Java 编写 Lambda 函数的编程模型

部署程序包既可以是 .zip 文件,也可以是独立的 .jar。您可以使用自己熟悉的任何构建和打包工具来创建部署程序包。有关如何使用 Maven 构建工具创建独立 .jar 的示例,请参阅使用 Maven 但不借助任何 IDE 创建 .jar 部署程序包 (Java)使用 Maven 和 Eclipse IDE 创建 .jar 部署程序包 (Java)。有关如何使用 Gradle 构建工具创建 .zip 文件的示例,请参阅创建 .zip 部署程序包 (Java)

确认已创建您的部署程序包后,请转到下一步来创建 IAM 角色(执行角色)。您将在创建 Lambda 函数时指定此角色。

下一步

步骤 2.2:创建执行角色(IAM 角色)

Python

在本节中,您将创建示例 Python 函数并安装依赖项。此代码示例与 Python 运行时版本 3.6 或 2.7 兼容。这些步骤适用于 3.6 运行时,但您也可以使用另一版本。

  1. 打开文本编辑器,并复制以下代码。该代码使用相同的图像名称将调整大小后的图像上传到其他存储桶,如下所示:

    source-bucket/image.png -> source-bucketresized/image.png

    注意

    利用 from __future__ 语句,可以编写与 Python 2 或 3 兼容的代码。如果您使用的是运行时版本 3.6,则不必将它包含在内。

    Copy
    from __future__ import print_function import boto3 import os import sys import uuid from PIL import Image import PIL.Image s3_client = boto3.client('s3') def resize_image(image_path, resized_path): with Image.open(image_path) as image: image.thumbnail(tuple(x / 2 for x in image.size)) image.save(resized_path) def handler(event, context): for record in event['Records']: bucket = record['s3']['bucket']['name'] key = record['s3']['object']['key'] download_path = '/tmp/{}{}'.format(uuid.uuid4(), key) upload_path = '/tmp/resized-{}'.format(key) s3_client.download_file(bucket, key, download_path) resize_image(download_path, upload_path) s3_client.upload_file(upload_path, '{}resized'.format(bucket), key)
  2. 将该文件保存为 CreateThumbnail.py

  3. 如果您的源代码在本地主机上,请复制它。

    scp -i key.pem /path/to/my_code.py ec2-user@public-ip-address:~/CreateThumbnail.py

  4. 通过 SSH 连接到 64 位 Amazon Linux 实例。

    ssh -i key.pem ec2-user@public-ip-address

  5. 使用以下步骤安装 Python 3.6 和 virtualenv:

    1. sudo yum install -y gcc zlib zlib-devel openssl openssl-devel

    2. wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tgz

    3. tar -xzvf Python-3.6.1.tgz

    4. cd Python-3.6.1 && ./configure && make

    5. sudo make install

    6. sudo /usr/local/bin/pip3 install virtualenv

  6. 选择通过 pip3 安装的虚拟环境

    /usr/local/bin/virtualenv ~/shrink_venv

    source ~/shrink_venv/bin/activate

  7. 在虚拟环境中安装库

    pip install Pillow

    pip install boto3

    注意

    AWS Lambda 包含适用于 Python 的 AWS 软件开发工具包 (Boto 3),因此您无需将它包含在部署程序包中,但可以选择包含它以用于本地测试。

  8. liblib64 站点程序包的内容添加到 .zip 文件中。请注意,以下步骤假定您使用 Python 运行时版本 3.6。如果您使用版本 2.7,需要进行相应更新。

    cd $VIRTUAL_ENV/lib/python3.6/site-packages

    zip -r9 ~/CreateThumbnail.zip *

    注意

    要包括所有隐藏的文件,请使用以下选项:zip -r9 ~/CreateThumbnail.zip .

  9. 添加 Python 代码到 .zip 文件

    cd ~

    zip -g CreateThumbnail.zip CreateThumbnail.py

下一步

步骤 2.2:创建执行角色(IAM 角色)

本页内容: