典型的基于 Lambda 的应用由事件触发的多个函数组成,例如 S3 bucket 中的新对象、传入的 HTTP 请求或新的 SQS 消息。这些函数可以独立运行,也可以利用其他资源,例如 DynamoDB 表、amazons3 存储桶和其他 Lambda 函数。到目前为止,我们已经了解了如何从 AWS 管理控制台或使用 AWS CLI 创建这些资源。在真实场景中,您希望花费更少的时间来调配所需的资源,并将更多精力放在应用逻辑上。最后,这就是无服务器方法。
最后一章将介绍基础架构作为代码的概念,以帮助您以自动化的方式设计和部署 N 层无服务器应用,从而避免人为错误和可重复的任务。
本书假设您基本熟悉 AWS 无服务器应用模型。如果您对 SAM 本身不熟悉,请参考第 1 章、无服务器到第 10 章、测试您的无服务器应用。您将获得一份关于如何开始 SAM 的分步指南。本章的代码包位于 GitHub 上的https://github.com/PacktPublishing/Hands-On-serverless-Applications-with-Go 。
Terraform是 HashiCorp 构建的开源自动化工具。它用于通过声明性配置文件创建、管理和更新基础结构资源。它支持以下提供程序:
- 云提供商:AWS、Azure、Oracle 云、GCP
- 基础设施软件:
- 领事:是一个分布式、高可用的服务发现和配置系统。
- Docker:这是一种工具,旨在通过使用容器更轻松地创建、部署和运行应用。
- Nomad:是一款易于使用的企业级集群调度器。
- 金库:是一种提供安全可靠的方式存储和分发机密的工具。
- 其他SaaS和PaaS
Terraform 不是配置管理工具(如 Ansible、Chef 和 Puppet&Salt)。创建它是为了生成和销毁基础设施,而配置管理工具用于在现有基础设施之上安装东西。然而,Terraform 可以做一些资源调配(https://www.terraform.io/docs/provisioners/index.html )。
本指南将向您展示如何使用 Terraform 部署 AWS Lambda,因此您需要安装 Terraform。您可以找到适合您系统的软件包并下载它(https://www.terraform.io/downloads.html )。下载后,确保PATH
变量上有terraform
二进制文件。配置您的凭据,以便 Terraform 能够代表您行事。以下是提供身份验证凭据的四种方法:
- 直接通过供应商提供 AWS
access_key
和secret_key
。 - AWS 环境变量。
- 共享凭据文件。
- EC2 IAM 角色
如果您遵循第 2 章、开始使用 AWS Lambda,您应该已经安装并配置了 AWS CLI。因此,您无需采取任何行动。
要开始创建 Lambda 函数,请执行给定的步骤:
- 创建具有以下结构的新项目:
- 我们将使用最简单的 Hello world 示例。
function
文件夹包含一个基于 Go 的 Lambda 函数,该函数显示一条简单消息:
package main
import "github.com/aws/aws-lambda-go/lambda"
func handler() (string, error) {
return "First Lambda function with Terraform", nil
}
func main() {
lambda.Start(handler)
}
- 您可以使用以下命令构建基于 Linux 的二进制文件并生成
deployment
包:
GOOS=linux go build -o main main.go
zip deployment.zip main
- 现在函数代码已经定义,让我们使用 Terraform 创建第一个 Lambda 函数。将以下内容复制到
main.tf
文件中:
provider "aws" {
region = "us-east-1"
}
resource "aws_iam_role" "role" {
name = "PushCloudWatchLogsRole"
assume_role_policy = "${file("assume-role-policy.json")}"
}
resource "aws_iam_policy" "policy" {
name = "PushCloudWatchLogsPolicy"
policy = "${file("policy.json")}"
}
resource "aws_iam_policy_attachment" "profile" {
name = "cloudwatch-lambda-attachment"
roles = ["${aws_iam_role.role.name}"]
policy_arn = "${aws_iam_policy.policy.arn}"
}
resource "aws_lambda_function" "demo" {
filename = "function/deployment.zip"
function_name = "HelloWorld"
role = "${aws_iam_role.role.arn}"
handler = "main"
runtime = "go1.x"
}
- 这告诉 Terraform,我们将使用 AWS 提供商,并默认使用
us-east-1
区域来创建我们的资源:
- IAM 角色是执行期间由 Lambda 函数承担的执行角色。它定义了 Lambda 函数可以访问的资源:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
- IAM 策略是授予 Lambda 函数将其日志流式传输到 CloudWatch 的权限列表。以下策略将附加到 IAM 角色:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:CreateLogGroup",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
- Lambda 函数是基于 Go 的 Lambda 函数。部署包可以直接指定为本地文件(使用
filename
属性),也可以通过 Amazon S3 bucket 指定。有关如何将 Lambda 功能部署到 AWS 的详细信息,请参阅第 6 章、部署无服务器应用
- 在终端上运行
terraform init
命令下载安装 AWS 提供程序,如下图:
- 使用
terraform plan
命令创建执行计划(干运行)。它向您展示了将提前创建的内容,这有助于调试并确保您没有做错任何事情,如下一个屏幕截图所示:
- 在将 Terraform 部署到 AWS 之前,您将能够检查 Terraform 的执行计划。准备好后,继续并通过发出以下命令应用更改:
terraform apply
- 通过键入
yes
确认配置。将显示以下输出(为简洁起见裁剪了某些零件):
确保用于执行这些命令的 IAM 用户具有执行 IAM 和 Lambda 操作的权限
- 如果您返回 AWS Lambda 控制台,则应创建一个新的 Lambda 函数。如果您尝试调用它,它将返回预期的消息,如下一个屏幕截图所示:
- 到目前为止,我们在模板文件中定义了 AWS 区域和函数名。然而,我们使用基础设施作为代码工具的原因之一是可用性和自动化。因此,应始终使用变量并避免硬编码值。幸运的是,Terraform 允许您定义自己的变量。为此,创建一个
variables.tf
文件,如下所示:
variable "aws_region" {
default = "us-east-1"
description = "AWS region"
}
variable "lambda_function_name" {
default = "DemoFunction"
description = "Lambda function's name"
}
- 更新
main.tf
以使用变量而不是硬编码值。注意${var.variable_name}
关键字的用法:
provider "aws" {
region = "${var.aws_region}"
}
resource "aws_lambda_function" "demo" {
filename = "function/deployment.zip"
function_name = "${var.lambda_function_name}"
role = "${aws_iam_role.role.arn}"
handler = "main"
runtime = "go1.x"
}
- 在函数按预期工作的情况下,创建到目前为止我们使用 Terraform 构建的无服务器 API。
- 在新目录中,创建一个名为
main.tf
的文件,该文件包含以下配置:
resource "aws_iam_role" "role" {
name = "FindAllMoviesRole"
assume_role_policy = "${file("assume-role-policy.json")}"
}
resource "aws_iam_policy" "cloudwatch_policy" {
name = "PushCloudWatchLogsPolicy"
policy = "${file("cloudwatch-policy.json")}"
}
resource "aws_iam_policy" "dynamodb_policy" {
name = "ScanDynamoDBPolicy"
policy = "${file("dynamodb-policy.json")}"
}
resource "aws_iam_policy_attachment" "cloudwatch-attachment" {
name = "cloudwatch-lambda-attchment"
roles = ["${aws_iam_role.role.name}"]
policy_arn = "${aws_iam_policy.cloudwatch_policy.arn}"
}
resource "aws_iam_policy_attachment" "dynamodb-attachment" {
name = "dynamodb-lambda-attchment"
roles = ["${aws_iam_role.role.name}"]
policy_arn = "${aws_iam_policy.dynamodb_policy.arn}"
}
- 前面的代码片段创建了一个 IAM 角色,该角色具有扫描 DynamoDB 表的权限,并将日志条目写入 CloudWatch。将 DynamoDB 表名作为环境变量配置基于 Go 的 Lambda 函数:
resource "aws_lambda_function" "findall" {
function_name = "FindAllMovies"
handler = "main"
filename = "function/deployment.zip"
runtime = "go1.x"
role = "${aws_iam_role.role.arn}"
environment {
variables {
TABLE_NAME = "movies"
}
}
}
接下来,我们必须设置 DynamoDB 表。执行以下步骤:
- 创建一个以 ID 作为表分区键的 DynamoDB 表:
resource "aws_dynamodb_table" "movies" {
name = "movies"
read_capacity = 5
write_capacity = 5
hash_key = "ID"
attribute {
name = "ID"
type = "S"
}
}
- 使用新项初始化
movies
表:
resource "aws_dynamodb_table_item" "items" {
table_name = "${aws_dynamodb_table.movies.name}"
hash_key = "${aws_dynamodb_table.movies.hash_key}"
item = "${file("movie.json")}"
}
- 项目属性在
movie.json
文件中定义:
{
"ID": {"S": "1"},
"Name": {"S": "Ant-Man and the Wasp"},
"Description": {"S": "A Marvel's movie"},
"Cover": {"S": http://COVER_URL.jpg"}
}
最后,我们需要使用 API 网关触发函数:
- 在 RESTAPI 上创建一个
movies
资源,并在其上公开一个GET
方法。如果传入请求与定义的资源匹配,它将调用前面定义的 Lambda 函数:
resource "aws_api_gateway_rest_api" "api" {
name = "MoviesAPI"
}
resource "aws_api_gateway_resource" "proxy" {
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
parent_id = "${aws_api_gateway_rest_api.api.root_resource_id}"
path_part = "movies"
}
resource "aws_api_gateway_method" "proxy" {
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
resource_id = "${aws_api_gateway_resource.proxy.id}"
http_method = "GET"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "lambda" {
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
resource_id = "${aws_api_gateway_method.proxy.resource_id}"
http_method = "${aws_api_gateway_method.proxy.http_method}"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "${aws_lambda_function.findall.invoke_arn}"
}
- 发出以下命令以安装 AWS 插件、生成执行计划并应用更改:
terraform init
terraform plan
terraform apply
- 创建整个基础设施需要几秒钟的时间。创建步骤完成后,应创建并正确配置 Lambda 函数,如以下屏幕截图所示:
- API 网关也是如此,需要在
/movies
资源上用GET
方法定义一个新的 REST API,如下图:
- 在 DynamoDB 控制台中,应使用电影项创建一个新表,如下一个屏幕截图所示:
- 为了调用我们的 API 网关,我们需要部署它。创建一个部署阶段,我们称之为
staging
:
resource "aws_api_gateway_deployment" "staging" {
depends_on = ["aws_api_gateway_integration.lambda"]
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
stage_name = "staging"
}
- 我们将使用 Terraform 的输出特性公开 API URL;创建一个包含以下内容的
outputs.tf
文件:
output "API Invocation URL" {
value = "${aws_api_gateway_deployment.staging.invoke_url}"
}
- 再次运行
terraform apply
创建这些新对象,它会检测到这些变化,并要求您确认它应该执行这些操作,如下所示:
- API 网关 URL 将显示在输出部分;将其复制到剪贴板:
- 如果将常用浏览器指向 API 调用 URL,则应显示错误消息,如下一屏幕截图所示:
- 我们将通过向 API 网关授予调用 Lambda 函数的执行权限来解决这个问题。更新
main.tf
文件以创建aws_lambda_permission
资源:
resource "aws_lambda_permission" "apigw" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.findall.arn}"
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_deployment.staging.execution_arn}/*/*"
}
- 使用
terraform apply
命令应用最新的更改。在 Lambda 控制台上,应显示 API 网关触发器,如下所示:
- 在您喜爱的 web 浏览器中加载跑步输出中给定的 URL。如果一切正常,您将看到以 JSON 格式存储在 DynamoDB 表中的电影,如下一个屏幕截图所示:
Terraform 将基础设施的状态存储在状态文件(.tfstate
中)。状态包含资源 ID 和所有资源属性。如果您使用 Terraform 创建 RDS 实例,则数据库凭据将以明文形式存在于状态文件中。因此,您应该将文件保存在远程后端,例如 S3 bucket。
最后,要删除所有资源(Lambda 函数、IAM 角色、IAM 策略、DynamoDB 表和 API 网关),可以发出terraform destroy
命令,如下所示:
如果您想删除特定的资源,可以使用如下的--target
选项:terraform destroy --target=RESOURCE_NAME
。操作将仅限于资源及其依赖项。
到目前为止,我们已经使用模板文件定义了 AWS Lambda 函数及其依赖项。因此,我们可以像其他代码一样对其进行版本设置。我们使用和配置的整个无服务器基础设施被视为源代码,允许我们在团队成员之间共享,在其他 AWS 区域复制,并在出现故障时回滚。
AWS CloudFormation是一种基础设施,作为以声明方式指定资源的代码工具。您可以在蓝图文档(模板)中对希望 AWS 加速的所有资源进行建模,AWS 将为您创建定义的资源。因此,您花更少的时间管理这些资源,而更多的时间关注在 AWS 中运行的应用。
Terraform 涵盖了 AWS 提供的几乎所有服务和功能,并支持第三方提供商(平台无关),而 CloudFormation 是特定于 AWS 的(供应商锁定)。
您可以使用 AWS CloudFormation 来指定、部署和配置无服务器应用。您可以创建一个模板来描述无服务器应用依赖关系(Lambda 函数、DynamoDB 表、API 网关、IAM 角色等),而 AWS CloudFormation 负责为您提供和配置这些资源。您不需要单独创建和配置 AWS 资源,也不需要弄清楚什么取决于什么。
在深入了解 CloudFormation 之前,我们需要了解模板结构:
- AWSTemplateFormatVersion:云信息模板版本。
- 说明:模板的简要说明。
- 映射:可用于指定条件参数值的键和关联值的映射。
- 参数:运行时传递给模板的值。
- 资源:AWS 资源及其属性(Lambda、DynamoDB、S3 等)。
- 输出:描述查看堆栈属性时返回的值。
了解 AWS CloudFormation 模板的不同部分后,您可以将它们放在一起,并在template.yml
文件中定义一个最小模板,如下所示:
AWSTemplateFormatVersion: "2010-09-09"
Description: "Simple Lambda Function"
Parameters:
FunctionName:
Description: "Function name"
Type: "String"
Default: "HelloWorld"
BucketName:
Description: "S3 Bucket name"
Type: "String"
Resources:
ExecutionRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
Policies:
- PolicyName: "PushCloudWatchLogsPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- Resource: "*"
HelloWorldFunction:
Type: "AWS::Lambda::Function"
Properties:
Code:
S3Bucket: !Ref BucketName
S3Key: deployment.zip
FunctionName: !Ref FunctionName
Handler: "main"
Runtime: "go1.x"
Role: !GetAtt ExecutionRole.Arn
前面的文件定义了两个资源:
ExecutionRole
:分配给 Lambda 函数的 IAM 角色,它定义 Lambda 运行时调用的代码具有哪些权限。HelloWorldFunction
:在 AWS Lambda 定义中,我们将运行时属性设置为使用 Go,并将函数代码设置为存储在 S3 上的 ZIP 文件中。该函数使用 CloudFormation 的内置GetAtt
函数引用 IAM 角色;它还使用Ref
关键字引用参数部分中定义的变量。
也可以使用 JSON 格式;可以在 GitHub 存储库(上找到 JSON 版本 https://github.com/PacktPublishing/Hands-On-serverless-Applications-with-Go )。
执行以下步骤开始:
- 使用以下命令构建部署包后,创建一个 S3 bucket,在其上存储部署包:
aws s3 mb s3://hands-on-serverless-go-packt/
GOOS=linux go build -o main main.go
zip deployment.zip main
aws s3 cp deployment.zip s3://hands-on-serverless-go-packt/
- 导航到 AWS CloudFormation 控制台,并选择创建堆栈,如下一个屏幕截图所示:
- 在选择模板页面,选择模板文件,将其上传到 Amazon S3 bucket,如下图:
- 单击“下一步”,定义堆栈名称,并根据需要覆盖默认参数,如下一个屏幕截图所示:
- 单击 Next(下一步),保留默认选项,然后单击 Create(创建),如下一个屏幕截图所示:
- 堆栈将开始创建模板文件中定义的所有资源。一旦创建,堆栈状态将从创建中更改为创建完成(如果出现错误,将自动执行回滚),如下所示:
- 因此,应创建 Lambda 函数,如以下屏幕截图所示:
- 您可以随时更新 CloudFormation 模板文件。例如,让我们创建一个新的 DynamoDB 表:
AWSTemplateFormatVersion: "2010-09-09"
Description: "Simple Lambda Function"
Parameters:
FunctionName:
Description: "Function name"
Type: "String"
Default: "HelloWorld"
BucketName:
Description: "S3 Bucket name"
Type: "String"
TableName:
Description: "DynamoDB Table Name"
Type: "String"
Default: "movies"
Resources:
ExecutionRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
Policies:
-
PolicyName: "PushCloudWatchLogsPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "*"
-
PolicyName: "ScanDynamoDBTablePolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- dynamodb:Scan
Resource: "*"
HelloWorldFunction:
Type: "AWS::Lambda::Function"
Properties:
Code:
S3Bucket: !Ref BucketName
S3Key: deployment.zip
FunctionName: !Ref FunctionName
Handler: "main"
Runtime: "go1.x"
Role: !GetAtt ExecutionRole.Arn
Environment:
Variables:
TABLE_NAME: !Ref TableName
DynamoDBTable:
Type: "AWS::DynamoDB::Table"
Properties:
TableName: !Ref TableName
AttributeDefinitions:
-
AttributeName: "ID"
AttributeType: "S"
KeySchema:
-
AttributeName: "ID"
KeyType: "HASH"
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
- 在 CloudFormation 控制台上,选择我们之前创建的堆栈,然后从菜单中单击 Update stack,如下所示:
- 上传更新后的模板文件,如下图:
- 与 Terraform 类似,AWS CloudFormation 将检测更改并显示将提前更改的资源,如下所示:
- 单击更新按钮以应用更改。堆栈状态将更改为“正在更新”,如下一屏幕截图所示:
- 应用更改后,将创建一个新的 DynamoDB 表,并将 DynamoDB 权限授予 Lambda 函数,如下所示:
当 CloudFormation 必须定义 IAM 角色、策略或相关资源时,--capabilities CAPABILITY_IAM
选项是必需的。
- AWS CLI 还可用于使用以下命令创建 CloudFormation 堆栈:
aws cloudformation create-stack --stack-name=SimpleLambdaFunction \
--template-body=file://template.yml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=BucketName,ParameterValue=hands-on-serverless-go-packt
ParameterKey=FunctionName,ParameterValue=HelloWorld \
ParameterKey=TableName,ParameterValue=movies
除了从头开始编写自己的模板外,还可以使用 CloudFormation 设计模板功能轻松创建堆栈。下面的屏幕截图显示了如何查看到目前为止我们创建的堆栈的设计:
如果一切顺利,您应该看到以下组件:
现在可以通过从左侧菜单拖放组件来创建复杂的 CloudFormation 模板。
AWS 无服务器应用模型(AWS SAM是定义无服务器应用的模型。AWS SAM 本机受 AWS CloudFormation 支持,并定义了用于表示无服务器资源的简化语法。您只需在模板文件中定义作为应用一部分所需的资源,并使用 SAM deploy 命令创建 CloudFormation 堆栈。
之前,我们了解了如何使用 AWS SAM 在本地测试 Lambda 函数。此外,SAM 还可用于设计并将功能部署到 AWS Lambda。您可以使用以下命令初始化基于 quick Go 的无服务器项目(样板):
sam init --name api --runtime go1.x
前面的命令将创建具有以下结构的文件夹:
sam init
命令提供了创建无服务器应用的快速方法。它在 Go 中生成一个简单的 Lambda 函数,并进行相关的单元测试。此外,将生成一个 Makefile,其中包含构建和生成部署包的步骤列表。最后,将创建一个称为 SAM 文件的模板文件,该文件描述了将功能部署到 AWS Lambda 所需的所有 AWS 资源。
现在我们知道了如何使用 SAM 生成样板,让我们从头开始编写自己的模板。创建一个名为findall
的文件夹,在其中创建一个包含FindAllMovies
函数代码内容的main.go
文件:
// Movie entity
type Movie struct {
ID string `json:"id"`
Name string `json:"name"`
Cover string `json:"cover"`
Description string `json:"description"`
}
func findAll() (events.APIGatewayProxyResponse, error) {
...
svc := dynamodb.New(cfg)
req := svc.ScanRequest(&dynamodb.ScanInput{
TableName: aws.String(os.Getenv("TABLE_NAME")),
})
res, err := req.Send()
if err != nil {
return events.APIGatewayProxyResponse{
StatusCode: http.StatusInternalServerError,
Body: "Error while scanning DynamoDB",
}, nil
}
movies := make([]Movie, 0)
for _, item := range res.Items {
movies = append(movies, Movie{
ID: *item["ID"].S,
Name: *item["Name"].S,
Cover: *item["Cover"].S,
Description: *item["Description"].S,
})
}
...
return events.APIGatewayProxyResponse{
StatusCode: 200,
Headers: map[string]string{
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
Body: string(response),
}, nil
}
func main() {
lambda.Start(findAll)
}
接下来,在template.yaml
文件中创建一个无服务器应用定义。下面的示例说明了如何使用 DynamoDB 表创建 Lambda 函数:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::serverless-2016-10-31
Resources:
FindAllFunction:
Type: AWS::serverless::Function
Properties:
Handler: main
Runtime: go1.x
Policies: AmazonDynamoDBFullAccess
Environment:
Variables:
TABLE_NAME: !Ref MoviesTable
MoviesTable:
Type: AWS::serverless::SimpleTable
Properties:
PrimaryKey:
Name: ID
Type: String
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
该模板类似于我们前面编写的 CloudFormation 模板。SAM 扩展了 CloudFormation 并简化了表示无服务器资源的语法。
使用package
命令将部署包上传到CloudFormation节中创建的 S3 bucket:
sam package --template-file template.yaml --output-template-file serverless.yaml \
--s3-bucket hands-on-serverless-go-packt
前面的命令将把部署页面上传到 S3 bucket,如下面的屏幕截图所示:
此外,将根据您提供的定义文件生成名为serverless.yaml
的 SAM 模板文件。它应该包含指向您指定的 Amazon S3 bucket 中的deployment
ZIP 的CodeUri
属性:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
FindAllFunction:
Properties:
CodeUri: s3://hands-on-serverless-go-packt/764cf76832f79ca7f29c6397fe7ccd91
Environment:
Variables:
TABLE_NAME:
Ref: MoviesTable
Handler: main
Policies: AmazonDynamoDBFullAccess
Runtime: go1.x
Type: AWS::serverless::Function
MoviesTable:
Properties:
PrimaryKey:
Name: ID
Type: String
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
Type: AWS::serverless::SimpleTable
Transform: AWS::serverless-2016-10-31
最后,使用以下命令将函数部署到 AWS Lambda:
sam deploy --template-file serverless.yaml --stack-name APIStack \
--capabilities CAPABILITY_IAM
CAPABILITY_IAM
用于明确确认允许 AWS CloudFormation 代表您为 Lambda 函数创建 IAM 角色。
当您运行sam deploy
命令时,它会创建一个名为 APIStack 的 AWS CloudFormation 堆栈,如下一个屏幕截图所示:
创建资源后,应将该函数部署到 AWS Lambda,如下所示:
SAM 范围仅限于无服务器资源(支持的 AWS 服务列表位于:https://docs.aws.amazon.com/serverlessrepo/latest/devguide/using-aws-sam.html )。
AWS Lambda 允许您导出现有函数的 SAM 模板文件。选择目标函数并从操作菜单中单击导出函数,如下所示:
单击下载 AWS SAM 文件以下载模板文件,如下所示:
模板将包含函数的定义、必要的权限和触发器:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::serverless-2016-10-31'
Description: An AWS serverless Specification template describing your function.
Resources:
FindAllMovies:
Type: 'AWS::serverless::Function'
Properties:
Handler: main
Runtime: go1.x
CodeUri: .
Description: ''
MemorySize: 128
Timeout: 3
Role: 'arn:aws:iam::ACCOUNT_ID:role/FindAllMoviesRole'
Events:
Api1:
Type: Api
Properties:
Path: /MyResource
Method: ANY
Api2:
Type: Api
Properties:
Path: /movies
Method: GET
Environment:
Variables:
TABLE_NAME: movies
Tracing: Active
ReservedConcurrentExecutions: 10
您现在可以使用sam package
和sam deploy
命令将函数导入不同的 AWS 区域或 AWS 帐户。
管理无服务器应用资源可以非常手动,也可以自动化工作流。但是,如果您有一个复杂的基础设施,那么自动化过程可能会很棘手。这就是 AWS CloudFormation、SAM 和 Terraform 等工具的用武之地。
在本章中,我们学习了如何将基础架构作为代码工具来自动创建 AWS 中的无服务器应用资源和依赖项。我们看到了特定于云的工具,以及在多个平台上工作的松散耦合的工具。然后,我们了解了如何使用这些工具将基于 Lambda 的应用部署到 AWS。
现在,您可以编写一次无服务器基础结构代码,然后多次使用它。与任何其他代码一样,定义基础结构的代码可以进行版本控制、分叉、回滚(时光倒流),并用于审核基础结构更改。此外,可以通过编程的方式发现和解决它。换言之,如果已手动修改基础结构,则会销毁该基础结构,并为不可变的基础结构重新生成一个干净的副本。
- 编写一个地形模板来创建
InsertMovie
Lambda 函数资源。 - 更新 CloudFormation 模板,以使用 API 网关触发定义的 Lambda 函数,以响应传入的 HTTP 请求。
- 编写一个 SAM 文件,对构建本书中构建的无服务器 API 所需的所有资源进行建模和定义。
- 将 Terraform 配置为将生成的状态文件存储在远程 S3 后端。
- 为我们在本书中构建的无服务器 API 创建一个 CloudFormation 模板。
- 为我们在本书中构建的无服务器 API 创建一个 Terraform 模板。