Tag: Serverless(无服务器)架构


使用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模板的基本功能和特性,并带领大家用一个实例体验了通过CloudFormation部署SAM模板。在这一篇中,我们仍然结合实例讲解,为大家继续介绍使用AWS CodeBuild 构建 Lambda函数以及使用AWS CodePipeline实现自动化持续集成。

部署配置AWS CodeBuild

如果我们的Lambda函数使用了依赖库时,我们可以通过AWS CodeBuild来把依赖库编译进Lambda函数的部署包里。

AWS CodeBuild  是一个完全托管的构建服务,可用于编写源代码、运行测试并生成可立即部署的软件包。CodeBuild基于AWS管理的容器,从而实现用户无需配置、管理和扩展自己的构建服务器。CodeBuild 可持续缩放和并行处理多个生成任务,因此构建任务不必在队列中等待。使用CodeBuild,我们只需要按构建时使用计算资源的分钟数付费,从而无需为预置的构建服务器的空闲时间付费。

除了常见的Java之类的程序源码的构建,CodeBuild还可用于Lambda函数部署前的构建。下面我们用一个例子来具体说明。

请先从以下git库下载源码。

https://github.com/xfsnow/serverless/tree/master/sam/codebuild

这个例子中的Lambda函数需要Node.js 依赖库 time,我们使用CodeBuild在构建时安装这个这个time库,把它加入到 Lambda 函数的包中。

index.js 文件中以下这行,表示需要依赖库 time。

var time = require('time');

buildspec.yml 中

install:

    commands:

      - npm install time

表示在构建的安装步骤把 time 库安装进来。

  build:

    commands:

      - aws cloudformation package --template-file codebuild.yaml --s3-bucket <bucket-name> --output-template-file output_codebuild.yaml

这段其实就是使用在上一章节我们介绍过的aws cloudformation package 打包。

上传源文件

把buildspec.yml文件中的 <bucket-name> 等变量值替换成你的具体的值。

在当前目录下除了 md 文件的其它文件打包成 codebuild.zip,然后把这个 zip 文件上传你自己的 S3桶中。

配置 CodeBuild 项目

打开 CodeBuild 控制台

点击 Create project。

在 Configure your project 页

Project name 输入 serverlessCodebuild

Source provider 选择 Amazon S3

Bucket 栏选择我们的刚才上传 zip 文件的 S3 桶名称

S3 object key 输入 codebuild.zip。

Environment image 保持选择 Use an image managed by AWS CodeBuild

Operating system 选择 Ubuntu

Runtime 选 Node.js

Version 选择 aws/codebuild/nodejs:4.3.2

Artifacts type 选 Amazon S3

Bucket name 还选择我们的刚才上传 zip 文件的 S3 桶名称

确认 Create a service role in your account 已选中

Role name 输入 serverlessCodebuild

点击右下角 Continue 按钮

在 Review 页点击右下方的 Save and build 按钮。

创建成功后前进到 Build projects 列表页,此时刚刚新建的项目应该是选中的状态。点击左上角 Start build 按钮。

在 Start new build 页,直接点击右下角 Start build 按钮。

在 Build 页可以查看构建进行的进度信息。注意看 Phase details 下面的输出内容。 构建成功完成以后,可以到我们的 S3 桶中查看结果,可以看到创建出一个 serverlessCodebuild 目录,里面就是构建的成果—— output_codebuild.yaml 文件。我们把它下载到本地,就可以用它再执行 CloudFormation 部署。

使用 CloudFormation 部署

执行以下命令

aws cloudformation deploy \

   --template-file output_codebuild.yaml \

   --stack-name serverlessCodebuild \

   --capabilities CAPABILITY_IAM

顺利地话,会看到逐渐输出的返回结果

Waiting for changeset to be created..


Waiting for stack create/update to complete

Successfully created/updated stack - serverlessCodebuild

这时到 CloudFormation 的控制台已经创建出一个 serverlessCodebuild ,整个过程大约持续 1 到 2 分钟。

然后到 API Gateway 控制台,可以看到创建出的 serverlessCodebuild 的 API,点击其 Stages 下的 Prod 链接,可以看到形如下面的调用 URL: Invoke URL: https://xxxxxxxxx.execute-api.my-region.amazonaws.com/Prod

点击它,打开一个新窗口,显示

“The time in Los Angeles is Mon Aug 07 2017 03:32:42 GMT-0700 (PDT)”
表示已经部署成功。

部署配置AWS CodePipeline

每次都要手工执行aws cloudformation deploy命令来部署仍然有些繁琐,而且手工部署难免会有人工的失误。下面我们使用AWS CodePipeline来最终实现完全自动化的部署。

AWS CodePipeline 是一个托管的持续集成与持续交付服务,可以实现快速而可靠的应用程序和基础设施更新。每次更改代码时,CodePipeline 都会根据我们定义的发布流程模型构建、测试和部署代码,就像管道一样逐个步骤的执行流程中的每一步操作,还支持可选的人工审核步骤。和CodeBuild一样, CodePipeline也是只按实际使用量付费,同样无需为预置的资源空闲付费。

我们下面这个例子,Lambda函数还是使用了time依赖库,仍然使用CodeBuild安装依赖库、CloudFormation进行部署,这次我们配置CodePipeline来完成构建和部署的全部流程,实现持续集成。

