Tag: AWS Lambda


使用AWS Lambda和AWS Step Functions轻松构建Serverless应用

作者: Vivian Zhang(张芸)

Serverless(无服务器)应用可以说是当前的行业热点,用户无需预配置或管理服务器,只需要部署功能代码,AWS Lambda会在需要的时候执行代码并自动缩放, 从每天几个请求到每秒数千个请求,轻松地实现FaaS (Function as a Service)。无服务器应用的使用场景非常广阔,从微服务架构,到批处理、流处理、运维自动化和移动计算。

实现Serverless应用,除了AWS Lambda还需要什么?

我们来看一个典型的基于Lambda的无服务器应用。

当我们将作为计算和存储实体的Lambda函数、消息队列、DB去掉,可以看到下面这张图。

这张图上的箭头,就是上一张图里Lambda函数之间的流程,或者可以称为Lambda函数之间的“胶水”,它们起到了编排协调各个Lambda函数的作用。通常在应用中,我们会需要有这样的一些流程:

  • 我想要顺序地执行方法。
  • 我想要并行地运行这些方法。
  • 我想要基于数据选择执行方法。
  • 我想要重试某些方法。
  • 我想要try/catch/finally。
  • 我想要代码运行一定时间或者等待一段时间……

通常我们可以通过方法调用、函数链、DB和消息队列来协调这些函数,实现流程。但是对于所采用的协调机制,我们都希望它具有以下功能:

  • 可以自动伸缩;
  • 不会丢失状态;
  • 可以处理错误和超时;
  • 可以简单的搭建和运维;
  • 可以审计。

这里我们介绍一种方式,采用AWS Step Functions协调Lambda函数之间的流程。

AWS Step Functions

AWS Step Functions是一个可视工作流服务,可用来轻松协调分布式应用程序和微服务的各个组件。用户从单个组件构建应用程序,每个组件都执行一个特定的功能,也就是Task(可以采用Lambda函数实现)。Step Functions提供了一种可靠的方法来协调这些组件并逐步完成应用程序中的这些功能,并且 提供了一个图形控制台,将应用程序的组件可视化为一系列步骤,它可以自动触发并跟踪每一个步骤,并在出现错误时重试,这样应用程序就可以每一次都按照预先设定的顺序执行。Step Functions会记录每一步的状态,因此当事情出错时,用户可以快速地诊断和调试问题。

要使用Step Functions构建应用,首先我们需要在Step Functions里创建State Machine(状态机),也就是对应每一个应用的工作流程。可以采用以下8种蓝图,包括7种预定义好的状态机和1种自定义的。创建好的状态机用JSON描述。

在每一个状态机里,我们需要定义一系列的State(状态),用来完成不同的功能:

  • Task:在状态机中完成特定的功能,可以采用Lambda函数实现。
  • Choice:在各种执行分支中进行选择。
  • Fail和Success:停止一个执行,并设为Fail或者Success。
  • Pass:简单地将输入传给输出,或者注入一些数据。
  • Wait:提供一定时间的延迟,或者等待到特定的时间/数据。
  • Parallel:并行地执行分支。

可以看出,上一节中我们所需要的协调和流程在这些状态中都得到了支持。其中的Task状态是用来真正实现应用的功能,而其他状态用来处理功能之间的流程。比如说,下面是一个名为HelloWorld,执行Lambda函数的状态。

下图是一个拥有所有状态的状态机:

在Console里看到一个创建好的状态机是这样:

我们点击New Execution并且传入input数据,就可以启动该状态机的一次执行,并且可以从界面上查看执行的情况。

此外也可以通过AWS SDKs,Step Functions API和AWS CLI来启动状态机的执行并且查看进程。

采用AWS Lambda和AWS Step Functions构建Serverless应用的例子

这里介绍一个镜像识别和后端处理的例子,展示如何使用 AWS Step Functions 编排一个集成 AWS Lambda、Amazon S3、Amazon DynamoDB 和 Amazon Rekognition 的无服务器处理工作流。此工作流处理上传至 Amazon S3 的照片,并从镜像中提取元数据,如地理位置、大小/格式、时间等。然后,它使用镜像识别功能标记照片中的对象,同时还生成照片的缩略图。该例子的源代码在github上:https://github.com/awslabs/lambda-refarch-imagerecognition

整个架构的流程如下:

  1. 一张图片上传到名为PhotoRepo的S3 bucket里,位于“Incoming/”前缀下。
  2. S3 upload event产生,触发了名为ImageProcStartExecution的Lambda函数,该函数启动了AWS Step Functions中ImageProc状态机的执行,并将S3 bucket和object key作为参数传入状态机。
  3. ImageProc状态机执行以下步骤:
  4. 从S3中读取文件并抽取出图片的元数据(格式、EXIF数据、大小等等);
  5. 基于上一步骤的输出,验证上传的文件格式是否支持(png或者jpg);如果不支持,抛出NotSupportedImageType错误并且结束执行。
  6. 将抽取出的元数据保存在ImageMetadata DynamoDB中。
  7. 并行地同时启动两个进程:
  • 1)    调用Amazon Rekognition探测图像文件的对象,如果探测到,将tag保存到ImageMetadata DynamoDB中;
  • 2)    生成缩略图并且保存在名为PhotoRepo的S3 bucket的“Thumbnails/”前缀下面。

可以通过源代码中的test web app上传图片来测试该图像识别和处理工作流的结果。

可以通过源代码中的CloudFormation template来创建该后端处理应用程序。

结论

用AWS Lambda函数定义应用程序需要执行的每一个特定功能,而用AWS Step Functions定义在各个功能中流转的流程,这样采用AWS Lambda和AWS Step Functions联合使用的方式,可以轻松地构建出Serverless应用。

此外,AWS 还提供一系列完全托管的服务,可以用来构建和运行无服务器应用程序。

参考

可以在我们的网站上下载到相关例子的sample code:https://github.com/awslabs/lambda-refarch-imagerecognition

关于AWS Step Functions的 更多内容请参考网站:https://aws.amazon.com/cn/step-functions/

关于AWS Lambda的更多内容请参考网站:https://aws.amazon.com/lambda/

关于AWS服务器平台请参考网站:https://aws.amazon.com/cn/serverless/

新工具 – AWS SAM Local (Beta 版) – 在本地构建和测试无服务器应用程序

今天,我们将发布一款新工具 — SAM Local (Beta 版)。使用这款工具,您可以轻松在本地构建和测试无服务器应用程序。在本文中,我们将使用 SAM Local 快速构建、调试并部署一款应用程序,该应用程序允许我们通过对终端节点运行 curl 命令给 Tabs 或 Spaces 投票。AWS 去年推出了无服务器应用程序模式 (SAM),让开发人员能够更轻松地部署无服务器应用程序。如果您还不熟悉 SAM,请阅读我的同事 Orr 发布的一篇优秀文章,其中详细介绍了如何使用 SAM,读完该文章大约需要 5 分钟。SAM 的核心是基于 AWS CloudFormation 的强大开源规范,它可轻松将您的无服务器基础设施保持为代码并提供可爱的标识。

SAM Local 吸收了 SAM 的全部精华并将它们应用到您的本地计算机中。

有多种安装 SAM Local 的方法,但最简便的方法是通过 NPM。通过运行 npm install -g aws-sam-local 命令可以快速安装,但如果您希望获得最新版本,始终可以直接从来源安装: go get github.com/awslabs/aws-sam-local (这将创建一个名为 aws-sam-local 而非 sam 的二进制文件)。

我想要投票,因此我们来编写一款简单的 SAM 应用程序,将票投给 Spaces 而不是 Tabs。我们将使用非常简单但功能强大的 API Gateway 架构来处理 Lambda 函数,并将结果存储在 DynamoDB 中。最终,用户应能够对 API 运行 curl 命令 curl https://SOMEURL/ -d '{"vote": "spaces"}' 并返回票数。

我们首先来编写一个简单的 SAM template.yaml:

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  VotesTable:
    Type: "AWS::Serverless::SimpleTable"
  VoteSpacesTabs:
    Type: "AWS::Serverless::Function"
    Properties:
      Runtime: python3.6
      Handler: lambda_function.lambda_handler
      Policies: AmazonDynamoDBFullAccess
      Environment:
        Variables:
          TABLE_NAME: !Ref VotesTable
      Events:
        Vote:
          Type: Api
          Properties:
            Path: /
            Method: post

我们创建一个 [dynamo_i] 表,并通过一个环境变量向我们的 Lambda 函数公开该表,该环境变量名为 TABLE_NAME

为了测试此模板是否有效,我继续调用 sam validate 确保我没有打错字。该命令返回 Valid! ,接下来我们继续处理 Lambda 函数。

import os
import os
import json
import boto3
votes_table = boto3.resource('dynamodb').Table(os.getenv('TABLE_NAME'))

def lambda_handler(event, context):
    print(event)
    if event['httpMethod'] == 'GET':
        resp = votes_table.scan()
        return {'body': json.dumps({item['id']: int(item['votes']) for item in resp['Items']})}
    elif event['httpMethod'] == 'POST':
        try:
            body = json.loads(event['body'])
        except:
            return {'statusCode': 400, 'body': 'malformed json input'}
        if 'vote' not in body:
            return {'statusCode': 400, 'body': 'missing vote in request body'}
        if body['vote'] not in ['spaces', 'tabs']:
            return {'statusCode': 400, 'body': 'vote value must be "spaces" or "tabs"'}

        resp = votes_table.update_item(
            Key={'id': body['vote']},
            UpdateExpression='ADD votes :incr',
            ExpressionAttributeValues={':incr': 1},
            ReturnValues='ALL_NEW'
        )
        return {'body': "{} now has {} votes".format(body['vote'], resp['Attributes']['votes'])}

我们在本地测试一下这个函数。我需要创建一个真实的 DynamoDB 数据库进行演示,并且需要通过环境变量 TABLE_NAME提供该数据库的名称。我可以使用 env.json 文件来执行该操作,也可以直接在命令行中传递它。首先,我可以通过调用
$ echo '{"httpMethod": "POST", "body": "{\"vote\": \"spaces\"}"}' |\
TABLE_NAME="vote-spaces-tabs" sam local invoke "VoteSpacesTabs"

