如何在 DynamoDb 表已经存在的情况下继续部署

32
我希望即使资源已经存在,也能继续部署(或强制执行)。
目前我遇到了这个错误:
Serverless Error ---------------------------------------

     An error occurred while provisioning your stack: AvailableDynamoDbTable
     - Available already exists.

如果你的资源不仅仅被无服务器应用处理,那么你就不应该去尝试处理它。要么在由无服务器创建的CloudFormation堆栈中处理资源,要么在它最初创建的位置处理。 - doorstuck
@doorstuck,这个问题是由Serverless处理的,但有时您需要重新创建表格,现在您需要删除所有Serverless,因为这个错误总是出现,导致无法部署。 - Marckaraujo
为什么必须重新创建表?听起来它并不完全被无服务器和云形成堆栈处理,而是有它自己的生命周期。在这种情况下考虑不使用无服务器管理数据库。 只有完全在无服务器项目中使用且仅在其中使用的数据库才应由无服务器项目处理。如果数据库具有外部依赖项(其他人调用它)或其他人将重新创建它等,则不应该成为无服务器堆栈的一部分。 那只是我的看法和经验 :) - doorstuck
你需要的是 SkipIfExists: True(https://github.com/serverless/serverless/issues/3183#issuecomment-962529842)。 - Ash
8个回答

11
这个问题比较老,但仍然在谷歌的前五名结果中显示,这里提供一些见解: 将您的无服务器堆栈拆分为多个服务是一个好主意,每个服务都有自己的serverless.yml文件。一个用于API和lambda函数,另一个用于DynamoDB。这样您就可以单独处理它们并更新您的lambda函数而不触及您的DB。 这里有一个很棒的指南:
  1. https://serverless-stack.com/chapters/organizing-serverless-projects.html
  2. https://serverless-stack.com/chapters/dynamodb-as-a-serverless-service.html
  3. https://serverless-stack.com/chapters/deploying-multiple-services-in-serverless.html

3
这是一个不错的建议,但并不是正确的解决方案。因为它并没有真正解决问题。正如你在论坛中所看到的那样,有很长的讨论。 - Marckaraujo
@Marckaraujo,你指的是哪个论坛?能否提供链接? - Tomiwa

11

备份表并删除它。一旦部署,就进行还原。

当我重命名我的无服务器项目并尝试部署时,我遇到了相同的问题。我有一个被再次使用的表tanks。出现了以下错误。

Serverless Error ---------------------------------------

 An error occurred: TanksDynamoDbTable - tanks already exists in stack arn:aws:cloudformation:eu-central-1:592235674655:stack/colossal-dev/105693a8-77af-11e9-8f9e-2a86e4085a59.

我通过备份tanks表并将其删除来解决了这个问题。

  1. 控制台 > DynamoDB
  2. 在左侧选择备份
  3. 创建备份 > 从下拉菜单中选择表格并为其命名 > 创建
  4. 在左侧选择表格
  5. 勾选Tanks > 删除

删除后,需要等待五分钟,因为缓存会定期清除而不是立即清除。之后,我尝试了serverless deploy,它能够成功执行。此外,您需要还原备份的数据库:

  1. 在左侧选择备份
  2. 勾选备份的表格 > 还原
  3. 将新表格的名称设置为之前的表格名称。
  4. 还原表格 还原数据库需要一些时间,请耐心等待五分钟或更长时间。

这实际上起作用了,尽管在能够再次恢复它之前,我不得不删除新部署的表。 - BenSower
3
当然会起作用,你们正在删除表格,然后部署。需要解决的问题是:第一次和再次部署时不应该抛出异常。 - Renan Cidale

4

1
有关这个问题的任何消息吗? - Benjamin Heinke
更新:问题已关闭,不会修复 - undefined

2

我已经和其他人一起努力解决这个问题两周了,同时还有其他的部署问题。

现在我想说的是 - 表格已经存在或队列不存在等类似的问题都是因为你试图违反堆栈“安全”:

  • 无服务器应用程序依赖于CloudFormation
  • 如果您的无服务器部署尝试管理不属于它的资源 - 您将会遇到“已存在...(但不是您的)”;

自从我重新从头开始部署并恢复了数据库以来,我几乎总是可以稳定地部署带有资源更改的内容,直到某个同事手动进行了操作)

所以为了避免这样的问题,最好:

  • 不要手动添加删除修改资源
  • 将它们命名为不重叠的名称(例如dev-Table/prod-Table)
  • 使用ARN作为外部堆栈资源(或使用具有无服务器输出的导出名称)
  • 尝试将资源(资源组)导入到您的堆栈中

