我正在使用
serverless
部署 AWS 资源。有时我会收到有关现有资源如何导致部署失败的错误。这可能是由于团队中的另一个开发人员部署了名称冲突的资源造成的。我想知道我应该如何处理这个问题serverless
?
我之前使用过
terraform
,它支持import
命令,用于将现有资源导入到我的项目中。 serverless
有类似的吗?如果不是,解决此问题的最佳实践是什么?我不想手动删除 AWS 上的资源。
如果您询问如何将现有资源导入无服务器:
到目前为止,我对 AWS 和无服务器框架还没有丰富的经验(我最近才开始采用它们),但据我所知,导入现有的 AWS 资源并不是那么容易。
我最近必须将现有的手动创建的 DynamoDB 表添加到 Serverless (SLS),而不影响其中的数据。这个想法听起来很简单,直到我点击
sls deploy
时收到以下消息:
Resource of type 'AWS::DynamoDB::Table' with identifier 'myTable' already exists.
无服务器框架采用 CloudFormation Stacks 进行底层部署,因此我专注于此,最终在 AWS Docs 中找到了解决方案。
我强烈建议成对执行此手动过程,您可能还想确保没有人并行修改堆栈和资源。
这是我所做的:
想象下面
serverless.yml
service: aws-node-project-1
frameworkVersion: '3'
provider:
name: aws
region: eu-west-1
runtime: nodejs18.x
functions:
function1:
handler: index.handler
# The above was already deployed successfully.
# resources: # Here is the Resource we can't add to Serverless at this time.
# Resources:
# myTable:
# DeletionPolicy: Retain
# Type: AWS::DynamoDB::Table
# Properties:
# TableName: myTable
# AttributeDefinitions:
# - AttributeName: id
# AttributeType: S
# KeySchema:
# - AttributeName: id
# KeyType: HASH
# BillingMode: PAY_PER_REQUEST
部署无服务器服务后,它会创建一个 CloudFormation 堆栈,其中包括它管理的资源。例如,如果服务的名称是
aws-node-project-1
,阶段是dev
,那么默认情况下,堆栈的名称很可能是aws-node-project-1-dev
。以下命令将帮助您在 template.json
文件中获取堆栈模板。
aws cloudformation get-template --stack-name aws-node-project-1-dev --output json > template.json
这应该如下所示:
{
"TemplateBody": {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application",
"Resources": {
// Your existing Resources in the Stack.
},
"Outputs": {
// ...
}
},
"StagesAvailable": [
// ...
]
}
获取您要导入的资源的描述。就我而言,它是一个 DynamoDB 表。
aws dynamodb describe-table --table-name myTable --output json > table.json
这应该如下所示:
{
"Table": {
"AttributeDefinitions": [
// ...
],
"TableName": "myTable",
"KeySchema": [
// ...
],
"TableStatus": "ACTIVE",
"ProvisionedThroughput": {
"NumberOfDecreasesToday": 0,
"ReadCapacityUnits": 0,
"WriteCapacityUnits": 0
},
"TableSizeBytes": 44,
"ItemCount": 3,
"TableArn": "SOME_ARN",
"TableId": "SOME_ID",
"GlobalSecondaryIndexes": [
// ...
],
"TableClassSummary": {
"TableClass": "STANDARD"
},
"DeletionProtectionEnabled": false
// ...
}
}
将新资源添加到
template.json
文件中,而不删除任何现有资源。该文件应包含现有堆栈资源和您要导入的资源。
您还需要将
TemplateBody
移动到文件的根目录并删除 TemplateBody
和 StagesAvailable
字段。
最终,文件应如下所示:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application",
"Resources": {
// Your existing Resources in the Stack.
// ...
// The resource you want to import:
"myTable": { // Don't forget: This field name is treated as the Logical Id.
"Type": "AWS::DynamoDB::Table",
"DeletionPolicy": "Retain", // You might need to add this.
"Properties": {
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"TableName": "myTable",
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 0,
"WriteCapacityUnits": 0
}
}
}
},
"Outputs": {
// ...
}
}
aws cloudformation create-change-set \
--stack-name aws-node-project-1-dev --change-set-name ImportChangeSet \
--change-set-type IMPORT \
--resources-to-import "[{\"ResourceType\":\"AWS::DynamoDB::Table\",\"LogicalResourceId\":\"myTable\",\"ResourceIdentifier\":{\"TableName\":\"myTable\"}}]" \
--template-body file://template.json \
# --capabilities CAPABILITY_NAMED_IAM # You may need such Capabilities depending on your case. Use this field consciously.
aws cloudformation describe-change-set --change-set-name ImportChangeSet --stack-name aws-node-project-1-dev
aws cloudformation execute-change-set --change-set-name ImportChangeSet --stack-name aws-node-project-1-dev
如果成功,您应该会看到
"ResourceStatus": "IMPORT_COMPLETE"
(给 AWS 一些时间来进展)。
# In AWS Web Console: CloudFormation -> aws-node-project-1-dev -> Events
aws cloudformation describe-stack-events --stack-name aws-node-project-1-dev
验证资源是否已按预期添加到堆栈中。
# In AWS Web Console: CloudFormation -> aws-node-project-1-dev -> Resources
aws cloudformation describe-stack-resources --stack-name aws-node-project-1-dev
在此阶段,您应该能够将资源添加到
serverless.yml
并进行部署。但在执行此操作之前,我建议检查导入的资源是否存在漂移。
据我了解,术语
Drift
用于指出堆栈所需配置(如模板中所述)与实际资源状态之间的差异。
# Start detection. This is a background process therefore it will return
# a `Stack-Drift-Detection-Id` so you can check the status of this process later.
# In AWS Web Console: CloudFormation -> aws-node-project-1-dev -> Stack Actions > Detect drifts
aws cloudformation detect-stack-drift --stack-name aws-node-project-1-dev
# Check the detection status until `DetectionStatus` is `DETECTION_COMPLETE`.
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id YOUR_STACK_DRIFT_DETECTION_ID_HERE
# If `StackDriftStatus` is `DRIFTED`, check the Drifts with the following command and resolve accordingly.
# In AWS Web Console: CloudFormation -> aws-node-project-1-dev -> Stack Actions > View drift results
aws cloudformation describe-stack-resource-drifts --stack-name aws-node-project-1-dev
TL;DR: 无服务器框架不支持导入 CloudFormation 资源。但有办法解决所讨论的问题。
无服务器允许您使用现有 CloudFormation 资源的值。先决条件是您的同事或至少 CloudFormation 堆栈将您依赖的资源描述为 “输出”。
// in your colleagues serverless.yaml to export a VPC
resources:
// ...
Outputs:
StackVPC:
Description: The ID of the VPC
Value: !Ref MyVPC
Export:
Name: !Sub "${AWS::StackName}-VPCID"
在您的 serverless.yaml 中,您可以导入/引用现有 VPC。有几种方法可以将资源导入到您的堆栈中。
var1: 'Fn::ImportValue': '${refSackName}-VPCID'
var2: ${cf:${refSackName}-VPCID}
Fn::ImportValue
此处列出了此方法的优点和缺点https://dev.to/lambdasharp/dynamic-bindings-for-cloudformation-stacks-15l6