来测试 Lambda 函数,它返回 Spaces 的票数,因此从理论上讲,函数内容全都正确无误。用键盘输入上述全部内容比较费劲,但我可以使用 sam local generate-event api 生成示例事件,并将该事件传递到本地调用。最简单的方式是在本地运行我们的 API。让我们运行: sam local start-api。接下来,我可以对我的本地终端节点运行 curl 命令进行测试。
我将运行命令 $ curl -d '{"vote": "tabs"}' http://127.0.0.1:3000/ ,该命令返回:“tabs now has 12 votes”。当然,第一次尝试编写此函数的效果并不完美。我编辑并保存了几次。热重载的其中一个优点是我可以随意更改函数,而不必执行任何额外的操作来测试新函数。这大大简化了迭代开发。

假设我们不希望通过网络访问真正的 DynamoDB 数据库。我们应该怎么做?我们可以下载 DynamoDB Local,并通过运行如下命令启动它: java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb。然后,我们可以在 Lambda 函数中使用 AWS_SAM_LOCAL 环境变量,以决定其行为方式。我们来稍微修改一下函数:

import os
import json
import boto3
if os.getenv("AWS_SAM_LOCAL"):
    votes_table = boto3.resource(
        'dynamodb',
        endpoint_url="http://docker.for.mac.localhost:8000/"
    ).Table("spaces-tabs-votes")
else:
    votes_table = boto3.resource('dynamodb').Table(os.getenv('TABLE_NAME'))

这样,我们就使用本地终端节点连接到本地数据库,这让在没有 WiFi 的环境下工作变得更轻松。

SAM Local 还支持交互调试!在 Java 和 Node.js 中,我只需传递 -d 标记和一个端口,即可立即启用调试程序。在 Python 中,我可以使用诸如 import epdb; epdb.serve() 之类的库并通过库进行连接。然后,我们可以调用 sam local invoke -d 8080 "VoteSpacesTabs" ,我们的函数将暂停执行,等待您逐步完成调试程序。

好的,我想我们已经准备就绪,现在开始部署吧!

首先,我将调用 sam package 命令 (该命令只是 aws cloudformation package 的别名),然后我将使用该命令的结果来运行 sam deploy命令。

$ sam package --template-file template.yaml --s3-bucket MYAWESOMEBUCKET --output-template-file package.yaml
Uploading to 144e47a4a08f8338faae894afe7563c3  90570 / 90570.0  (100.00%)
Successfully packaged artifacts and wrote output template to file package.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file package.yaml --stack-name 
$ sam deploy --template-file package.yaml --stack-name VoteForSpaces --capabilities CAPABILITY_IAM
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - VoteForSpaces

这将转到我们的 API:

我将跳到生产阶段,并添加一些速率限制,以防你们过度投票,但另一方面,我们已经完成了本地工作并将它部署到云中,而这并不复杂。我非常享受第一次部署就成功的状态!

现在,您可以投票并实时查看结果了!http://spaces-or-tabs.s3-website-us-east-1.amazonaws.com/

我们希望 SAM Local 能够简化无服务器应用的测试、调试和部署。我们提供了 CONTRIBUTING.md 指南,并欢迎你们提交提取请求。请 @ 我们,让我们知道您构建的超酷应用程序。您可以查看我们的新增功能文章以及此处在线提供的文档。

Randall

AWS Marketplace 中的 Box 平台 – Lambda 蓝图和示例代码

Box 是一个基于云的文件共享内容管理系统,具有一个最近已在 AWS Marketplace 中提供的 API (Box 平台 – 云内容管理 API)。凭借一系列协作相关功能的推出,以及对安全性的重视,Box 已经在许多企业中得到了广泛应用 (请参见其成功案例页面中的列表)。

Box API 允许开发人员将内容体验构建到 Web 和移动应用程序中。今天我想向您介绍一些 [lambda] 蓝图和模板,这些蓝图和模板将可以帮助您在构建 AWS 应用程序时使用此 API 来简化用户身份验证和将元数据添加到新上传的内容中。这些模板基于 Box 节点 Lambda 示例而创建,可作为您开发工作的一个强大起点。我们来看一看这些蓝图,顺便查看一些我们在 Box 的好友所撰写的博客文章。

适用于 Lambda 的 Box 蓝图

蓝图显示了您如何通过 [apigateway] 调用 Box API 和将 Box webhook 连接到 Lambda 函数。要找到它们,请直接打开 Lambda 控制台,搜索 box

第一个蓝图使用存储在 BOX_CONFIG 环境变量中的安全凭证。您可以从 Lambda 控制台内设置此变量:

此蓝图中的代码会检索并记录通过凭证确定的用户的 Box User 对象。第二个蓝图会实施一个 Box webhook,置于 API Gateway 终端节点后面。它会接受请求,验证它们,然后将它们记录到Amazon CloudWatch中:

查看方便的博客文章

Box 的开发人员关系团队撰写了一些博客文章,向您展示如何将 Box 与多项 AWS 服务结合使用:结合使用 Amazon Cognito 和 Box 平台来管理用户身份验证 – 这篇文章向您展示了如何使用Amazon Cognito来为您的应用程序用户的登录页面提供支持。Cognito 将会处理身份验证和用户池管理,博客文章中所列出的代码会在用户首次登录时在 Box 中创建一个应用程序用户。该代码在 GitHub 上作为 box-node-cognito-lambdas-sample 提供。

利用 Amazon Rekognition 将基于深度学习的图像识别功能添加到您的 Box 应用程序中 – 这篇文章向您展示如何构建由Amazon Rekognition提供支持的图像标记应用程序。对于用户拍摄并上传的照片,应用程序会使用存储在Amazon Dynamodb中的元数据自动标记这些照片。文件上传时,代码会通过一个 webhook 激活。您可以在 GitHub 上的 box-node-rekognition-webhook 中找到代码。感谢我们在 Box 的好友抽出时间来创建了这些非常有用的开发人员资源。

-Jeff

利用Kong及AWS Lambda构建无服务器的后端逻辑

Kong是一个开源的API GW及微服务管理层,基于Nginx, Cassandra或者PostgreSQL构建,最初由Mashape开发,用于为其API Marketplace管理超过15,000个API和微服务,并于2015年开源。Kong具有如下优点:

  1. 可扩展性:通过简单地添加更多的机器,Kong可以轻松地水平缩放,这意味着您的平台可以处理几乎任何负载,同时保持低延迟。
  2. 模块化:可以通过添加新的插件来扩展,并通过RESTful Admin API轻松配置所有插件。
  3. 平台无关性:Kong可以运行在任何地方,包括本地数据中心及公有云,支持物理机,虚机及容器部署。

目前Kong的最新版本为0.10.2,支持的插件如下:

  • 认证:Basic Authentication, Key Authentication, OAuth2.0 Authentication, OAuth 2.0 Introspection, HMAC Authentication, JWT, LDAP Authentication
  • 安全:ACL, CORS, Dynamic SSL, IP Restriction, Bot Detection
  • 流控:Rate Limiting, Response Rate Limiting, Request Size Limiting
  • 无服务器架构:AWS Lambda, OpenWhisk
  • 分析监控:Galileo, Datadog, Runscope
  • 内容转换:Request Transformer, Response Transformer, Correlation ID
  • 日志:TCP/UDP/HTTP Logging, File Logging, Syslog, StatsD, Loggly

通过AWS Lambda插件,Kong可以作为一个统一的API前端,接收用户的请求,并调用不同的lambda函数做相关的处理,最后将结果返回给客户端,目前Lambda插件支持如下region:

us-east-1, us-east-2, ap-northeast-1, ap-northeast-2, ap-southeast-1, ap-southeast-2, eu-central-1, eu-west-1

Kong的安装

Kong支持多种安装方式,对于在AWS上运行Kong的情况,主要有三种:

  1. 通过marketplace安装,此安装方式会在一台EC2上同时安装Kong及其存储数据库Cassandra,适合单机部署或者测试环境
  2. 通过CloudFormation安装,CloudFormation安装方式目前支持如下region,可以通过配置选择存储数据库的类型Cassandra还是PostgreSQL,或者不由CloudFormation创建存储数据库
  3. 通过yum在EC2上安装

本文主要讲解第三种方式的安装过程,安装Kong 0.10.1版本

第一步 配置Kong的数据存储

Kong支持两种datastore:Cassandra和PgSQL,方便起见,这里利用AWS RDS创建PgSQL作为数据存储

注意事项:

  1. RDS的安全组需要放行5432端口
  2. 记录RDS创建过程中设置的用户名,密码及数据库名

比如:username/password:ivan/ivan

DB:kong

第二步 安装配置Kong (Amazon Linux)

yum update –y

wget https://github.com/Mashape/kong/releases/download/0.10.1/kong-0.10.1.aws.rpm

yum install kong-0.10.1.aws.rpm –nogpgcheck

cp /etc/kong/kong.conf.default /etc/kong/kong.conf

vim /etc/kong/kong.conf,

修改配置如下

database = postgres

pg_host = postgre-kong.XXXXXXXX.rds.cn-north-1.amazonaws.com.cn

pg_port = 5432

pg_user = ivan

pg_password = ivan

pg_database = kong

简单测试

第三步 创建AMI,利用ELB,Autoscaling Group构建高可用架构

注意,如果EC2上已经启动过kong,那么会将生成的id也打包进入AMI,导致基于AMI生成的多台机器的id相同,从而无法建立集群,创建AMI前需要删除id

rm –f /usr/local/kong/serf/serf.id

参考:

https://github.com/Mashape/kong/issues/1751

检查集群状态

第四步 创建Lambda函数并且测试

第五步 配置Kong API GW并调用Lambda

5.1.配置API

测试

5.2.配置Lambda插件

测试

第六步 配置启用额外的插件

6.1为API开启key认证

配置用户并绑定key