总的操作流程主要是以下几步:

  1. 在 github 上创建一个库存放源文件。
  2. 创建一个 CodeBuild 项目,用于构建无服务器应用。
  3. 创建一个 IAM 角色,用于 CloudFormation 部署无服务器应用。
  4. 创建一个 CodePipeline 项目,把上述若干步骤和资源组建成管道。

在 github 上创建一个库存放源文件

请在你自己的github新建一个存储库,名为 serverlessCodepipepline。

从以下git库下载源码。

https://github.com/xfsnow/serverless/blob/master/sam/codepipeline

放在我们自已的 serverlessCodepipepline 库的根目录下。

把 buildspec.yml 中的 <bucket> 更新成自己的桶名称,再 commit 到 git 库中。

配置 CodeBuild 项目

  • 打开 CodeBuild 控制台,点击 Create project。

在 Configure your project 页

Project name 输入 serverlessCodepipeline

Source provider 选择 Github

Repository 选择 Use a repository in my account

Repository URL 输入我们自己的库的路径,比如 https://github.com/xfsnow/serverlessCodepipepline

  • Environment image 保持选择 Use an image managed by AWS CodeBuild

Operating system 选择 Ubuntu

Runtime 选 Node.js

Version 选择 aws/codebuild/nodejs:4.3.2

Build specification 保持选中 Use the buildspec.yml in the source code root directory

Artifacts type 选 Amazon S3

Bucket name 还选择我们在 buildspec.yml 中指定的 S3 桶名称

确认 Create a service role in your account 已选中

Role name 输入 serverlessCodebuild,点击右下角 Continue 按钮。

  • 在 Review 页点击右下方的 Save and build 按钮。

创建成功后前进到 Build projects 列表页,此时刚刚新建的项目应该是选中的状态。点击左上角 Start build 按钮。

在 Start new build 页,直接点击右下角 Start build 按钮。

  • 在 Build 页可以查看构建进行的进度信息。注意看 Phase details 下面的输出内容。

构建成功完成以后,可以到我们的 S3 桶中查看结果,可以看到创建出一个 serverlessCodepipeline 目录,里面就是构建的成果—— output-codepipeline.yaml 文件。

我们可以把它下载到本地看一下,后续我们继续配置 CodePipeline 就是用它来做无服务器资源的部署。

配置 IAM 角色

登录 AWS 管理控制台。点击左侧导航链接中的 Roles,点击 Create new role 按钮。

  • 在 Select role type 页选择 AWS Service Role,找到 AWS Cloudformation Role 点击其右边的 Select 按钮。
  • 在 Attach Policy 页,选择 AWSLambdaExecute。点击 Next Step 按钮。
  • 在 Set role name and review 页, Role name 输入 cloudformation-lambda-execution,然后点击 Create role 按钮。
  • 打开刚才创建的角色,在 Permissions 选项卡下,点击 Inline Policies 展开之,然后选择 click here 链接。

选择 Custom Policy,然后选择 Select。

在 Policy Name 中,输入 cloudformation-deploy-lambda ,然后将以下内容中的 region account_id 替换成你自己的值,粘贴到 Policy Document 字段中:

{

    "Statement": [

        {

            "Action": [

                "s3:GetObject",

                "s3:GetObjectVersion",

                "s3:GetBucketVersioning"

            ],

            "Resource": "*",

            "Effect": "Allow"

        },

        {

            "Action": [

                "s3:PutObject"

            ],

            "Resource": [

                "arn:aws:s3:::codepipeline*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "lambda:*"

            ],

            "Resource": [

                "arn:aws:lambda:region:account-id:function:*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "apigateway:*"

            ],

            "Resource": [

                "arn:aws:apigateway:region::*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "iam:GetRole",

                "iam:CreateRole",

                "iam:DeleteRole"

            ],

            "Resource": [

                "arn:aws:iam::account-id:role/*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "iam:AttachRolePolicy",

                "iam:DetachRolePolicy"

            ],

            "Resource": [

                "arn:aws:iam::account-id:role/*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "iam:PassRole"

            ],

            "Resource": [

                "*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "cloudformation:CreateChangeSet"

            ],

            "Resource": [

                "arn:aws:cloudformation:region:aws:transform/Serverless-2016-10-31"

            ],

            "Effect": "Allow"

        }

    ],

    "Version": "2012-10-17"

}    

点击 Validate Policy,然后点击 Apply Policy。

配置 CodePipeline 项目
打开 CodePipeline 控制台,点击 Create project。

  • 在 Step 1: Name 页

Project name 输入 serverlessCodepipeline,点击“Next Step” 按钮。

  • 在 Step 2: Source 页

Source provider 选择 Github,然后点击 Connect to GitHub 按钮,关联 GitHub 账号。按提示完成关联操作。

回到 AWS 页面后,Repository 选择前述我们自己创建的存储库。

Branch 选择 master ,点击“Next Step” 按钮。

  • 在 Step 3: Build 页

Build provider 选择 AWS CodeBuild

Configure your project 保持选中 Select an existing build project。

Project name 在下拉列表中选择我们前面创建的 serverlessCodepipeline 项目。

  •  在 Step 4: Deploy 页

Deployment provider 选择 AWS CloudFormation。

Action mode 选择 Create or replace a change set。

Stack name 输入 serverlessCodepipeline。

Change set name 输入 serverlessCodepipelineChangeSet。

