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