测试

6.2为API限速

6.3基于IP地址的过滤

作者介绍

余骏,AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内的应用和推广。在加入AWS之前,他在思科中国担任系统工程师,负责方案咨询和架构设计,在企业私有云和基础网络方面有丰富经验。

Lambda@Edge – 在边缘智能地处理 HTTP 请求

去年年底,我宣布推出预览版 Lambda@Edge,并谈论了如何使用它在靠近客户的位置 (低延迟) 智能地处理 HTTP 请求。申请并获得预览版访问权的开发人员一直在很好地使用它,并为我们提供了大量非常有用的反馈意见。在预览期间,我们添加了生成 HTTP 响应和支持 CloudWatch Logs 的功能,并根据反馈意见更新了路线图。

现已正式发布
今天我很高兴地宣布 Lambda@Edge 现已正式发布!您可以使用它来:

  • 检查 Cookie 并重写 URL 以执行 A/B 测试。
  • 根据 User-Agent 标头将特定对象发送给用户。
  • 通过在将请求传递到源之前查找特定标头来实现访问控制。
  • 添加、删除或修改标头以将用户指引到不同的缓存对象。
  • 生成新的 HTTP 响应。
  • 干净利落地支持旧 URL。
  • 修改或缩减标头或 URL 以提高缓存利用率。
  • 向其他 Internet 资源发出 HTTP 请求,并使用结果自定义响应。

Lambda@Edge 允许您创建基于 Web 的丰富且个性化的用户体验。由于它正迅速成为当今世界的常态,因此您不需要配置或管理任何服务器。您可以直接上传代码 (在Node.js 中编写的 Lambda 函数),并选择您为分发版创建的其中一个 CloudFront 行为以及所需的 CloudFront 事件:

在本例中,我的函数 (假设名为 EdgeFunc1) 将会运行,以响应对指定分发版中的 image/* 的源请求。如您所见,您可以运行代码以响应四种不同的 CloudFront 事件:

查看器请求 – 当事件从查看器 (HTTP 客户端,通常是 Web 浏览器或移动应用程序) 到达并且可以访问传入 HTTP 请求时,触发此事件。众所周知,每个 CloudFront 边缘站点都维护一个大型对象缓存,以便它可以高效地响应重复的请求。无论请求的对象是否已被缓存,都会触发此特定事件。

源请求 – 由于所请求的对象未缓存在边缘站点而导致边缘站点反过来要向源发出请求时,触发此事件。它可以访问将向源 (通常是 S3 存储桶或在 EC2 实例上运行的代码) 发出的请求。

源响应 – 在源返回对请求的响应后触发此事件。它能够访问来自源的响应。

查看器响应 – 在边缘站点返回对查看器的响应之前触发此事件。它可以访问此响应。

函数在全局范围内复制,并且请求将自动路由到最佳位置进行执行。您可以编写一次代码,然后无需您执行任何明确的操作,即可以较低延迟向世界各地的用户提供代码。

您的代码可以完全访问请求和响应,包括标头、Cookie、HTTP 方法 (GET、HEAD 等) 和 URI。它可以修改现有标头并插入新标头,但存在一些限制。

操作中的 Lambda@Edge
我们来创建一个为了响应查看器请求事件而运行的简单函数。我打开 Lambda 控制台并创建一个新函数。我选择 Node.js 6.10 运行时并搜索 cloudfront 蓝图:

我选择 cloudfront-response-generation 并配置一个触发器来调用该函数:

Lambda 控制台为我提供了有关我函数的运行环境的一些信息:

我照常输入函数的名称和描述:

蓝图包括一个可正常运行的函数。它生成一个“200”HTTP 响应和一个非常简单的主体:

我将该主体用作我自己代码的起点,以便从请求中提取一些有趣的值,并将它们显示在表中:

'use strict';
exports.handler = (event, context, callback) => {

    /* Set table row style */
    const rs = '"border-bottom:1px solid black;vertical-align:top;"';
    /* Get request */
    const request = event.Records[0].cf.request;
   
    /* Get values from request */ 
    const httpVersion = request.httpVersion;
    const clientIp    = request.clientIp;
    const method      = request.method;
    const uri         = request.uri;
    const headers     = request.headers;
    const host        = headers['host'][0].value;
    const agent       = headers['user-agent'][0].value;
    
    var sreq = JSON.stringify(event.Records[0].cf.request, null, ' ');
    sreq = sreq.replace(/\n/g, '<br/>');

    /* Generate body for response */
    const body = 
     '<html>\n'
     + '<head><title>Hello From Lambda@Edge</title></head>\n'
     + '<body>\n'
     + '<table style="border:1px solid black;background-color:#e0e0e0;border-collapse:collapse;" cellpadding=4 cellspacing=4>\n'
     + '<tr style=' + rs + '><td>Host</td><td>'        + host     + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Agent</td><td>'       + agent    + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Client IP</td><td>'   + clientIp + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Method</td><td>'      + method   + '</td></tr>\n'
     + '<tr style=' + rs + '><td>URI</td><td>'         + uri      + '</td></tr>\n'
     + '<tr style=' + rs + '><td>Raw Request</td><td>' + sreq     + '</td></tr>\n'
     + '</table>\n'
     + '</body>\n'
     + '</html>'

    /* Generate HTTP response */
    const response = {
        status: '200',
        statusDescription: 'HTTP OK',
        httpVersion: httpVersion,
        body: body,
        headers: {
            'vary':          [{key: 'Vary',          value: '*'}],
            'last-modified': [{key: 'Last-Modified', value:'2017-01-13'}]
        },
    };

    callback(null, response);
};

我配置我的处理程序,并请求创建一个具有 Basic Edge Lambda 权限的新 IAM 角色:

在下一页上,我确认我的设置 (就像我对常规 Lambda 函数所做的那样),然后单击 Create function

这将创建函数,将触发器附加到分发版,并且还将启动该函数的全局复制。在复制期间 (通常为 5 至 8 分钟),我的分发版状态将更改为 In Progress

复制完成后,状态立即改回 Deployed