1
如果是测试环境,您可以进入AWS控制台删除已存在的表格。因此,如果您想创建多个Lambda函数来共享某些表格,则应创建一个仅处理Dynamodb的无服务器,并且其余服务不包含任何Dynamodb配置。
如果您希望所有Lambda都具有相同的API Gateway,则可以在提供程序下添加apiGateway,如下面的示例所示。
例如:
- 无服务器A:DynamoDB和公共端点/,API Gateway具有restApiId:xxxxx、restApiRootResourceId:yyyyyy。 - 无服务器B:用户服务和公共端点/users。 - 无服务器C:车辆服务和公共端点/vehicle。
serverless.yml无服务器A
resources:
  Resources:
    VehiclesDynamoDbTable:
        Type: 'AWS::DynamoDB::Table'
        DeletionPolicy: Retain
        Properties:
          AttributeDefinitions:
            -
              AttributeName: id
              AttributeType: S
          KeySchema:
            -
              AttributeName: id
              KeyType: HASH
          ProvisionedThroughput:
            ReadCapacityUnits: 1
            WriteCapacityUnits: 1
          TableName: ${self:provider.environment.DYNAMODB_VEHICLE_TABLE}

     UsersDynamoDbTable:
        Type: 'AWS::DynamoDB::Table'
        DeletionPolicy: Retain
        Properties:
          AttributeDefinitions:
            -
              AttributeName: id
              AttributeType: S
          KeySchema:
            -
              AttributeName: id
              KeyType: HASH
          ProvisionedThroughput:
            ReadCapacityUnits: 1
            WriteCapacityUnits: 1
          TableName: ${self:provider.environment.DYNAMODB_USER_TABLE}

serverless.yml serverless B

provider:
  apiGateway
    restApiId: xxxxx # REST API resource ID. Default is generated by the framework
    restApiRootResourceId: yyyyyy # Root resource, represent as / path
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
        - dynamodb:DescribeTable
        Resource: "*"

serverless.yml serverless C

provider:
  apiGateway
    restApiId: xxxxx # REST API resource ID. Default is generated by the framework
    restApiRootResourceId: yyyyyy # Root resource, represent as / path
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
        - dynamodb:DescribeTable
        Resource: "*"

我使用了这个的变体,基本上我的无服务器A保持不变,它创建和管理DynamoDB。 它还运行代码并执行操作。对于Serverless B,C ... 我注释掉了资源:部分,并使用了“Resource:”*“”片段。Resource: "*"是所有这些的真正要点。 我相信它也可以使我们使用手动设置的DyanamoDB表。 - JasonWilson

0

我曾经遇到过同样的问题,解决方法是在 serverless.yml 文件中删除已经存在于 DynamoDB 中的 xxxDynamoDbTable,这样就可以正常工作了。你不需要再次使用 Resources


那并不能解决你的问题。 - Niketh Sudhakaran

0
如果你真的想避免删除表格,那么最好的办法是停止将AWS资源作为lambda函数堆栈的一部分进行管理。相反,你可以从某个外部来源导入生产表格资源。
无服务器团队不会修复一个功能请求来解决这个问题。
我们所处理的问题,并不是框架本身的限制,而是通过框架部署配置服务时的CloudFormation的限制。
虽然现在通过CloudFormation似乎“有点”可能实现所需的功能(通过处理DeletionPolicy和最近引入的导入资源功能的组合)。但是,试图以通用方式解决这个问题似乎并不容易。这可能需要大量的工作(以及新的问题需要解决),正如@kennu已经观察到的那样。
由于所涉及的复杂性,这似乎不是正确的方向。更合理的做法是认为Serverless服务配置的资源是服务的不可分割的一部分,并且在使用sls remove命令删除服务时也应该一并删除这些资源。对于不接受这种方式的情况,我们应该在外部配置相关资源。需要注意的是,框架在许多地方允许连接到已经创建和配置外部的资源。

-1

请确保您没有意外创建一个新的 CloudFormation 堆栈实例,可能使用不同的名称。如果您正在使用与已经存在的堆栈相同的名称进行部署,则应该只是更新所有内容。

但是,如果您无意中创建了一个新的堆栈,因为名称发生了变化,例如 "my-app-prod" 与 "my-app-production",则可能会出现此故障,因为您的 "my-app-prod" 已经创建了表格,而 "my-app-production" 正在尝试重新创建这些相同的表格,这将失败,因为它们已经存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接