Template file 输入 buildspec.yml 中指定的构建结果文件名 output-codepipeline.yaml。

Capabilities 选择 CAPABILITY_IAM。

Role name 选择我们前面创建的 IAM 角色 cloudformation-lambda-execution。 点击 Next Step 按钮。

  • 在 Step 5: Service Role 页

点击 Create Role 按钮,在弹出的 IAM AWS CodePipeline is requesting permission to use resources in your account 页面,直接点击右下角 Allow 按钮,返回后点击 Next Step 按钮。

  • 在 Step 6: Review 页面,直接点击右下角 点击右下角的 Create Pipeline 按钮。最后来到 serverlessCodepipeline 项目详情页。
  • 增加测试部署阶段 在 serverlessCodepipeline 详情页点击 Edit 按钮。

在 Staging 阶段下面点击 +Stage 链接。

在 Stage name 栏输入 Beta,然后点击其下面的 +Action 按钮。

在 Action category 中,选择Deploy。

在 Action name 中,输入 executeChangeSet。

在 Deployment provider 中,选择 AWS CloudFormation。

在 Action mode: 中,选择 execute a changeset。前一步我们已经创建了 ChangeSet,将 SAM 模板转换为完整的 AWS CloudFormation 格式,现在我们要使用 deployChangeSet 部署 AWS CloudFormation 模板了。

在 Stack name:中,输入 serverlessCodepipeline。

在 Change set name:中,输入 serverlessCodepipelineChangeSet。

选择 Add Action。

回到页面顶部点击 Save pipeline changes。

选择 Save and continue。

查看结果

我们在 serverlessCodepipeline 项目详情页稍等10秒左右,Pipeline 会自动开始第一次部署。可以随时查看到各个步骤的执行情况,比如:

Source
GitHub
Succeeded 2 min ago
d24ff81
最后等到 Beta 步骤也完成,这时到 CloudFormation 的控制台查看已经创建出一个 serverlessCodepipeline ,整个过程大约持续 3到5 分钟。

然后到 API Gateway 控制台,可以看到创建出的 serverlessCodepipeline 的 API,点击其 Stages 下的 Prod 链接,可以看到形如下面的调用 URL: Invoke URL: https://xxxxxxxxx.execute-api.my-region.amazonaws.com/Prod

复制此 URL,打开一个新窗口,粘贴进地址栏,然后在后面再输入 /time,组成形如

https://xxxxxxxxx.execute-api.my-region.amazonaws.com/Prod/time

的链接再访问之,显示

“The time in Los Angeles is Mon Aug 07 2017 03:31:39 GMT-0700 (PDT)”
表示已经部署成功。

然后我们模拟代码更新,把你自己的 github 存储库中的 README.md 文件编辑一下,然后 git commit 到 github 上去。 然后再回到 serverlessCodepipeline 详情页,稍等一会我们会看到从 Source 开始整个管道会再次执行一遍。

执行到每一步时,我们都可以点击 Detail 链接到相关服务的详情页查看具体进度。比如 CloudFormation 会创建出一个新的 serverlessCodepipelineChangeSet 来执行变更。

最后到 API Gateway 的 serverlessCodepipeline API,选择一个 Stage ,再点选 Deployment History 可以看到 Deployment date时间更新了。

小结

今天我们继续结合实例,为大家讲解了使用AWS CodeBuild 构建 Lambda函数以及使用AWS CodePipeline实现自动化持续集成。这些也是基于AWS 无服务器应用模型和SAM模板,再与其它AWS运维的服务集成,共同实现无服务器应用的自动化运维。

相关资源链接

Serverless Application Model (SAM):
https://github.com/awslabs/serverless-application-model

无服务器服务官网:

AWS Lambda: https://aws.amazon.com/lambda

Amazon API Gateway: https://aws.amazon.com/api-gateway

运维相关的服务:

CloudFormation: https://aws.amazon.com/cloudformation

CodeBuild: https://aws.amaz.com/codebuild

CodePipeline: https://aws.amazon.com/codepipeline

 

作者介绍:

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

用无服务器应用模型部署无服务器应用 (一)无服务器应用模型入门

作者:薛峰

背景介绍

AWS无服务器架构也涉及到多个AWS服务,如AWS Lambda、Amazon API Gateway、Amazon DynamoDB等。如何把这些服务资源方便地管理起来呢?今天我们介绍的AWS 无服务器应用模型(AWS Serverless Application Model,以下简称AWS SAM)就是一种解决方案,它是一个开源的模型,结合AWS自动运维相关的服务如AWS CloudFormation 和AWS CodePipeline,统一管理多种资源,实现我们的无服务器应用的持续集成和部署。

我们从SAM开始,用几个具体例子为大家介绍使用AWS服务实现持续集成的具体方法,帮助大家快速上手,体验其强大和便捷。

SAM 简介

松鼠SAM是AWS Lamba和无服务器应用模型的吉祥物,寓意轻便、灵活、敏捷。它头顶的头盔上是希腊字母 lambda ,代表了AWS无服务器核心服务 Lambda。

SAM是 AWS 2016年11月发布的一个应用架构模型。遵循开源协议,是一个开放的说明文档。通过开源协议方式发布,也体现了AWS推动开源流动的努力。

官方的github地址如下:

https://github.com/awslabs/serverless-application-model