然后,我访问分发版的根 (https://dogy9dy9kvj6w.cloudfront.net/),函数将运行,下面是我看到的样子:

尽管单击图片 (它链接到我的分发版的根) 以运行我的代码!

与往常一样,这是一个非常简单的例子,我相信您可以做得更好。以下是帮助您开始使用的几点提示:

站点管理 – 在维护或灾难恢复操作期间,您可以使用 Lambda@Edge 函数使整个动态网站脱机,并替换关键页面。

大量内容 – 您可以创建记分卡、天气预报或公共安全页面,并快速、经济高效地在边缘提供它们。

创建一些很酷的东西,并在评论或博客文章中分享,我会关注的。

需知信息
当您开始思考如何将 Lambda@Edge 用于您的应用程序时,请记住以下几点:

超时 – 处理源请求和源响应事件的函数必须在 3 秒钟内完成。处理查看器请求和查看器响应事件的函数必须在 1 秒钟内完成。

版本控制 – 在 Lambda 控制台中更新代码后,必须发布新版本并为其设置一组新的触发器,然后等待复制完成。您必须始终使用版本号来引用您的代码;$LATEST 和别名不适用。

标头 – 就像您在我的代码中看到的那样,HTTP 请求标头可作为数组访问。标头分为四类:

  • 可访问 – 可以读取、写入、删除或修改。
  • 受限 – 必须传递给源。
  • 只读 – 可以读取,但不能以任何方式修改。
  • 列入黑名单 – 代码看不到它,并且无法添加。

运行时环境 – 运行时环境为每个函数提供 128 MB 内存,但没有内置库,也无法访问 /tmp

Web 服务访问 – 处理源请求和源响应事件的函数必须在 3 秒钟内完成,并且可以通过 HTTP 访问 AWS API 并获取内容。这些请求总是与对原始请求或响应的请求同步进行。

函数复制 – 如前所述,您的函数将在全局范围内复制。复制副本在 Lambda 控制台的“其他”区域中可见:

CloudFront – 您已经了解的有关 CloudFront 和 CloudFront 行为的一切都与 Lambda@Edge 密切相关。您可以使用每个行为类别中的多个行为 (每个行为最多四个 Lambda@Edge 函数),自定义标头和 Cookie 转发等等。还可以在编辑行为时在事件和函数之间建立关联 (通过包含函数版本的 ARN):

现已推出
Lambda@Edge 现已推出,您可以立即开始使用。定价取决于您的函数被调用的次数及其运行时间的长短 (有关详细信息,请参阅 Lambda@Edge 定价页面)。

Jeff

AWS Lambda 对 AWS X-Ray 的支持

今天,我们宣布全面推出 AWS LambdaAWS X-Ray 的支持。您可能已经从 Jeff 的 GA 文章中了解到,X-Ray 是 AWS 推出的一项服务,用于分析分布式应用程序的执行和性能行为。传统调试方法对于基于微服务的应用程序效果不佳,在这些应用程序中,有多个独立的组件在不同的服务上运行。利用 X-Ray,您可以通过对应用程序中的延迟进行细分,来快速诊断错误、速度下降和超时问题。稍后我将详细介绍如何构建和分析一个基于 Lambda 的简单应用程序,以演示您如何能够在自己的应用程序中使用 X-Ray。如果您想立即开始使用,可以通过导航到现有 Lambda 函数的配置页面并启用跟踪,来轻松地为函数启用 X-Ray:

或者在 AWS 命令行界面 (CLI) 中更新函数的 tracing-config (请务必同时传入 --function-name ):

$ aws lambda update-function-configuration --tracing-config '{"Mode": "Active"}'

如果激活跟踪模式,Lambda 将尝试跟踪您的函数 (除非上游服务明确说明不跟踪)。如果不激活跟踪模式,仅当上游服务明确说明需要跟踪时,才跟踪您的函数。一旦启用跟踪,您将开始生成跟踪,并将获得应用程序中资源的可视化表示形式以及它们之间的联系 (边缘)。需要注意的一点是,X-Ray 守护进程会占用 Lambda 函数的一些资源。如果您已接近内存限制,Lambda 将尝试终止 X-Ray 守护程序,以免引发内存不足错误。

下面让我们通过快速构建一个使用几种不同服务的应用程序来测试这种新的集成。

作为一个二十多岁且拥有智能手机的年轻人,我有大量 图片 自拍照 (一万多张!),我想如果能够分析所有这些照片,那就太棒了。我们将使用 Java 8 运行时编写一个简单的 Lambda 函数,以响应上传到 Amazon Simple Storage Service (S3) 存储桶的新图片。我们将对照片使用 Amazon Rekognition,并将检测到的标签存储在 Amazon DynamoDB 中。

服务地图

首先,我们来快速定义几个 X-Ray 术语:子分段分段跟踪。明白了吗?如果您记住子分段和分段构成 X-Ray 要处理的跟踪以生成服务图,那么 X-Ray 就很容易理解了。如上所示,服务图是一种很不错的直观表示 (用不同的颜色表示各种请求响应)。运行您的应用程序的计算资源以分段形式发送有关它们所完成工作的数据。您可以通过创建子分段来添加有关该数据的其他注释和更细粒度的代码时间信息。通过跟踪来追踪请求在您的应用程序中传输的路径。跟踪会收集单个请求生成的所有分段。这意味着您可以轻松地跟踪从 S3 进入的 Lambda 事件,一路跟踪到 DynamoDB,并了解错误和延迟的出现位置。

因此,我们将创建一个名为 selfies-bucket的 S3 存储桶,一个名为 selfies-table的 DynamoDB 表和一个 Lambda 函数。我们将在 ObjectCreated:All 事件上为 S3 存储桶的 Lambda 函数添加一个触发器。我们的 Lambda 函数代码超级简单,您可以在这里查看完整代码。无需更改代码,我们可以通过在 JAR 中包含 aws-xray-sdk 和 aws-xray-sdk-recorder-aws-sdk-instrumentor 程序包,来在 Java 函数中启用 X-Ray。现在我们上传一些照片,并看看 X-Ray 中的跟踪。

我们获得了一些数据!我们可以单击其中一个跟踪,获取有关我们的调用的大量详细信息。

在第一个 AWS::Lambda 分段中,我们看到函数的停留时间 (即等待执行的时间),以及尝试执行的次数。

在第二个 AWS::Lambda::Function 分段中,有几个可能的子分段:

嗯,DynamoDB 方面似乎有点问题。我们甚至可以通过单击错误图标更深入地探究,并获取完整的异常堆栈跟踪。您可以看到,我们已经受到 DynamoDB 的限制,因为我们的写入容量单位不足。幸运的是,我们只需单击几下或快速调用一个 API,就可以添加更多单位。当我们这样做时,我们将会在服务地图上看到越来越多的绿色!

借助 X-Ray 软件开发工具包,向 X-Ray 发送数据变得非常容易,但您不必使用它们与 X-Ray 守护进程通信。对于 Python,您可以从名为 fleece 的 Rackspace 查看此库。X-Ray 服务充满了许多有趣的内容,了解更多信息的最好去处是跳转到文档。我一直将它用于我的 @awscloudninja 自动程序,它真的非常好用!请记住,这不是官方资料库,AWS 不为其提供支持。就我个人而言,我真的很高兴能够在所有即将开展的项目中使用 X-Ray,因为在进行调试和运行时,它真的能够为我节省一些时间和精力。我期待看到我们的客户也可以使用它进行构建。如果您想到了一些很酷的技巧或窍门,请告诉我们!

– Randall

AWS Greengrass – 在互连设备上运行 AWS Lambda 函数

在 re:Invent 大会期间发布的文章 (AWS Greengrass – 无处不在的现实世界计算) 中,我首次介绍了 AWS Greengrass。当时我们推出了 AWS Greengrass 的有限预览版,并邀请您注册。

正如我当时指出的那样,许多 AWS 客户希望在现场收集和处理数据,而现场的网络连接通常很慢,有时还时断时续,并不可靠。利用 Greengrass,他们可以在基于现场的小型简单设备上应用 AWS 编程模型。它建立在 AWS IoTAWS Lambda 的基础上,支持访问 AWS Cloud 中不断增加的各种服务。

利用 Greengrass,您可以访问在现场运行的计算、消息收发、数据缓存和同步服务,这些服务并不依赖与 AWS 区域的稳定高带宽连接。您可以在 Python 2.7 中编写 Lambda 函数,并将其从云部署到 Greengrass 设备,同时使用 Device Shadows 来维护状态。您的设备和外设可以使用本地消息收发互相通信,后者并不通过云进行传递。

现已公开发布

今天我们将在US East (Northern Virginia) 和 US West (Oregon) 区域公开发布 Greengrass。在预览版本中,AWS 客户已成功获得 Greengrass 的实践操作体验,并开始围绕它构建应用程序和业务。在后文中,我将分享一些早期的成功案例。

Greengrass 核心代码可在每台设备上运行。它允许您在设备上部署和运行 Lambda 应用程序,支持通过安全网络传递本地 MQTT 消息,并可确保设备和云之间的对话通过安全连接完成。Greengrass 核心还支持安全的无线软件更新,包括 Lambda 函数。它包括消息代理、Lambda 运行时、Thing Shadows 实现和部署代理。Greengrass 核心和可选的其他设备共同组成 Greengrass 组。该组包括配置数据、Greengrass 核心的设备和身份列表、Lambda 函数列表以及一组定义消息应发往何处的订阅。在部署过程中,所有这些信息都将复制到 Greengrass 核心设备。

您的 Lambda 函数可以使用三个不同软件开发工具包中的 API:

适用于 Python 的 AWS 软件开发工具包 – 该软件开发工具包允许您的代码与 Amazon Simple Storage Service (S3)Amazon DynamoDBAmazon Simple Queue Service (SQS), 和其他 AWS 服务交互。

AWS IoT 设备软件开发工具包 – 该软件开发工具包 (适用于 Node.js、Python、Java 和 C++) 可帮助您将硬件设备连接到 AWS IoT。C++ 软件开发工具包具有几项额外功能,包括对 Greengrass Discovery Service 的访问权和支持根 CA 下载。

AWS Greengrass 核心软件开发工具包 – 该软件开发工具包提供的 API 允许本地调用其他 Lambda 函数,发布消息和使用 Thing Shadows。

您可以在启用了 OverlayFS 和用户命名空间功能的 x86 和 ARM 设备 (具有版本 4.4.11 或更高版本 Linux 内核) 上运行 Greengrass 核心。虽然大部分 Greengrass 部署将针对专业化的工业级硬件,但您也可以在 Raspberry Pi 或 EC2 实例上运行 Greengrass 核心进行开发和测试。

在本文中,我使用了附加到 BrickPi 的 Raspberry Pi,它通过 WiFi 连接到我的家庭网络:

Raspberry Pi、BrickPi、盒子和所有其他部件均在 BrickPi 3 初学者工具包中提供。您需要一些 Linux 命令行专业知识和一定的动手能力将所有这一切组装起来,不过如果我都能做到,您肯定也可以。

Greengrass 的实际使用

我可以从控制台、API 或 CLI 访问 Greengrass。我将使用控制台。Greengrass 控制台的简介页面允许我定义组,添加 Greengrass 核心,并向组中添加设备:

单击 Get Started,然后单击 Use easy creation

然后为组命名:

并为第一个 Greengrass 核心命名:

准备好后,单击 Create Group and Core

这将运行几秒钟,然后提供可供下载的安全资源 (两个密钥和一个证书) 以及 Greengrass 核心:

我下载这些安全资源并将它们放到一个安全的地方,然后选择并下载所需版本的 Greengrass 核心软件 (适用于我的 Raspberry Pi 的 ARMv7l),最后单击 Finish

现在我打开 Pi 的电源,并将安全资源和软件复制到其中 (我将它们放在一个 S3 存储桶中,并使用 wget下载它们)。这是此时的外壳程序历史记录:

重要更新:正如我在 AWS 安全团队的一位细心的同事指出的那样,这不是向设备分发密钥的好方法。我本来可以使用 AWS CLI 从加密的存储桶中下载,通过剪切和粘贴复制它们,或者使用 USB 闪存盘。

我按照用户指南中的说明创建新用户和组,然后运行 rpi-update 脚本,并安装几个程序包,包括 sqlite3openssl几次重启后,我就可以继续了!

接下来,仍然遵循指示,解压缩 Greengrass 核心软件,并将安全资源移动到其最终目的地 (/greengrass/configuration/certs),在这个过程中为它们指定通用名称。目录看起来如下所示:

下一步是将核心与 AWS IoT 事物关联起来。返回到控制台,点击浏览组和 Greengrass 核心,找到 Thing ARN:

将证书名称和 Thing ARN 插入到 config.json 文件中,同时填充缺失的 iotHostggHost部分:

启动 Greengrass 守护程序 (这是我的第二次尝试;第一次我把其中一个路径名称拼错了):

在命令行中度过愉快的时光后 (这让我回想起了使用 Unix v7 和 BSD 4.2 的日子),现在是时候再次转到视觉界面了!访问我的 AWS IoT 控制面板,看到我的 Greengrass 核心正在与 IoT 建立连接:

我转到 Lambda 控制台并使用 Python 2.7 运行时创建一个 Lambda 函数 (IAM 角色在这里无关紧要):

以常用方式发布函数,然后跳转到 Greengrass 控制台,单击我的组,并选择添加一个 Lambda 函数:

然后选择要部署的版本:

我还将此函数配置为长期存在而不是按需提供:

我的代码会将消息发布到 AWS IoT,所以我通过指定源和目标来创建一个订阅:

我还在订阅上设置一个主题筛选条件 (hello/world):

确认完成的设置并保存我的订阅,现在我已准备就绪,可以部署代码了。重新访问我的组,单击 Deployments,并从 Actions 菜单中选择 Deploy

选择 Automatic detection 以便继续:

由于这是我的第一个部署,我需要创建一个服务级角色,以便为 Greengrass 授予访问其他 AWS 服务的权限。直接单击 Grant permission

可以看到每个部署的状态:

代码现在已在我的 Pi 上运行!它向主题 hello/world 发布消息;我可以通过转到 IoT 控制台,单击“Test”并订阅该主题,来查看这些消息:

消息如下所示:

完成所有设置工作后,我可以通过上传、发布和部署代码的新版本来进行迭代开发。我计划使用 BrickPi 来控制一些 LEGO Technic 电动车,并发布从一些传感器收集的数据。敬请关注相关文章!

Greengrass 定价

作为 AWS 免费套餐的一部分,您可以在三台设备上免费运行一年 Greengrass 核心。在下一级别 (3 到 10,000 台设备),有两个选项可用:

  • 即付即用 – 每台设备每个月 0.16 USD。
  • 年度承诺 – 每台设备每年 1.49 USD,节省 17.5% 的成本。

如果您想在 10,000 台以上的设备上运行 Greengrass 核心,或者想做出更长期的承诺,请与我们联系;有关所有定价模型的详细信息,请参阅 Greengrass 定价页面。

-Jeff

深入Serverless—让Lambda 和 API Gateway支持二进制数据

1.概述

Serverless即无服务器架构正在迅速举起,AWS Lambda 和AWS API Gateway作为Serverless 架构主要的服务,正受到广泛关注,也有越来越多用户使用它们,享受其带来的便利。传统上来说,Lambda 和API Gateway主要用以实现RESTful接口,其响应输出结果是JSON数据,而实际业务场景还有需要输出二进制数据流的情况,比如输出图片内容。本文以触发式图片处理服务为例,深入挖掘Lambda 和 API Gateway的最新功能,让它们支持二进制数据,展示无服务器架构更全面的服务能力。

先看一个经典架构的案例——响应式主动图片处理服务。

Lambda配合 S3 文件上传事件触发在后台进行图片处理,比如生成缩略图,然后再上传到 S3,这是Lambda用于事件触发的一个经典场景。

http://docs.aws.amazon.com/lambda/latest/dg/with-s3-example.html

在实际生产环境中这套架构还有一些局限,比如:

  • 后台运行的图片处理可能无法保证及时完成,用户上传完原图后需要立即查看缩略图时还没有生成。
  • 很多图片都是刚上传后使用频繁,一段时间以后就使用很少了,但是缩略图还不能删,因为也可能有少量使用,比如查看历史订单时。
  • 客户端设备类型繁多,一次性生成所有尺寸的缩略图,会消耗较多Lambda运算时间和 S3存储。
  • 如果增加了新的尺寸类型,旧图片要再生成新的缩略图就比较麻烦了。

我们使用用户触发的架构来实现实时图片处理服务,即当用户请求某个缩略图时实时生成该尺寸的缩略图,然后通过 CloudFront缓存在CDN上。这其实还是事件触发执行Lambda,只是由文件上传的事件主动触发,变成了用户访问的被动触发。但是只有原图存储在S3,任何尺寸的缩图都不生成文件不存储到S3。要实现此架构方案,核心技术点就是让Lambda和API Gateway可以响应输出二进制的图片数据流。

总体架构图如下:

主要技术点:

  • 涉及服务都是AWS完全托管的,自动扩容,无需运维,尤其是 Lambda,按运算时间付费,省去 EC2 部署的繁琐。
  • 原图存在 S3 上,只开放给 Lambda 的读取权限,禁止其它人访问原图,保护原图数据安全。
  • Lambda 实时生成缩略图,尽管Lambda目前还不支持直接输出二进制数据,我们可以设置让它输出base64编码后的文本,并且不再使用JSON结构。配合API Gateway可以把base64编码后的文本再转换回二进制数据,最终就可以实现输出二进制数据流了。
  • 用 API Gateway 实现 图片访问的URL。我们常见的API Gateway用来做RESTful 的API接口,接口的 URL形式通常是 /resource?parameter=value,其实还可以配置成不用GET参数,而把URL中的路径部分作参数映射成后端的参数。
  • 回源 API Gateway,缓存时间可以用户自定义,建议为24小时。直接支持 HTTPS,支持享用AWS全球边缘节点。
  • CloudFront 上还可使用 Route 53 配置域名,支持用户自己的域名。

相比前述的主动生成,被动触发生成有以下便利或优势:

  • 缩略图都不存储在S3上,节省存储空间和成本。
  • 方便给旧图增加新尺寸的缩略图。

2.部署与配置

本例中使用的 Region 是Oregon(us-west-2),有关文件从以下链接下载:

https://s3.amazonaws.com/snowpeak-share/lambda/awslogo.png

2.1 使用IAM设置权限

打开控制台:

https://console.aws.amazon.com/iam/home?region=us-west-2

创建一个 Policy,名叫CloudWatchLogsWrite,用于确保Lambda运行的日志可以写到 CloudWatch Logs。内容是

{
"Version":
"2012-10-17",
"Statement": [
{
"Effect":
"Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": [
"arn:aws:logs:*:*:*"
]
}
]
}

 

创建 一个Role,名叫 LambdaReadS3,用于Lambda访问S3。Attach Poilcy选AmazonS3ReadOnlyAccess 和刚刚创建的CloudWatchLogsWrite。

记下它的ARN,比如arn:aws:iam::111122223333:role/LambdaReadS3

2.2 使用S3 配置原图存储

打开控制台

https://console.aws.amazon.com/s3/home?region=us-west-2

创建 Bucket,Bucket Name需要填写全局唯一的,比如 img201703,Region 选 US Standard。通常图片的原图禁止直接访问,这里我们设置权限,仅允许 Lambda 访问。

Permissions 下点 Add bucket policy,使用AWS Policy Generator :

Select Type of Policy 选 S3 bucket policy,

Principal 填写前述创建的LambdaReadS3 的 ARN arn:aws:iam::111122223333:role/LambdaReadS3

Actions 下拉选中 GetObjext,

Amazon Resource Name (ARN) 填写刚刚创建的bucket 的ARN,比如arn:aws:s3:::image201703/*

然后点Add Statement,最后再点 Generate Policy,生成类似

{
"Id": "Policy1411122223333",
"Version":
"2012-10-17",
"Statement": [
{
"Sid": "Stmt1411122223333",
"Action": [
"s3:GetObject"
],
"Effect":
"Allow",
"Resource":
"arn:aws:s3:::img201703/*",
"Principal": {
"AWS": [
"arn:aws:iam::111122223333:role/LambdaReadS3"
]
}
}
]
}

复制粘贴到Bucket Policy Editor里 save即可。

验证S3 bucket配置效果。把前下载图片文件awslogo.png 下载到自己电脑,然后把它上传到这个 bucket里,测试一下。直接访问链接不能下载,需要右键菜单点“Download”才能下载,说明权限配置已经成功。

2.3 创建Lambda函数

AWS Lambda 管理控制台:

https://us-west-2.console.aws.amazon.com/lambda/home?region=us-west-2#/

点击Create a Lambda function 按钮

Select runtime 菜单选Node.js 4.3,然后点Blank Function。

Configure triggers页,点Next。

Configure function 页,在 Name 栏输入ImageMagick,Description 栏输入

Uses ImageMagick to perform simple image processing operations, such as resizing.

 

Lambda function code 里填写以下代码:

'use strict';

var AWS = require('aws-sdk');
const im = require('imagemagick');
const fs = require('fs');

const defaultFilePath = 'awslogo_w300.png';
// 样式名配置,把宽高尺寸组合定义成样式名。
const config = {
'w500':{'width':500,
'height':300},
'w300':{'width':300,
'height':150},
'w50':{'width':50,
'height':40}
};
// 默认样式名
const defaultStyle = 'w50';
// 完成处理后把临时文件删除的方法。
const postProcessResource = (resource, fn) => {
let ret = null;
if (resource) {
if (fn) {
ret = fn(resource);
}
try {

fs.unlinkSync(resource);
} catch (err) {
// Ignore
}
}
return ret;
};
// 生成缩略图的主方法
const resize = (filePathResize, style, data, callback) => {
// Lambda 本地写文件,必须是 /tmp/ 下
var filePathResize =
'/tmp/'+filePathResize;
// 直接用 Buffer 操作图片转换,源文件不写到本地磁盘,但是转换成的文件要写盘,所以最后再用 postProcessResource 把临时文件删了。
var resizeReq = {
srcData: data.Body,
dstPath: filePathResize,
width: style.width,
height: style.height
};
try {
im.resize(resizeReq,
(err) => {
if (err) {
throw err;
} else {

console.log('Resize ok: '+ filePathResize);
// 注意这里不使用JSON结构,直接输出图片内容数据,并且要进行base64转码。
callback(null,
postProcessResource(filePathResize, (file) => new
Buffer(fs.readFileSync(file)).toString('base64')));
}
});
} catch (err) {
console.log('Resize
operation failed:', err);
callback(err);
}
};

exports.handler = (event, context, callback) => {
var s3 = new AWS.S3();
//改成刚刚创建的 bucket 名字,如 img201703
var bucketName = 'image201702';
// 从文件 URI 中截取出 S3 上的 key 和尺寸信息。
// 稳妥起见,尺寸信息应该规定成样式名字,而不是直接把宽高参数化,因为后者会被人滥用。
// 使用样式还有个好处,样式名字如果写错,可以有个默认的样式。
var filepath = (undefined ===
event.filepath ? defaultFilePath:event.filepath);
var tmp =
filepath.split('.');
var fileExt = tmp[1];
tmp = tmp[0].split('_');
var fileName = tmp[0];
var style = tmp.pop();
console.log(style);
var validStyle = false;
for (var i in config)
{
if (style == i)
{
validStyle = true;
break;
}
}
style = validStyle ? style :
defaultStyle;
console.log(style);
var fileKey =
fileName+'.'+fileExt;
var params = {Bucket:
bucketName, Key: fileKey};

// 从 S3 下载文件,成功后再回调缩图
s3.getObject(params,
function(err, data) {
if (err)
{
console.log(err,
err.stack);
}
else
{
resize(filepath,
config[style], data, callback);
}
});
};

注意一定要把

var bucketName = ‘image201702’;

改成刚刚创建的 bucket 名字,如

var bucketName = ‘img201703’;

这个 Lambda 函数就可以运行了。

Lambda function handler and role 部分的Role 选择 Choose an existing role,然后Existing role 选择之前创建的LambdaReadS3。

Advanced settings:Memory (MB)* 选 512,Timeout 选30 sec。

其它保持默认,点 Next;最后一页确认一下,点Create Function。

提示创建成功。

点击 Test 按钮,测试一下。第一次测试时,会弹出测试使用的参数值,这些参数其实我们都不用,也不用管它,点击 Save and test 按钮测试即可。以后再测试就不会弹出了。

显示“Execution result: succeeded”表示测试成功了,右边的 Logs 链接可以点击,前往 CloudWatch Logs,查看详细日志。右下方的Log output是当前测试执行的输出。

可以看到这里 Execution result 下面显示的结果是一个长字符串,已经不是我们以往普通Lambda函数返回的JSON结构了。想做进一步验证的,可以把这个长字符串 base64 解码,会看到一个尺寸变小的图片,那样可以进一步验证我们运行成功。

2.4 配置API Gateway

管理控制台

https://us-west-2.console.aws.amazon.com/apigateway/home?region=us-west-2#

2.4.1 配置API

点击 Create API

API name 填写ImageMagick。
Description 填写Endpoint for Lambda using ImageMagick to perform simple image processing operations, such as resizing.

这时左侧导航链接会显示成 APIs > ImageMagick > Resources。点击 Actions 下拉菜单,选择Create Resource。

Resource Name* 填写filepath

Resource Path* 填写 {filepath},注意要包括大括号。然后点击Create Resource按钮。

这时刚刚创建的{filepath}应该是选中状态,再点击Actions 下拉菜单,选择Create Method,在当时出现的方法菜单里选择GET,然后点后面的对号符确定。

然后在/{filepath} – GET – Setup 页,Integration type 保持Lambda Function 不变,Lambda Region 选 us-west-2,在Lambda Function 格输入ImageMagick,下拉的备选菜单中点中ImageMagick,点击 Save。弹出赋权限提示,点击“OK”。

这时会显示出完整的“/{filepath} – GET – Method Execution”配置页。

点击右上角“Integration Request”链接,进入配置页,点击“Body Mapping Templates”左边的三角形展开之。

Request body passthrough 选择When there are no templates defined (recommended)。

点击最下面“add mapping template”链接,“Content-Type”格,注意即使这里已经有提示文字application/json,还是要自己输入application/json,然后点击右边的对勾链接,下面会弹出模板编辑输入框,输入

{“filepath”: “$input.params(‘filepath’)”}

完成的效果如下图所示:

最后点击“Save”按钮。点击左上角 “Method Execution”链接返回。

点击左下角“Method Response”链接,HTTP Status 下点击第一行200左边的三角形展开之,“Response Headers for 200” 下点击add header链接,Name格输入Content-Type,点击右边的对勾链接保存。Response Body for 200 下已有一行application/json,点击其右边的笔图标编辑,把值改成image/png,点击右边的对勾链接保存。点击左上角 “Method Execution”链接返回。

点击右下角“Integration Response”链接,点击第一行 “- 200 Yes”左边的三角形展开之,“Content handling”选择 Convert to binary(if needed),然后点击“Save”按钮。这项配置是把Lambda返回的base64编码的图片数据转换成二进制的图片数据,是此架构的另一个技术重点。

Header Mappings 下已有一行Content-Type,点击其右边的笔图标编辑,在“Mapping value”格输入’image/png’,注意要带上单引号,点击右边的对勾链接保存。

点击“Body Mapping Templates”左边三角形展开之,点击“application/json”右边的减号符,把它删除掉。点击左上角 “Method Execution”链接返回。

点击最左边的竖条Test链接,来到“/{filepath} – GET – Method Test”页,“{filepath}”格输入awslogo_w300.png,点击 Test 按钮。右侧显示类似下面的结果

Request: /awslogo_w300.png

Status: 200

Latency: 247 ms

Response Body是乱码是正常的,因为我们的返回内容就是图片文件本身。可以查看右下角Logs 部分显示的详细执行情况,显示类似以下的日志表示执行成功。

Thu Mar 09 03:40:11 UTC 2017 : Method response body
after transformations: [Binary Data]

Thu Mar 09 03:40:11 UTC 2017 : Method response
headers: {X-Amzn-Trace-Id=Root=1-12345678-1234567890abcdefghijlkln,
Content-Type=image/png}

Thu Mar 09 03:40:11 UTC 2017 : Successfully completed
execution

Thu Mar 09 03:40:11 UTC 2017 : Method completed with
status: 200

2.4.2 部署API

点击Actions按钮,在下拉菜单中点选Deploy API,Deployment stage 选择[New Stage],Stage name 输入 test,注意这里都是小写。

Stage description 输入 test stage

Deployment description 输入 initial deploy to test.

点击Deploy按钮。然后会跳转到Test Stage Editor 页。

复制Invoke URL: 后面的链接,比如

https://1234567890.execute-api.us-west-2.amazonaws.com/test

然后在后面接上awslogo_w300.png,组成形如以下的链接

https://1234567890.execute-api.us-west-2.amazonaws.com/test/awslogo_w300.png

输入浏览器地址栏里访问,可以得到一张图片,表示 API Gateway已经配置成功。

2.5 配置CloudFront分发

我们在API Gateway前再加上CloudFront,通过 CDN 缓存生成好的图片,就可以实现不需要把缩略图额外存储,而又不用每次都为了图片处理进行计算。这里使用了CDN和其它使用CDN的思路一样,如果更新图片,不建议调用清除CloudFront的API,而是从应用程序生成新的图片标识字符串,从而生成新的URL让CloudFront成为无缓存状态从而回源重新计算。

由于API Gateway仅支持HTTPS访问,而CloudFront同时支持HTTP和HTTPS,所以我们可以配置成CloudFront前端同时支持HTTP和HTTPS,但是实测发现CloudFront前端使用HTTP而回源使用HTTPS时性能不如前端和回源同为HTTPS。所以这里我们也采用同时HTTPS的方式。

我们打开CloudFront的管理控制台

https://console.aws.amazon.com/cloudfront/home?region=us-west-2#

点击Create Distribution按钮,在 Web 下点击Get Started。

Origin Domain Name,输入上述部署出来的 API Gateway 的域名,比如 1234567890.execute-api.us-west-2.amazonaws.com

Origin Path,输入上述 API Gateway 的 Stage 名,如 /test

Origin Protocol Policy 选择HTTPS Only

Object Caching 点选Customize,然后Maximum TTL输入86400

Alternate Domain Names (CNAMEs) 栏本例使用自己的域名,比如img.myexample.com。SSL Certificate选择Custom SSL Certificate (example.com),并从下面的证书菜单中选择一个已经通过 ACM 管理的证书。

注意,如果填写了自己的域名,那么下面的SSL Certificate就不建议使用默认的Default CloudFront Certificate (*.cloudfront.net),因为很多浏览器和客户端会发现证书的域名和图片 CDN 的域名不一致会报警告。

其它项保持默认,点击Create Distribution按钮,然后回到CloudFront Distributions列表,这里刚刚创建的记录Status会显示为 In Progress,我们点击ID的链接,前进到详情页,可以看到Domain Name 显示一个CloudFront分发的URL,比如cloudfronttest.cloudfront.net。大约 10 多分钟后,等待Distribution Status 变成Deployed,我们可以用上述域名来测试一下。注意测试用的URL不要包含API Gateway 的 Stage 名,比如

https://1234567890.execute-api.us-west-2.amazonaws.com/test/awslogo_w300.png

那么 CloudFront 的URL 应该是

https://cloudfronttest.cloudfront.net/awslogo_w300.png

尽管我们已经配置了自己的域名,但是这时自已的域名还未生效。我们还需要到Route 53 去添加域名解析。

2.6  Route 53

最后我们使用Route 53 实现自定义域名关联CloudFront分发。访问 Route 53 管制台

https://console.aws.amazon.com/route53/home?region=us-west-2

在Hosted Zone 下点击一个域名,在域名列表页,点击上方Create Record Set 按钮,页面右侧会弹出创建记录集的面板。

Name 栏输入 img。

Type 保持默认 A – IP4 Address不变。

Alias 点选 Yes,在Alias Target输入前述创建的CloudFront分发的URL cloudfronttest.cloudfront.net。

点击右下角Create按钮完成创建。

3. 效果验证     

现在我们回到CloudFront控制台,等到我们的Distribution 的Status变成Deployed,先用CloudFront自身的域名访问一下。

https://cloudfronttest.cloudfront.net/awslogo_w300.png

顺利的话,会看到咱们的范例图片。再以自定义域名访问一下。

http://img.myexample.com/awslogo_w300.png

还是输出这张图片,那么到此就全部部署成功了。现在可以在S3的bucket里上传更多其它图片,比如 abc.png,然后访问时使用的URL就是

http://img.myexample.com/abc_w300.png

用浏览器打开调试工具,可以看到响应头里已经有

X-Cache: Hit from cloudfront

表示已经经过CloudFront缓存。

4. 监控

这个架构方案使用的服务都可以通过CloudTrail记录管理行为,使用CloudWatch记录用户访问情况。

4.1 Lambda 监控

在Lambda控制台点击我们的ImageMagick 函数,然后点击选项卡最末一个Monitoring,可以看到常用指标的简易图表。

点击任何一个图表,都可以前进到CloudWatch相关指标的指标详细页。然后我们还可以为各个指标配置相关的CloudWatch Alarm,用以监控和报警。

点击View logs in CloudWatch链接,可以前往CloudWatch Log,这里记录了这个Lambda函数每次执行的详细信息,包括我们的函数中自已输出的调试信息,方便我们排查问题。

4.2 API Gateway 监控

在API Gateway控制台找到我们的API ImageMagick,点击它下面的 Dashboard。

如果部署了多个Stage,注意左上角 Stage 菜单要选择相应的Stage。同样下面展示的是常用图表,点击每个图表也可以前往CloudWatch显示指标监控详情。

4.3 CloudFront日志

我们刚刚配置CloudFront时没有启用日志。如果需要日志,可以来到CloudFront控制台,点击我们刚刚创建的分发,在General选项页点击Edit按钮。在Edit Distribution 页找到Logging项,选择On,然后再填写Bucket for Logs和Log Prefix,这样CloudFront的访问日志就会以文件形式存储在相应的S3的bucket 里了。

5. 小结

我们这样一个例子使用了Lambda和API Gateway的一些高级功能,并串联了一系列AWS全托管的服务,演示了一个无服务器架构的典型场景。虽然实现的功能比较简单,但是 Lambda函数可以继续扩展,提供更丰富功能,比如截图、增加水印、定制文本等,几乎满足任何的业务需求。相比传统的的计算能力部署,不论是用EC2还是ECS容器,都要自己管理扩容,而使用 Lambda无需管理扩容,只管运行代码。能够让我们从繁琐的重复工作中解脱,而把业务集中到业务开发上,这正是无服务器架构的真正理念和优势。

作者介绍:

薛峰

AWS解决方案架构师,AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内和全球的应用和推广,在大规模并发应用架构、移动应用以及无服务器架构等方面有丰富的实践经验。在加入AWS之前曾长期从事互联网应用开发,先后在新浪、唯品会等公司担任架构师、技术总监等职位。对跨平台多终端的互联网应用架构和方案有深入的研究。

使用AWS Lambda和Amazon DynamoDB自动管理AWS CloudFormation模板中的Parameters和Mappings

背景介绍

相信AWS的用户对AWS CloudFormation都不会陌生。AWS CloudFormation是实现IAC(Infrastructure as Code)自动化运维的一项重要服务,可以帮助用户对 AWS资源进行建模和设置,以便能花较少的时间管理这些资源。CloudFormation中有两个重要选项:Mappings段和Parameters段,可以帮助用户组织模板里的参数和映射,让用户更好地自定义堆栈,以实现模板的重用和复用。比方说可以用Mappings管理对应AWS上不同region的AMI ID,或者管理企业内部的不同部门。

但是当用户所在的组织越来越多地采用IAC自动化时,mappings和parameters的数量也会急剧增长,给CloudFormation模板的编写和维护带来复杂度。

解决方案

本文里我们介绍一种方法:用当前流行的Serverless计算AWS Lambda 和Amazon DynamoDB自动地管理AWS CloudFormation模板中的Parameters和Mappings。

本文中主要用到了以下几种 AWS服务:

1、DynamoDB表:Amazon DynamoDB是一个NoSQL数据库,这里我们采用它保存CloudFormation模板中所有的mappings和parameters。不仅可以实现集中存放,而且可以依赖DynamoDB的接口实现方便快速地增删和查找。比方说在我们的sample code中,整个企业采用这样一张表:partition key包括组名(比如说team1、team2等)和环境(比如说development、test、production等),sort key保存应用的名字。这个表里的数据类似这样:

当我们把这些数据都insert到DynamoDB中后,可以在AWS console里看到表中的内容是这样的:

2、Lambda方法:AWS Lambda又称为Serverless的计算,通过它你可以运行你的code而不需要预配置或者管理任何服务器。这里我们采用Lambda方法实现CloudFormation和DynamoDB之间的关联,它从CloudFormation模板接收primary key和sort key作为输入,查找DynamoDB表,并且返回所有的key-value数据。

3、Custom lookup resource:这是CloudFormation里的一个自定义资源,与一个Lambda方法绑定。CloudFormation除了可以定义已有的AWS资源,还支持几种自定义资源,包括这种以Lambda方法作为后端的自定义资源。当这种自定义资源创建、更新或者删除时,CloudFormation自动地向Lambda API发起请求,引发方法并将请求的数据传给Lambda方法,本例中所请求的数据是primary key,返回的数据是key-value数据。通常在一个组织中只需要建立这一个custom resource,所有的CloudFormation模板都可以复用它。下图是sample code里建立的custom resource:

让我们将这几种服务组合起来,并且定义好它们之间的交互顺序,整个解决方案就是下图展示的这样:

那么整个的交互顺序如下:

1、用户创建DynamoDB表,插入所需的mappings和parameters数据。

2、CloudFormation模板中的custom resource调用Lambda方法,用组名和环境名称(“teamname-environment”)作为partition key,用应用名称(”appname”)作为sort key。

3、Lambda方法用partition key和sort key作为输入查询DynamoDB表。

4、DyanamoDB将结果返回给Lambda方法。

5、Lambda方法将这些key-value数据作为结果返回给模板中的custom resource。

6、custom resource拿到数据后,堆栈里的其他资源可以通过Fn::GetAtt的方式获得这些数据。

结论

通过这种方式,可以将我们创建堆栈所需的固定部分保存在模板中,而将可变部分mappings和parameters保存在方便增删改查的DynamoDB中,用Lambda实现两者之间的关联。对于大型组织来说,这样可以提高运维效率,也是使用CloudFormation的一种最佳实践。

参考

可以在我们的网站上下载到相关的sample code:https://github.com/awslabs/custom-lookup-lambda

关于AWS Lambda的更多内容请参考网站:https://aws.amazon.com/lambda/

关于CloudFormation自定义资源的更多内容请参考网站:http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html

作者介绍

张芸

AWS云架构咨询顾问,获得AWS解决方案架构师专业级认证和DevOps工程师专业级认证,为企业客户和合作伙伴提供迈向云端的专业服务。目前已为多家跨国公司及本土公司、合作伙伴提供上云迁移、应用优化、架构设计等咨询设计和实施服务。在加入AWS之前有近10年的云计算和大数据开源技术研究和开发经验,拥有多项美国和中国专利及专利申请,涉及云计算及服务,分布式系统,软件定义数据中心和自动化运维等领域,合作编著图书《大数据–战略·技术·实践》。

 

带您玩转Lambda,轻松构建Serverless后台!

Amazon CTO Werner Vogels曾经在AWS re:Invent大会上提到: 如果把云计算理解成一个执行环境,那么,在这个环境里,函数(即业务逻辑的载体)+数据(即跟业务相关的输入与输出)就是应用的核心,有了Functions、Data、Event这三者,其它任何代码和框架,无非是整个应用的胶水和UI罢了。那么,最理想的情况就是用最少的时间写胶水,将更多的时间投入到核心应用的开发中,甚至,彻底实现整个软件栈的微服务化。

那么能不能做到呢?答案是肯定的。AWS Lambda也在这样的背景下应运而生了,其实在很多人眼里,Lambda是一个具有“革命性”的服务,我本人也非常喜欢Lambda这个服务,因为它给我的感觉是: 轻、快、高可用!能够快速将想法写成代码,并应用到生产,不需要关心底层基础设施的运维。接下来,让我们一起搭建一个serverless的后台!

【1】AWS Lambda怎么用?

怎么学习Lambda呢?让我们从一个简单的数学问题开始,10以内乘法和加法运算,获得随机的一个数字。代码有注释,如下:

//Node.js尽量全使用严格模式

'use strict';

//利用console.log可以将日志自动打到CloudWatch里面

console.log('Loading function');

exports.handler = (event, context, callback) => {

    //定义一个最小值为2

    var min = 2;

    //定义一个最大值为10

    var max = 10;

    //生成一个随机数,乘以最大值,再加上一个最小值

    var generatedNumber = Math.floor(Math.random() * max) + min;

    //利用callback回调,得到结果。

    callback(null, generatedNumber);

};
接下去,然后选择Lambda服务

创建一个Lambda Function

选择Node.js 6.10的环境

当然,Lambda目前支持C#,Node.js,Python,Java,后续会支持很多的语言比如Go,PHP,Ruby等。换言之,之后任何能在Linux上跑的环境都能在Lambda上运行。

接下去把上面那段代码拷贝进去,选择“Role”角色,这其实就是Lambda执行时所拥有的权限。当然,你可以通过IAM服务创建一个新的Role,或者选择已经存在的Role。

然后点击“Create Function”,接着就会看到

好!Lambda创建成功了!在Lambda上方点击Test,进行测试,能看到输出的结果。细心的你已经发现,代码运行的时间只有0.3ms哦。

查看Lambda执行的结果:

您可以多次点击test,每次输出的结果都不一样,这是因为,代码一开始生成了一个随机数,所以每次输出的结果也都是随机的。

您可以点击“View logs in CloudWatch”,能看到所有Lambda运行相关的日志。AWS已经把这部分的日志已经自动集成到CloudWatch里面了。

如果你想结合自己常用的日志分析工具,比如sumologic,可以再用一个Lambda将CloudWatch Logs的日志导出。

【2】Lambda + API Gateway

到这里,我们发现,应用的逻辑可以交给Lambda执行,那前端的HTTP请求怎么办呢?AWS还有一个服务叫API Gateway,提供的HTTP网关服务,那么,Lambda怎么和API Gateway又怎么结合起来使用呢?

接下去,您可以进入到API Gateway这个服务里面,点击“Create API”。

写入API的名字然后创建

创建一个Method

选择HTTP Get方法。目前,AW API Gateway支持HTTP DELETE, HEAD, OPTIONS, PATCH, POST, PUT等方法。指定我们之前创建的Lambda函数,选择“Integration Type”Lambda Function。

输入Lambda对应的Region和Lambda函数的名字,然后点击Save。

然后进行部署API,点击“Deploy API”。

指定API的版本,比如prod或者test。

注意,当你定义好这个API之后,可以自动生成整套SDK,有Android,JavaScript,iOS-OC,iOS-Swift,Java。所以,开发人员可以基于这一套自定义的、标准的SDK进行统一开发。只要指定了统一的后端数据库,所有的开发人员都可以各自开发自己的内容,互不干扰,最终形成一个统一、完整的项目。

然后点击“Stages”,查看Get的http地址。

将这个地址复制到浏览器(比如Firefox),可以查看Lambda运行后输出的结果。这样,Lambda就和API gateway结合起来了。

点击刷新,当然数字会变。

【3】Lambda + API Gateway + 传参

如果客户端需要想传递参数,怎么办呢?

那就可以通过API Gateway接受客户端(比如浏览器)输入的参数,然后API Gateway把这个参数传递给后端的Lambda,Lambda通过event对象获得前端API Gateway传递过来的参数,从而进行代码的逻辑执行。

让我们先改动一下Lambda的代码,将固定值2和10换成以变量的形式传递进去。

然后再到API Gateway服务里面,找到“Integration Request”。

找到“Body Mapping Templates”,修改其中的“application/json”,输入提供的内容。

{

    "min":$input.params('min'),

    "max":$input.params('max')

}
点击保存,这样,就通过客户端就可以把参数传递给API Gateway了。比如:

https://j3bi4vs4w4.execute-api.us-west-2.amazonaws.com/prod/number

这个时候打开之前的链接是空值,因为还没传递参数进去。

https://j3bi4vs4w4.execute-api.us-west-2.amazonaws.com/prod/number?min=1&max=10

在浏览器客户端中,传递参数进去之后,比如min=1,max=10,如下:

刷新浏览器,当然会得到随机的结果。

再来一次,刷新浏览器,当然会得到随机的结果。

【4】快速部署Lambda函数?

部署Lambda的函数,可以直接在控制台输入代码,也可以在本地写好之后打成zip包上传到Lambda,或者上传到S3再指定链接内部加载到Lambda上。

当然,如果觉得不是很方便,目前其实已经有很多开源的框架支持都Lambda的快速部署了,比如SERVERLESS.com,Claudiajs.com,APEX,Zappa,Kappa,Chalice等。

【注意!】我们会在下一期内容中专门讲解这些框架怎么用,以及如何借用这些框架,再配合AWS CodePipeline,CodeCommit,CodeBuild,CloudFormation完全实现serverless微服务化,一键自动化发布和部署整个软件栈。

在这里,由于个人喜好,我们拿一个比较轻量的工具APEX举例,http://apex.run/,Apex集成了Lambda的SDK,用户只需要在本地执行apex init命令就创建了一个Lambda环境以及所需的Role,然后通过deploy命令就可以将本地的Lambda代码以及所需要的依赖自动打成zip包,并上传到云端环境。并且Apex会自动进行Lambda版本管理,更重要的是,还支持回滚,查看云端log。这可以让您真正只关心代码,写完代码之后直接部署就可以了,非常方便。你会发现,开发的时候甚至连AWS的控制台都不需要打开!

本地安装,一条curl语句。搞定了!真的挺简单的。

curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sudo sh

接下去通过aws configure配置你的权限

danrongm:~ danrong$ aws configure

AWS Access Key ID [****************2T5A]:

AWS Secret Access Key [****************Tcma]:

Default region name [us-west-2]:

Default output format [json]:

创建apex项目: apex init,然后输入项目名称 first-apex-project

接着就开始部署了

acbc32c13f31:apex-demo danrongm$ apex deploy

   • creating function         env= function=hello

   • created alias current   env= function=hello version=1

   • function created          env= function=hello name=first-apex-project_hello version=1

Apex自动会帮您创建Role,以及进行版本的管理和控制。当你修改完代码之后,可以再次执行apex deploy,只要代码有改变,版本号以数字形式就会往上增加。

如果部署其中的一个函数: apex deploy hello

如果调用函数显示输出结果: apex invoke hello

另外,可以直接在本地查看日志的输出。

apex-demo danrongm$ apex invoke -L hello 会把日志输出的所有内容输出

START RequestId: 7c432478-ee78-11e6-8d9b-21a4e48977b8 Version: 5

2017-02-09T03:33:13.014Z     7c432478-ee78-11e6-8d9b-21a4e48977b8     processing event: {}

END RequestId: 7c432478-ee78-11e6-8d9b-21a4e48977b8

REPORT RequestId: 7c432478-ee78-11e6-8d9b-21a4e48977b8     Duration: 0.41 ms     Billed Duration: 100 ms      Memory Size: 128 MBMax Memory Used: 10 MB 104

查看Apex的所有日志(其实就是最近5分钟内的CloudWatch的日志)

apex logs

【5】Lambda + CloudWatch Event

有些场景,有可能是想定期、或者定时让Lambda去执行处理逻辑,针对这种情况,可以使用CloudWatch Event,触发Lambda定时执行。

可以在CloudWatch里面创建一个Rule,然后Event selector可以通过Cron方式定期调用Lambda函数,如下:

这样,你就可以按照一定的规则,定时的去触发Lambda函数了。更多内容可参考:

http://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/events/RunLambdaSchedule.html

【6】Lambda + DynamoDB –> 数据写入到数据库

用户发送HTTP请求,交给API Gateway处理,业务逻辑交给Lambda处理,那如果动态的数据需要存储到数据库呢?AWS提供了NoSQL的数据库DynamoDB和关系型数据库RDS,这些都可以和Lambda配合使用。值得一提的是,Lambda可以和RDS一样,放在VPC内部,配置安全组。

那么,如何使用Lambda把处理后的数据存储在DynamoDB呢?Lambda又怎么和数据库进行交互呢?直接上代码。首先创建一个Lambda函数,比如命名为: lambda_dynamodb_write,代码如下

'use strict';

console.log('Loading function');

var AWS = require('aws-sdk');

var docClient = new AWS.DynamoDB.DocumentClient();

AWS.config.region = 'us-west-2’;

exports.handler = function (event, context, callback){

     var params = {

          Item: {

               date: Date.now(),

               message: "Danrong"

          },

          TableName: 'lambda_dynamodb_write_read'

     };

     docClient.put(params, function(err, data){

          if(err){

               callback(err, null);

          }else{

               callback(null, data);

          }

     });

};

【7】Lambda + DynamoDB –> 数据从数据库读取

搞定了数据库的写入操作,Lambda又怎么读写数据库里的内容呢?直接上代码。

创建一个Lambda函数,比如命名为: lambda_dynamodb_read,代码如下

'use strict';

console.log('Loading function');

var AWS = require('aws-sdk');

var docClient = new AWS.DynamoDB.DocumentClient({region:'us-west-2'});

exports.handler = function(event, context, callback){

     var params = {

          TableName: 'lambda_dynamodb_write_read',

          Limit: 100

     };

     docClient.scan(params, function(err,data){

          if(err){

               callback(err, null);

          }else{

               callback(null, data);

          }

     });

};
对于数据库的修改和删除操作,同样可以轻松做到。到这里,Lambda和DynamoDB的交互就搞定了。

【8】Lambda + API Gateway + DynamoDB

此时,我们再将前面三者,即Lambda,API Gateway,DynamoDB结合起来。创建一个Date为主键的DynamoDB Table,让它存储Lambda处理的结果,如下:

由于之前我们已经创建过HTTP GET了,同样的方式,在API Gateway里面,创建一个HTTP POST的方法。如下:

API Gateway中可以解决跨域CORS的问题,点击“Enable CORS”。

到这里,客户端浏览器发出请求,会发送到API Gateway 那边,然后API Gateway传递客户端的参数给Lambda,Lambda通过Event对象获取API Gateway传参的值,并处理逻辑。比如将数据写入到DynamoDB,或者从DynamoDB读取数据显示在前端。

【9】Lambda + API Gateway + DynamoDB + S3 + CloudFront

托管静态网站。如果您是一个网站,或者是移动、IoT等后台,可以把前端显示的静态内容,比如HTML,JS,CSS,以及所有图片托管在S3上,启用静态网站托管。

到这里,一个serverless的网站就做好了,您可以点击下面链接进行尝试。

https://s3.amazonaws.com/danrong.io/index-ajax.html

前端显示的HTML代码开源,您可以公开下载:

https://s3.cn-north-1.amazonaws.com.cn/danrong-share/external/aws-china-blog-lambda-demo-index.html

接下去,其实就是前端的UI设计了,比如,我比较喜欢用http://www.bootcss.com/

完全可以改善一下前端的展示风格,看起来舒服一点。

如果要解决域名的问题,可以使用Amazon Route53访问(注意,域名也可以直接在Route53上购买),这样,就可以用您自定义的域名访问一个Serverless的网址了。

到这里,一个类似于“点击发布评论”、“查看所有评论”的网站就完成了。整个网站基于微服务的思想,完全实现了serverless的架构。

【10】Lambda + CodeCommit + CodePipeline + CodeBuild + CloudFormation

到这里,或许您已经在考虑Lambda如何做到持续化的发布和部署呢?能不能让我的开发人员只关心写代码,其余之后的事情全部一键搞定呢?比如,开发人员在本地用各种各样的IDE写代码,写完之后将代码提交到Git仓库,然后整个pipeline自动完成。在AWS的世界里,当然可以!例如,整个流程可以这样:

我们完全可以利用AWS全面的开发工具,CodeCommit + CodePipeline + CodeBuild + CloudFormation,实现从代码开发,到代码提交,到代码发布,到代码构建,到代码部署,一键自动化发布整个软件栈。再配合Serverless的各种框架(见前面正文),真正可以做到微服务化并且快速迭代敏捷开发!

另外,读者也可以关心一下Security安全的问题,比如Authentication, Authorization, Sensitive data等问题;关于Quality,比如Testing, Continuous Integration, Deployment等问题。这两部分的内容,我们将会在下一期中介绍,期待您继续关注AWS中国官方微信。

更多关于Lambda内容可以参考:

https://aws.amazon.com/cn/lambda/

http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/welcome.html

 

作者介绍:

毛郸榕

AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内的应用和推广,毕业于北京航空航天大学云计算专业,硕士,毕业后直接加入亚马逊AWS中国。在大规模后台架构、企业混合IT和自动化运维等方面有着丰富的实践经验。目前在集中精力学习新一代无服务器架构的开发与设计。