亚马逊AWS官方博客

AWS 无服务器应用程序模型 (SAM) 命令行界面介绍

几十年前,我用 6502 汇编语言写了一页又一页的代码。汇编和链接代码后,我将它加载到内存中,在战略位置设置断点,并分步调试以确保一切都符合预期。现在,我再也没有机会编写或调试任何非平凡代码,因此在撰写此博文时我有些担心(说真的,我已经犹豫不决了好几星期)。

SAM CLI

我将给大家介绍以下新的无服务器应用程序模型 (SAM) 命令行界面,提高对我自己使用 AWS Lambda 进行构建的能力的信心! 在开始之前让我们先回顾一些术语:
AWS SAM ,是Serverless Application Model 的缩写,指无服务器应用程序模型,它是一种可以用来在 AWS 上构建无服务器应用程序的开放源框架。它提供了一种简略语法,以便您使用简单的 YAML 模板来描述应用程序(Lambda 函数、API 终端节点、DynamoDB 表和其他资源)。在部署期间,SAM 将对简略 SAM 语法进行转换并扩展为 AWS CloudFormation 模板。然后,CloudFormation 将会以可靠、可重复的方式预置资源。

AWS SAM CLI 以前叫做 SAM Local,是一种支持构建基于 SAM 的应用程序的命令行界面。它支持本地开发和测试,同时也是一个活跃的开放源项目。CLI 允许您选择 Python、Node、Java、Go、.NET,包含一系列好用的模板以帮助您入门。

借助 SAM CLI 中的 sam local 命令,可以支持对 Lambda 函数和基于 SAM 的无服务器应用程序的本地调用和测试,同时可以在类似于 Lambda 的执行环境中本地运行函数代码。您还可以使用 sam local 命令在本地生成示例负载,启动本地终端节点以测试您的 API,或者实现 Lambda 函数的自动化测试。

安装与设置
我需要首先安装一些文件包才能演示如何使用 SAM CLI。由于 sam local 命令提供的函数使用 Docker,因此我需要在非虚拟化的环境中实施更改! 设置流程概括如下:

Docker — 我会安装社区版的 Docker for Windows(下载包 512 MB),然后运行 docker ps 命令来验证它是否正常运行:

Python — 我将安装 Python 3.6 并确保它位于我的 Windows 路径上:

Visual Studio Code — 我会安装 VS Code 以及随带的 Python 扩展

AWS CLI — 我将安装 AWS CLI:

然后配置我的凭证:

SAM — 我将使用 pip 命令来安装 AWS SAM CLI:

现在我已经安装了所有的移动组件,可以开始探索 SAM。

使用 SAM CLI

我为我的项目创建了一个目录 (sam_apps),然后运行 sam init 命令以创建我的第一个项目:

这将创建一个子目录 (sam-app),其中包含所有必要的源文件和配置文件:

我将在 hello_world 内部创建一个 build 目录,然后安装 requirements 中定义的文件包。build 包含了 SAM Local 加载的源代码和 Python 文件包:

然后是最后一步! 我需要将源文件复制到 build 目录以进行部署:

我的应用程序(app.py 和空的 __init__.py)已经可以部署,因此我启动了一个本地终端节点:

这时,终端节点将侦听端口 3000 的 HTTP 连接,同时连接成功时将会启动一个 Docker 容器。build 目录将对容器开放,从而可以加载 Python 文件包并运行 app.py 中的代码。

当我在浏览器中打开 http://127.0.0.1:3000/hello 时,必要时将会下载容器映像,运行代码并在我的浏览器中显示输出:

另一侧发生的情况如下。您可以在此开到所有重要的步骤,包括代码的调用、映像的下载、在容器中挂在 build 目录以及请求的日志记录:

我可以修改代码,刷新浏览器选项卡,这时将会运行新的版本:

编辑/部署/测试循环令人难以置信地快速,您的生产效率也将得到前所未有的提升!

这里需要特别注意一点。最初的 app.py 文件是在 hello_world 目录中生成的,并且我在几个步骤之前将它复制到了 build 目录。我可以每次都执行这一部署步骤,也可以直接将 build 目录中的代码视为真实代码并直接进行编辑。当我开始构建并设置代码的版本后,这将会影响我的源代码控制计划。