SAM实质上是一个AWS CloudFormation 的扩展,基于AWS CloudFormation 并且为无服务器做了优化,它简化了无服务器资源的管理,增加了无服务器相关的新资源类型。

SAM模板简介

AWS CloudFormation标准模板语法比较复杂,SAM模板提供了一套简化的语法,我们先来看一个简单的例子:

AWSTemplateFormatVersion: '2010-09-09'

Transform: AWS::Serverless-2016-10-31

Resources: 

  GetHtmlFunction:

    Type:
AWS::Serverless::Function

    Properties:

      CodeUri: s3://sam-demo-bucket/todo_list.zip

      Handler:
index.gethtml

      Runtime:
nodejs4.3

      Policies:
AmazonDynamoDBReadOnlyAccess

      Events:

        GetHtml:

          Type: Api

          Properties:

            Path:
/{proxy+}

            Method: ANY 

  ListTable:

    Type:
AWS::Serverless::SimpleTable 

最上面是模板格式的版本号和Transform声明。Transform声明告诉 CloudFormation这是一个 SAM 模板,需要转换成标准模板再执行。它的值取固定值,这里是 AWS::Serverless-2016-10-31,告诉CloudFormation这个模板里的声明都是无服务器应用的描述,以及进行相应的转换。

其余的两段其实都是 Resources 节点的子节点。这2段就是具体资源的声明:

GetHtmlFunction 段,Type: AWS::Serverless::Function,意思是创建一个Lambda函数,它有若干属性,如CodeUri指定函数的代码在S3的URL,Runtime 指定运行时的语言和版本,Policies 指定它的 IAM策略,以赋给它处理下游资源的权限。

Events 段,声明Lambda函数要响应的事件源。这里只有一个事件源,即创建一个 API Gateway 的 API,它有几个 API 相关的属性,比如路径、请求方式。

ListTable 这个资源Type是 AWS::Serverless::SimpleTable ,现在实际上是创建一个DynamoDB 表格。这里没有额外属性,就是以默认的容量规模创建,DynamoDB表容量默认值是每秒5次读写。

SAM 模板功能特性

可以和其它非SAM CloudFormation资源混用在同一个模板里 。SAM模板只增加了3种新资源,Lambda函数、API 和 SimpleTable,我们还可以使用其它标准CloudFormation资源,比如 S3 桶, Kinesis流,Step Function等等。

其它CloudFormation的标准功能SAM模板都支持,比如使用参数、映射和输出等,允许我们在CloudFormation执行时动态传入参数等, CloudFormation的内置函数我们在SAM也都可以使用,如连接字符串、拆分字符串等等。ImportValue也可使用,允许我们从现有架构中直接调取参数值,可以不再使用参数、映射等方式。总之这些标准功能使SAM模板可以和CloudFormation模板一样享受动态化的便利。

SAM 基于 CloudFormation,所以也是支持YAML 和JSON两种格式。

SAM 模板特有资源类型

SAM 模板新增3个特有资源类型,前面的简单例子已经展示了 ,即:AWS::Serverless::Function,AWS::Serverless::Api,AWS::Serverless::SimpleTable。这是当前Transform版本为 AWS::Serverless-2016-10-31所支持的特有资源类型。将来还有可能增加更多资源类型,到时请注意升级换用相应的Transform版本号。

第1个特有资源AWS::Serverless::Function 就是声明Lambda函数,模板中的包括Lambda函数所有的属性,如Handler、运行时、代码地址、描述等等。Events用来声明事件源,同一函数可以支持多个事件源。 Policies 声明IAM策略。Environment 可以声明环境变量,可用于传递给 Lambda函数。另外还有 Tags声明标签,这是 AWS 管理资源的通用功能,比如用于资源分组,账单和成本分解等。

第2个特有资源是 AWS::Serverless::Api,用于声明 API Gateway,关于API的详细定义,在 DefinitionUri 指定的swagger.yml里。其余的属性不多,主要是:StageName 阶段名称、CacheClusterEnabled 是否启用API Gateway的缓存,以及 CacheClusterSize缓存的容量。最后的Variables是传递给API 的参数,比如阶段参数,也是用来灵活部署的。

第3个特有资源是AWS::Serverless::SimpleTable,用于创建 DynamoDb 表。我们需要做的就是声明一下主键、类型,以及配置的容量规模。

AWS::Serverless::Function 事件源
在SAM模板中AWS::Serverless::Function资源下 Events 节点声明事件源。我们知道AWS Lambda 是事件驱动的无服务器函数服务,所以事件源也是部署Lambda函数的重要属性。事件源可以有很多种,大体分为3类:

  • 数据状态变化,如S3对象的新增、删除。
  • 请求端点,这里主要指的是通过 API  Gateway 暴露为对外服务的 HTTP API 接口。
  • 资源状态变化,如EC2实例的启动、停止等状态。

具体产生的事件源来自这些服务:S3、SNS、Kinesis、DynamoDB、Schedule、CloudWatchEvent、AlexaSkill。各事件源的各种事件及属性全部支持。具体这里不再赘述,大家可以参考各服务的事件部分相关文档。

Lambda环境变量

Lambda环境变量是可以动态传递给我们的函数的键值对,比如IAM的验证凭据,API的密钥等等。Lambda环境变量是Lambda服务本身的功能,在无服务器应用模型SAM里,我们可以方便地把环境变量管理起来。在SAM模板中以 Parameters 节点来声明环境变量。可以通过标准环境变量API使用,如 Node.js 的process.env 或 Python的os.environ,即Lambda的环境变量会添加到Node.js 的process.env 里,方便咱们开发时使用。下面我们看一个环境变量的具体例子。

