使用代码部署无服务器应用:Terraform与CloudFormation实践
基础设施即代码简介
基于Lambda的典型应用由多个事件触发的函数组成,这些事件包括S3存储桶中的新对象、传入的HTTP请求或新的SQS消息。这些函数可以独立运行,也可以利用其他资源,如DynamoDB表、Amazon S3存储桶和其他Lambda函数。在实际场景中,我们希望减少配置所需资源的时间,将更多精力放在应用逻辑上,这正是无服务器方法的核心。基础设施即代码(Infrastructure as Code)的概念可以帮助我们以自动化的方式设计和部署N层无服务器应用,避免人为错误和重复性任务。
技术要求
在开始之前,需要对AWS无服务器应用模型有一定的了解。代码包可在GitHub上获取:https://github.com/PacktPublishing/Hands-On-serverless-Applications-with-Go 。
使用Terraform部署AWS Lambda
Terraform是HashiCorp构建的开源自动化工具,通过声明式配置文件创建、管理和更新基础设施资源。它支持多种云提供商和基础设施软件,如AWS、Azure、Consul、Docker等。Terraform与配置管理工具(如Ansible、Chef等)不同,它主要用于创建和销毁基础设施。
安装和配置Terraform
要使用Terraform部署AWS Lambda,需要先安装Terraform。可从https://www.terraform.io/downloads.html 下载适合系统的包,并确保terraform二进制文件在PATH变量中可用。同时,需要配置凭证,有四种方式提供认证凭证:
1. 通过提供者直接提供AWS访问密钥和秘密密钥。
2. 使用AWS环境变量。
3. 使用共享凭证文件。
4. 使用EC2 IAM角色。
如果之前已经安装并配置了AWS CLI,则无需额外操作。
创建Lambda函数
创建Lambda函数的步骤如下:
1. 创建一个新的项目结构。
2. 使用简单的Hello world示例,函数文件夹包含一个基于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的二进制文件并生成部署包:
GOOS=linux go build -o main main.go
zip deployment.zip main
-
创建
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"
}
其中,IAM角色定义了Lambda函数在执行期间可访问的资源,IAM策略授予Lambda函数将日志流式传输到CloudWatch的权限。
5. 在终端运行
terraform init
命令下载并安装AWS提供者。
6. 使用
terraform plan
命令创建执行计划,查看将创建的资源,有助于调试和确保操作正确。
7. 确认执行计划后,运行
terraform apply
命令应用更改,并在提示时输入
yes
确认配置。确保执行这些命令的IAM用户具有执行IAM和Lambda操作的权限。
8. 若一切顺利,在AWS Lambda控制台将创建一个新的Lambda函数,调用该函数应返回预期的消息。
为了提高模板的可用性和自动化程度,建议使用变量避免硬编码值。创建
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
文件以使用变量:
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"
}
设置DynamoDB表
设置DynamoDB表的步骤如下:
1. 创建一个以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网关
使用API网关触发函数的步骤如下:
1. 在REST API上创建一个movies资源,并公开一个GET方法:
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网关和DynamoDB表应已创建并正确配置。
- 创建一个部署阶段(如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"
}
-
创建
outputs.tf文件以暴露API URL:
output "API Invocation URL" {
value = "${aws_api_gateway_deployment.staging.invoke_url}"
}
-
再次运行
terraform apply命令创建新对象,确认更改后,API Gateway URL将显示在输出部分。 -
若在浏览器中访问API调用URL显示错误消息,需要授予API网关调用Lambda函数的执行权限。更新
main.tf文件:
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命令应用最新更改,再次访问API调用URL,应能看到DynamoDB表中存储的电影信息以JSON格式显示。
Terraform将基础设施的状态存储在状态文件(.tfstate)中,为了安全起见,建议将文件保存在远程后端,如S3存储桶。如果要删除所有资源,可使用
terraform destroy
命令;若要删除特定资源,可使用
--target
选项。
以下是使用Terraform部署的流程图:
graph LR
A[安装和配置Terraform] --> B[创建Lambda函数]
B --> C[设置DynamoDB表]
C --> D[配置API网关]
D --> E[部署和测试]
E --> F[清理资源]
通过以上步骤,我们可以使用Terraform自动化部署和管理AWS Lambda函数、DynamoDB表和API网关等资源,提高开发效率和减少人为错误。
使用代码部署无服务器应用:Terraform与CloudFormation实践
使用CloudFormation部署AWS Lambda
AWS CloudFormation是一种基础设施即代码工具,可通过声明式方式指定资源。用户在蓝图文档(模板)中对想要AWS创建的所有资源进行建模,AWS会为用户创建这些定义好的资源,这样用户就能将更多时间花在运行于AWS的应用程序上,而减少管理资源的时间。
Terraform几乎涵盖了AWS的所有服务和功能,并且支持第三方提供商(平台无关),而CloudFormation则是特定于AWS的(存在供应商锁定)。用户可以使用AWS CloudFormation来指定、部署和配置无服务器应用程序,只需创建一个描述无服务器应用程序依赖项(如Lambda函数、DynamoDB表、API网关、IAM角色等)的模板,AWS CloudFormation就会负责为用户配置和供应这些资源,无需用户单独创建和配置AWS资源并理清它们之间的依赖关系。
在深入了解CloudFormation之前,需要先了解模板的结构:
-
AWSTemplateFormatVersion
:CloudFormation模板的版本。
-
Description
:模板的简要描述。
-
Mappings
:键和关联值的映射,可用于指定条件参数值。
-
Parameters
:在运行时传递给模板的值。
-
Resources
:AWS资源及其属性(如Lambda、DynamoDB、S3等)。
-
Outputs
:描述查看堆栈属性时返回的值。
理解了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格式也可以使用,JSON版本可在GitHub存储库(https://github.com/PacktPublishing/Hands-On-serverless-Applications-with-Go )中找到。
以下是使用CloudFormation部署的步骤:
1. 创建一个S3存储桶,用于存储部署包:
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存储桶。
- 点击“下一步”,定义堆栈名称,并根据需要覆盖默认参数。
- 再次点击“下一步”,将选项保留为默认值,然后点击“创建”。
-
堆栈将开始创建模板文件中定义的所有资源。创建完成后,堆栈状态将从
CREATE_IN_PROGRESS变为CREATE_COMPLETE(如果出现问题,将自动执行回滚)。 - 最终,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控制台中,选择之前创建的堆栈,然后从菜单中点击“更新堆栈”。
- 上传更新后的模板文件。
- 与Terraform类似,AWS CloudFormation会检测到更改并提前显示将更改的资源。
-
点击“更新”按钮应用更改,堆栈状态将变为
UPDATE_IN_PROGRESS。 - 更改应用后,将创建一个新的DynamoDB表,并向Lambda函数授予DynamoDB权限。
当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部署的流程图:
graph LR
A[了解模板结构] --> B[创建模板文件]
B --> C[创建S3存储桶并上传部署包]
C --> D[创建堆栈]
D --> E[更新模板(可选)]
E --> F[更新堆栈]
总结
通过Terraform和CloudFormation这两种基础设施即代码的工具,我们可以实现无服务器应用的自动化部署和管理。Terraform具有平台无关性,支持多种云提供商和基础设施软件;而CloudFormation则是专门为AWS设计的,能很好地与AWS生态系统集成。
在实际应用中,可以根据项目的需求和团队的技术栈来选择合适的工具。使用这两种工具都能提高开发效率,减少人为错误,并且可以像管理代码一样对基础设施进行版本控制,方便团队成员之间的共享、在其他AWS区域进行复制以及在出现故障时进行回滚操作。
以下是Terraform和CloudFormation的对比表格:
| 特性 | Terraform | CloudFormation |
| ---- | ---- | ---- |
| 平台支持 | 支持多种云提供商和基础设施软件 | 特定于AWS |
| 模板格式 | HCL | YAML或JSON |
| 状态管理 | 存储在状态文件(.tfstate) | 由AWS CloudFormation管理 |
| 社区支持 | 活跃的开源社区 | AWS官方支持 |
无论是使用Terraform还是CloudFormation,都可以帮助开发者更高效地构建和管理无服务器应用,让开发者将更多的精力放在应用逻辑的开发上。
超级会员免费看
51

被折叠的 条评论
为什么被折叠?