会发生什么

现在示例代码正在运行,然后我们来看 SAM 模板(假设叫做 template.yaml)。为节约空间,我直接跳至 Resources 部分:

Resources:

    HelloWorldFunction:
        Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
        Properties:
            CodeUri: hello_world/build/
            Handler: app.lambda_handler
            Runtime: python3.6
            Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
                Variables:
                    PARAM1: VALUE
            Events:
                HelloWorld:
                    Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
                    Properties:
                        Path: /hello
                        Method: get

这一部分定义了 HelloWorldFunction,规定了它的位置 (hello_world/build/)、运行方式 (python3.6),并且允许定义和设置环境变量。此外它还说明函数可以处理由规定路径 (/hello) 上的 GET 操作生成的 HelloWorld 事件。

此模板不会自动重新加载;如果我对它进行了更改,我将需要重新启动 SAM Local。我建议您用一些时间来修改此处的名称和路径,观察出现的错误。这可帮助您充分了解背后发生的情况,并帮助您在以后提高生产效率。

模板的剩余部分描述了模板的输出(API Gateway 终端节点、函数的 ARN 以及函数的 IAM 角色)。这些值不会影响本地执行,但对云部署的成功不可或缺。

Outputs:

    HelloWorldApi:
      Description: "API Gateway endpoint URL for Prod stage for Hello World function"
      Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"

    HelloWorldFunction:
      Description: "Hello World Lambda Function ARN"
      Value: !GetAtt HelloWorldFunction.Arn

    HelloWorldFunctionIamRole:
      Description: "Implicit IAM Role created for Hello World function"
      Value: !GetAtt HelloWorldFunctionRole.Arn

在您充分理解背后发生的情况之前,您可以原样保留所有这些值。

使用 SAM CLI 和 VS Code 进行调试

好,现在我们进行设置以完成一些交互式的调试! 我花了好些时间才搞定这一步,希望您可以通过我的经验受益。第一步是安装 ptvsd 文件包:

然后我会编辑 requirements.txt 文件,以规定我的应用程序需要使用 ptvsd(我复制了上述文件包名称中的版本号):

requests==2.18.4
ptvsd==4.1.4

然后我重新运行 pip 命令以在我的 uild 目录中安装此新的需求:

现在,我需要修改代码以便可以进行调试。我将此代码添加到现有的导入后:

import ptvsd
ptvsd.enable_attach(address=('0.0.0.0', 5858), redirect_output=True)
ptvsd.wait_for_attach()

第一句告诉应用程序,调试程序将在端口 5858 进行挂载;第二句会在调试程序完成挂载前暂停代码(您可以将此设置为条件)。

然后,我会启动 VS Code 并选择我的应用程序的根文件夹:

现在我需要配置 VS Code 以进行调试。我会选择调试图标,单击 DEBUG 旁的白色三角形,然后选择 Add Configuration

我会选择 Python 配置,用下列文本替换文件 (launch.json) 的全部内容,然后保存文件 (File:Save)。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [

        {
            "name": "Debug with SAM CLI (Remote Debug)",
            "type": "python",
            "request": "attach",
            "port": 5858,
            "host":  "localhost",
            "pathMappings": [
                {
                "localRoot": "${workspaceFolder}/hello_world/build",
                "remoteRoot" : "/var/task"
                }
            ]
        }
    ]
}

现在我将从 DEBUG 菜单中选择此调试配置:

还跟得上吗? 大功即将告成!

我再次启动 SAM Local,告诉它侦听调试端口:

我返回 VS Code 并设置代码中的断点(类似于以前的 F9):

需要记住一点 — 务必要在 build 目录中打开 app.py 并在那里设置断点。