使用SAM模板管理Lambda环境变量

请先从以下git库下载源码。

https://github.com/xfsnow/serverless/tree/master/sam/parameters

我们打开 parameters.yaml,看下面这个片段。

Parameters:

  MyEnvironment:

    Type: String

    Default: testing

    AllowedValues:

      - testing

      - staging

      - prod

    Description: Environment of this stack of resources

这里我们声明了一个Lambda环境变量,变量名是MyEnvironment。它的属性都可以顾名思义,类型是字符串,默认值是testing,可取值是testing、staging和 prod。最后还有一个描述。我们建议给各种变量和资源添加描述,以清楚说明它们具体的使用情况。

ApiHelloFunction:

    Type: AWS::Serverless::Function

    Properties:

      Handler: index.handler

      Runtime: nodejs6.10

      Environment:

        Variables:

          S3_BUCKET: !Ref MyEnvironment

然后在声明Lambda函数时在 Variables: 段声明一个环境变量S3_BUCKET,它的值使用CloudFormatioin内置函数!Ref读取SAM模板中的环境变量MyEnvironment。

var bucketName = process.env.S3_BUCKET;

相应地,在我们的Lambda函数代码中,index.js 中上述这段就可以通过全局变量process.env 获取到S3_BUCKET这个环境变量值了。

用CloudFormation部署SAM模板

我们还使用上述Lambda环境变量这个例子,具体介绍一下CloudFormation部署的方法。

以下操作流程使用 AWS CLI 命令执行。准备环境及了解 AWS CLI 基本功能请参见 https://aws.amazon.com/cn/cli/

请先从以下git库下载源码。

https://github.com/xfsnow/serverless/tree/master/sam/parameters

把下面命令中的 <bucket-name> 等变量值替换成你的具体的值。

在当前目录下执行以下命令,把文件上传到S3并打包成可用于 CloudFormation 的模板文件。

aws cloudformation package \

    --template-file parameters.yaml \

    --s3-bucket <bucket-name> \

    --output-template-file packaged_parameters.yaml

确认已经生成 packaged_parameters.yaml 文件。

执行以下命令。–parameter-overrides MyEnvironment=prod 表示部署时为 CloudFormation 的模板参数指定值为 prod。

aws cloudformation deploy \

   --template-file output_parameters.yaml \

   --stack-name parameters \

   --capabilities CAPABILITY_IAM \

   --parameter-overrides MyEnvironment=prod

顺利地话,会看到逐渐输出的返回结果。

Waiting for changeset to be created..

Waiting for stack create/update to complete

Successfully created/updated stack - lambdaProxy

这时到 CloudFormation 的控制台已经创建出一个 lambdaProxy,整个过程大约持续 1 到 2 分钟。 然后到 API Gateway 控制台,可以看到创建出的 lambdaProxy 的 API,点击其 Stages 下的 Prod 链接,可以看到形如下面的调用 URL: Invoke URL: https://xxxxxxxxx.execute-api.my-region.amazonaws.com/Prod

点击它,打开一个新窗口,显示

{“bucketName”:”prod”}

表示已经部署成功。

再执行一次 aws cloudformation deploy,把 MyEnvironment 参数变成 testing

aws cloudformation deploy \

   --template-file output_parameters.yaml \

   --stack-name parameters \

   --capabilities CAPABILITY_IAM \

   --parameter-overrides MyEnvironment=testing

等待执行完毕后,刷新刚才的调用 URL,可以看到内容已经更新成了

{“bucketName”:”testing”}

这个例子演示了我们在SAM模板中定义的环境变量在具体部署时可以灵活赋成不同的值,然后部署出相应的效果。

小结

今天我们介绍了AWS 无服务器应用模型和SAM模板的基本功能和特性,并带领大家用一个实例体验了通过CloudFormation部署SAM模板。随着无服务器应用开发逐渐复杂,规模越来越大,涉及的服务和资源也会越来越多,SAM确实为我们提供了一种使用AWS服务进行统一管理的方法,希望大家多多体验。

下一篇中,我们将进一步为大家讲解使用AWS CodeBuild 构建 Lambda函数以及使用AWS CodePipeline实现自动化持续集成。

 

作者介绍:

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

新工具 – 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

利用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之前,他在思科中国担任系统工程师,负责方案咨询和架构设计,在企业私有云和基础网络方面有丰富经验。

无服务器应用程序:乔治亚州立大学的云计算之旅

近年来,众多高等院校开始越来越多地立足远程教育开展各类创新举措。乔治亚州立大学所推出的虚拟锻炼课程正是解决这一挑战的典型实例之一。该在线课程的目标在于帮助学生们在锻炼过程当中了解如何管理其心率活动,从而获得最理想的运动效果。

最初,学生们需要以手动方式从其健身追踪器当中导出数据,而后将其发送给教师。很明显,这种繁琐的作法远称不上理想。乔治亚州立大学在线学习办公室主任 、首席教学设计师James Castle总结称,“从学生的角度出发,这样的过程可能令人困惑——因为其在进行数据下载时面对着多种报告与文件类型。而任何报告错误或者格式错误都可能导致数据无法正常使用。对于一部分学生来说,数据管理已经成为其学习过程中的巨大障碍。”

为了减轻学生们的负担,James与多位来自计算机科学专业的学生们共同开发出一款替代性解决方案。该团队着目光投向了Amazon Web Services(简称AWS),希望通过一种低成本的方式实现应用程序运行以及无缝化数据收集。如此一来,他们将得以显著简化学生与教练们的数据收集与分析方式。

乔治亚州立大学计算机科学专业大三学生Chuma Atunzu解释称,“为了实现这一目标,我需要查阅大量关于AWS的说明文档。我观看了很多讲解视频,并发现这非常有趣。凭借着这些技术相关经验,我能够利用多项AWS服务构建起一款现代化、无服务器型应用程序。”

在AWS的帮助下,他们设计出的无服务器应用程序分别运用到AWS Lambda、Amazon DynamoDB、Amazon API Gateway、Amazon简单存储服务(简称Amazon S3)、Amazon简单邮件服务(简称Amazon SES)以及Desire2Learn(简称D2L)与Fitbit等。在夏季新学期开始之前,他们进行了为期一个月的应用程序测试,而最终月度计费账单仅为0.01美元。

现在,学生们已经能够在学期初始以一键式操作访问该应用,而后即可享受更为便利的数据管理服务。而教授们则可在获得许可后面向各个模块发出数据请求,并对课程进度及其它情况进行必要分析。

这项在线健身课程如今与Fitbit以及新的无服务器应用程序一同对乔治亚州立大学内身处世界各地的全部学生的心率数据进行监控——无论其身在瑞士、韩国、乞力马扎罗山顶抑或是坦桑尼亚。James解释称:“到目前为止,项目进展似乎一切顺利。我们的学生几乎能够立足世界上的任何地区获取其必要的体征数据信息。”

目前这项课程建立起两类工作负载(而每月成本仅需要1美分!)——其一面向学生,其二则面向教师。

图一:学生工作流

图二:教师工作流

感兴趣的朋友亦可点击此处了解更多与AWS Cloud在高等教育领域的相关应用信息。

 

深入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之前曾长期从事互联网应用开发,先后在新浪、唯品会等公司担任架构师、技术总监等职位。对跨平台多终端的互联网应用架构和方案有深入的研究。

带您玩转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和自动化运维等方面有着丰富的实践经验。目前在集中精力学习新一代无服务器架构的开发与设计。

 

从IaaS到FaaS—— Serverless架构的前世今生

今天大多数公司在开发应用程序并将其部署在服务器上的时候,无论是选择公有云还是私有的数据中心,都需要提前了解究竟需要多少台服务器、多大容量的存储和数据库的功能等。并需要部署运行应用程序和依赖的软件到基础设施之上。假设我们不想在这些细节上花费精力,是否有一种简单的架构模型能够满足我们这种想法?这个答案已经存在,这就是今天软件架构世界中新鲜但是很热门的一个话题——Serverless(无服务器)架构。

什么是Serverless

如同许多新的概念一样,Serverless目前还没有一个普遍公认的权威的定义。最新的一个定义是这样描述的:“无服务器架构是基于互联网的系统,其中应用开发不使用常规的服务进程。相反,它们仅依赖于第三方服务(例如AWS Lambda服务),客户端逻辑和服务托管远程过程调用的组合。”

最开始,“无服务器”架构试图帮助开发者摆脱运行后端应用程序所需的服务器设备的设置和管理工作。这项技术的目标并不是为了实现真正意义上的“无服务器”,而是指由第三方云计算供应商负责后端基础结构的维护,以服务的方式为开发者提供所需功能,例如数据库、消息,以及身份验证等。简单地说,这个架构的就是要让开发人员关注代码的运行而不需要管理任何的基础设施。程序代码被部署在诸如AWS Lambda这样的平台之上,通过事件驱动的方法去触发对函数的调用。很明显,这是一种完全针对程序员的架构技术。其技术特点包括了事件驱动的调用方式,以及有一定限制的程序运行方式,例如AWS Lambda的函数的运行时间默认为3秒到5分钟。从这种架构技术出现的两年多时间来看,这个技术已经有了非常广泛的应用,例如移动应用的后端和物联网应用等。简而言之,无服务器架构的出现不是为了取代传统的应用。然而,从具有高度灵活性的使用模式及事件驱动的特点出发,开发人员/架构师应该重视这个新的计算范例,它可以帮助我们达到减少部署、提高扩展性并减少代码后面的基础设施的维护负担。

Serverless的历史

Serverless这个概念并不容易理解。乍见之下,很容易让人混淆硬件服务器及软件上的服务与其所谓的“服务器”差别。在这里强调的所谓“无服务器”指的是我们的代码不会明确地部署在某些特定的软件或者硬件的服务器上。运行代码托管的环境是由例如AWS这样的云计算厂商所提供的。