现在我将返回浏览器,再次访问本地地址 (http://127.0.0.1:3000/hello)。这时容器将会启动以处理请求并运行 app.py。代码将持续运行,直到它触及 wait_for_attach 调用,现在我将在 VS Code 中按下 F5 以开始调试。

触及断点后,我将一步跳至 requests.get 调用并检查 ip 变量:

然后我按下 F5 继续,Web 请求将会完成。正如您可以看出,我可以发挥 VS Code 调试程序的强大功能来构建和调试 Lambda 函数。我所介绍的不过是九牛一毛,欢迎您继续探索,弥补我的不足之处。如需了解更多信心,请参阅使用 SAM CLI 在本地调试无服务器应用程序

云部署

SAM CLI 还可帮助我封装完成后的代码,将它上传到 S3 并进行运行。我首先会启动一个 S3 存储桶 (jbarr-sam) 并运行 sam package 命令。这将创建一个部署文件包并将它上传至 S3:

这将需要数秒的时间。然后我会运行 sam deploy 命令以创建 CloudFormation 堆栈:

如果堆栈已经存在,SAM CLI 将会创建一个更改集并使用它来更新堆栈。我的堆栈将在一两分钟内准备就绪,包含 Lambda 函数、一个 API Gateway 以及所有的支持资源:

我可以在堆栈输出中找到 API Gateway 终端节点的位置:

然后使用浏览器访问它,就好像代码在本地运行一样:

我还可以使用 sam logs 命令来访问我的堆栈的 CloudWatch 日志:

我的 SAM 应用程序现在可以在 Lambda 控制台中看到(这是一个相对较新的功能):

我可以总览模板以及应用程序的资源:

我还可以查看资源之间的关系:

此外还有一个监控控制面板:

我可以将 Amazon CloudWatch 控制面板添加到我的模板,从而自定义控制面板(更多信息请参阅在 AWS Lambda 控制台中管理应用程序)。

不止如此

不论您是否相信,我只不过是浅尝辄止地介绍了 SAM、SAM CLI 以及 sam local 命令的强大功能。对于下面的这些功能您也应有所了解:

本地函数调用 — 我可以直接调用 Lambda 函数:

示例事件源生成 — 如果我要编写 Lambda 函数以响应来自其他 AWS 产品的触发器(例如 S3 PUT 等等),我可以生成示例事件并使用它们来调用函数:

在真实世界里,我会将输出重定向至某个文件,必要时进行一些额外的自定义,然后用该文件来调用函数。

Cookiecutter 模板 — SAM CLI 可以使用Cookiecutter 模板来创建项目,我们已经创建了多个示例以便您开始使用。如需了解更多信息,请参阅 Cookiecutter AWS Sam S3 Rekognition Dynamodb Python 以及适用于 AWS SAM 和 .NET 的 Cookiecutter。

CloudFormation 扩展 — AWS SAM 对 CloudFormation 进行了扩展,让您可以受益于基础设施即代码的强大功能。您将获得可靠且可重复利用的部署,并且可以发挥全部 CloudFormation 资源类型内置函数和其他模板功能的强大能力。

内置最佳实践 — 除基础设施即代码模式所提供的优势外,您还可以轻松受益于许多其他最佳实践,例如代码审核、通过 AWS CodePipeline 进行安全部署以及使用 AWS X-Ray 进行跟踪等。

与开发工具深度集成 — 您可以将 AWS SAM 与一系列的 AWS 工具结合使用,以构建无服务器应用程序。您可以发现 AWS Serverless Application Repository 中的新应用程序。对于基于 SAM 的无服务器应用程序的授权、测试和调试,您可以使用 AWS Cloud9 IDE。如要为您的无服务器应用程序构建部署管道,您可以使用 AWS CodeBuildAWS CodeDeployAWS CodePipeline。您还可以使用 AWS CodeStar 来开始使用项目结构、代码存储库以及自动为您配置的 CI/CD 管道。如要部署您的无服务器应用程序,您可以使用 AWS SAM Jenkins 插件,此外您还可以使用 Stackery.io 工具包来构建生产就绪型应用程序。

先睹为快

但愿上述介绍让您满意,并希望您可以在您的下一个无服务器项目中充分利用 SAM!

 

本篇作者

Jeff Barr

AWS 首席布道师; 2004年开始发布博客,此后便笔耕不辍。