Serverless这个词第一次被使用大约是2012年由Ken Form所写的一篇名为《Why The Future of Software and Apps is Serverless》的文章。这篇文章谈到的内容是关于持续集成及源代码控制等内容,并不是我们今天所特指的这一种架构模式。但Amazon在2014年发布的AWS Lambda让“Serverless”这一范式提高到一个全新的层面,为云中运行的应用程序提供了一种全新的系统体系结构。至此再也不需要在服务器上持续运行进程以等待HTTP请求或API调用,而是可以通过某种事件机制触发代码的执行,通常这只需要在AWS的某台服务器上配置一个简单的功能。此后Ant Stanley 在2015年7月的名为《Server are Dead…》的文章中更是围绕着AWS Lambda及刚刚发布的AWS API Gateway这两个服务解释了他心目中的Serverless,“Server are dead…they just don’t know it yet”。到了2015年10月份,在那一年的AWS re:Invent大会上,Serverless的这个概念更是反复出现在了很多场合。印象中就包括了“(ARC308)The Serverless Company Using AWS Lambda”及“(DVO209)JAWS: The Monstrously Scalable Serverless Framework”这些演讲当中。随着这个概念的进一步发酵,2016年10月在伦敦举办了第一届的Serverlessvconf。在两天时间里面,来自全世界40多位演讲嘉宾为开发者分享了关于这个领域进展。

在Serverless的世界里面,AWS扮演了一个非常重要的角色。但是AWS并不是唯一的Serverless架构服务的供应商。其他厂商,例如Google Cloud Functions、Microsoft Azure Functions、IBM OpenWhisk、Iron.io和Webtask等各种开源平台都提供了类似的服务。

Serverless与FaaS

微服务(MicroService)是软件架构领域业另一个热门的话题。如果说微服务是以专注于单一责任与功能的小型功能块为基础,利用模组化的方式组合出复杂的大型应用程序,那么我们还可以进一步认为Serverless架构可以提供一种更加“代码碎片化”的软件架构范式,我们称之为Function as a Services(FaaS)。而所谓的“函数”(Function)提供的是相比微服务更加细小的程序单元。例如,可以通过微服务代表为某个客户执行所有CRUD操作所需的代码,而FaaS中的“函数”可以代表客户所要执行的每个操作:创建、读取、更新,以及删除。当触发“创建账户”事件后,将通过AWS Lambda函数的方式执行相应的“函数”。从这一层意思来说,我们可以简单地将Serverless架构与FaaS概念等同起来。

FaaS与PaaS的比较

乍看起来,FaaS与PaaS的概念在某些方面有许多相似的地方。人们甚至认为FaaS就是另一种形式的PaaS。但是Intent Media的工程副总裁Mike Roberts有自己的不同看法:“大部分PaaS应用无法针对每个请求启动和停止整个应用程序,而FaaS平台生来就是为了实现这样的目的。”

FaaS和PaaS在运维方面最大的差异在于缩放能力。对于大部分PaaS平台,用户依然需要考虑缩放。但是对于FaaS应用,这种问题完全是透明的。就算将PaaS应用设置为自动缩放,依然无法在具体请求的层面上进行缩放,而FaaS应用在成本方面效益就高多了。AWS云架构战略副总裁Adrian Cockcroft曾经针对两者的界定给出了一个简单的方法:“如果你的PaaS能够有效地在20毫秒内启动实例并运行半秒,那么就可以称之为Serverless”。

Serverless架构的优点

  • 降低运营成本:

Serverless是非常简单的外包解决方案。它可以让您委托服务提供商管理服务器、数据库和应用程序甚至逻辑,否则您就不得不自己来维护。由于这个服务使用者的数量会非常庞大,于是就会产生规模经济效应。在降低成本上包含了两个方面,即基础设施的成本和人员(运营/开发)的成本。

  • 降低开发成本:

IaaS和PaaS存在的前提是,服务器和操作系统管理可以商品化。Serverless作为另一种服务的结果是整个应用程序组件被商品化。

  • 扩展能力:

Serverless架构一个显而易见的优点即“横向扩展是完全自动的、有弹性的、且由服务提供者所管理”。从基本的基础设施方面受益最大的好处是,您只需支付您所需要的计算能力。

  • 更简单的管理:

Serverless架构明显比其他架构更简单。更少的组件,就意味着您的管理开销会更少。

  • “绿色”的计算:

按照《福布斯》杂志的统计,在商业和企业数据中心的典型服务器仅提供5%~15%的平均最大处理能力的输出。这无疑是一种资源的巨大浪费。随着Serverless架构的出现,让服务提供商提供我们的计算能力最大限度满足实时需求。这将使我们更有效地利用计算资源。

Serverless的架构范式

移动应用后台Serverless参考架构

实时文件处理Serverless参考架构

Web应用Serverless参考架构

物联网应用后台参考架构

实时流处理Serverless参考架构

美丽新世界

技术上不可能有应用程序可以不依赖于服务器,必须要有某种硬件来支持应用程序。但是以AWS Lambda为代表的Serverless架构可以使得开发人员专注于程序功能本身,而让AWS处理与服务器部署、存储和数据库相关的所有复杂性工作。这听起来很简单,但是实现起来却并不简单。这种新的架构打破了人们的习惯思维,它让服务器不可见,并提供了一个极具成本效益的服务。Serverless架构仅有两年的历史,仍处于起步阶段。未来,这个领域还会有更大的进步,这将是非常有趣的。它给所有开发人员带来的是软件架构和应用程序部署的美丽新世界。

作者介绍:

费良宏

费良宏,AWS首席云计算技术顾问,拥有超过20年在IT行业以及软件开发领域的工作经验。在此之前他曾经任职于Microsoft、Apple等知名企业,任职架构师、技术顾问等职务,参与过多个大型软件项目的设计、开发与项目管理。目前专注于云计算以及互联网等技术领域,致力于帮助中国的开发者构建基于云计算的新一代的互联网应用。

如何在1个小时之内轻松构建一个Serverless 实时数据分析平台

数据分析平台,特别是实时数据分析,正在被越来越广泛的应用于各个行业。 举例来说,游戏公司在发布新游戏之后,需要实时定位用户的留存、增长等情况;快销公司需要精确地记录每一笔订单的情详情,并结合社交媒体,实时分析促销活动引起的用户购买行为与销量等等。基于这些需求, AWS提供了一整套成熟的解决方案与服务,并且得到了广泛的应用。

图1 AWS大数据参考架构示例

上图中,Amazon Kinesis 是实时的流式分析服务,而Amazon S3是AWS的海量数据存储服务。利用Kinesis与S3,我们可以十分方便的构建一个实时流式信息数据的采集与存储。 值得注意的是,作为Serverless计算服务的代表 , 用户只需要编写实现对应的ETL逻辑,Amazon Lambda就可以非常方便地对Kinesis流式数据进行抽取与分析而不需要部署任何服务器。另外,用户也可以使用Kinesis Firehose(Kinsis服务之一)实现原始数据的直接注入与收集。

随着Amazon Athena在AWS re:Invent 2016的重磅发布,AWS的大数据平台又增添了重要的一员!Amazon Athena 是一种交互式查询服务,用户可以使用标准SQL 分析 Amazon S3 中的数据。因为Athena底层是基于Serverless(无服务器)架构,用户不需要运维底层的服务器,并且查询处理能力会随着用户的数据将进行自适应与扩展,实现秒级别的数据查询与处理。

闲话少说,我们将利用AWS提供的三个重要服务——Amazon Kinesis Firehose,、Lambda和Athena在1个小时之内实现一套实时分析的Serverless数据分析平台!

准备好了吗?Let’s rock

1.数据源。作为测试,我们将对AWS VPC Flow Logs进行分析。您可以使用Kinesis Agent/Flume/Fluentd或者Amazon Kinesis SDK对前端的实时日志进行分析。Amazon VPC Flow Logs将实时记录VPC监控的网络端口的流量与通信日志,并将日志发布于AWS CloudWatch Logs。详细的配置请参见 https://aws.amazon.com/cn/blogs/aws/vpc-flow-logs-log-and-view-network-traffic-flows/

2.数据ETL。VPC Flow Logs进入CloudWatch Logs之后,可以利用Lambda对实时日志进行订阅处理。订阅之后,Lambda会在CloudWatch Logs更新之后,自动调用执行,进行数据ETL。

首先,在控制台创建一个Lambda函数(利用Python实现).为了确保Lambda有对应的执行权限,需要赋予Lambda函数相应的Permission Role.在这个示例中,我们只需要服务Lambda对应的CloudWatch Logs以及Kinesis Firehose的权限即可。

其次,Lambda 代码会对进入的CloudWatch日志的第一个Base64编码的转码并进行gzip解压(因为Cloudwatch Logs会对送往Lambda首先进行Base64编码并进行gzip压缩)。之后,Lambda会对具体的日志进行汇聚,以batch的方式发送给Kinesis Firehose。具体的代码如下:

代码中,利用环境变量 DELIVER_STREAM_NAME 传递Kinesis Firehose Stream,详见步骤3)。

最后,利用AWS CloudWatch logs的订阅功能,就可以实时地把日志发布到Lambda函数中了。

aws logs put-subscription-filter \

    --log-group-name myLogGroup \

    --filter-name demo \

    --filter-pattern "" \

    --destination-arn arn:aws:lambda:us-east-1:123456789123:function:helloworld\

具体的配置过程可以参考 http://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/logs/Subscriptions.html

3.创建Kinesis Fireshose实现到S3的数据自动存储与汇聚。Kinesis Firehose提供了自动对数据进行汇聚,目前支持S3和Redshift, ElastiSearh。这里,我们利用控制台,十分简单地创建了如下一个Firehose Stream:

图2 Kinesis Firehose 配置过程

4.利用Amazon Athena进行数据查询。因为Athena底层是基于Hive Catalog对S3数据进行管理,上层基于Presto的方式进行SQL查询。因此我们首先需要使用Hive对S3的VPC Flow Logs进行外表DDL操作。具体代码如下:

我们在创建表的过程中,创建了 Year,Month, Day 与Hour的分区,是因为我们在实现Firehose的时候自动进行了时间和日期的前缀设置。同时,利用分区也可以大大提高hive的数据查询性能。

到这里,整个Serverless 处理能力自适应的架构已经构建完成,来测试一下Athena的查询结果吧。 Athena提供了Web Console让BI用户可以直接对S3数据湖进行查询,同时,用户也可以利用JDBC直接与第三方的BI工具集成实现自动化查询。查询结果也可以利用CSV的文件下载的方式直接分享给其他用户。

图3 利用Web Console对Athena进行数据分析

作者介绍:

肖凌

AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内和全球的应用和推广,在大规模并发后台架构、跨境电商应用、社交媒体分享 、Hadoop大数据架构以及数据仓库等方面有着广泛的设计和实践经验。在加入AWS之前曾长期从事移动端嵌入式系统开发,IBM服务器开发工程师。并负责IBM亚太地区企业级高端存储产品支持团队,对基于企业存储应用的高可用存储架构和方案有深入的研究。