sbstjn / serverless-dynamodb-autoscaling

Serverless Plugin for Amazon DynamoDB Auto Scaling configuration.
https://sbstjn.com/serverless-dynamodb-auto-scaling-with-cloudformation.html
MIT License
148 stars 27 forks source link

Deploys with no Errors but Properties Unchanged #23

Closed shawnemullen closed 6 years ago

shawnemullen commented 7 years ago

I installed the plugin and configured. When I deploy I do not get any errors but the auto scaling properties of the tables do not change. I am trying to set auto scaling for two tables and there are no indexes.

I am using the latest version of serverless. The tables already exist from a previous deploy.

Before attempting to use this plugin, I configured auto scaling manually through the aws console. I removed my manual configuration before trying to use the plugin. Maybe something was left behind when I did it manually that is preventing the plugin from working.

Any ideas?

sbstjn commented 7 years ago

Are the tables part of the CloudFormation resources in your serverless.yml ? The plugin configuration needs the resource identifier and not the table name:

custom:
  capacities:
    - table: CustomTable  # DynamoDB Resource identifier

Can you provide an example serverless.yml configuration ?

shawnemullen commented 7 years ago

Yes.

  plugins:
    - serverless-dynamodb-autoscaling
  custom:
    capacities: 
      - table: subscriptionDetailTable
        read:
          minimum: 50
          maximum: 300
          usage: 0.70
        write:
          minimum: 50
          maximum: 300
          usage: 0.70
      - table: subscriptionPoliciesTable
        read:
          minimum: 50
          maximum: 300
          usage: 0.70
        write:
          minimum: 50
          maximum:300
          usage: 0.70

resources:
  Resources:
    subscriptionDetailTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:service}-subscription-details
        AttributeDefinitions:
          - AttributeName: subscription_detail_id
            AttributeType: S
        KeySchema:
          - AttributeName: subscription_detail_id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 50
          WriteCapacityUnits: 50
        StreamSpecification:
          StreamViewType: KEYS_ONLY

    subscriptionPoliciesTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:service}-subscription-policies
        AttributeDefinitions:
          - AttributeName: subscription_policy_id
            AttributeType: S
        KeySchema:
          - AttributeName: subscription_policy_id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 50
          WriteCapacityUnits: 50
        StreamSpecification:
          StreamViewType: NEW_IMAGE
sbstjn commented 7 years ago

Thanks 👍

pierreis commented 7 years ago

Got the same issue. Creating a fresh new table works, CloudFormation completes successfully, but the table is not configured with auto scaling.

service: test

plugins:
  - serverless-dynamodb-autoscaling

resources:
  Resources:
    TokensTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: Tokens
        AttributeDefinitions:
          - AttributeName: user_id
            AttributeType: S
          - AttributeName: key_id
            AttributeType: S
        KeySchema:
          - AttributeName: user_id
            KeyType: HASH
          - AttributeName: key_id
            KeyType: RANGE
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TimeToLiveSpecification:
          AttributeName: ttl
          Enabled: TRUE

custom:
  capacities:
    - table: TokensTable
      read:
        minimum: 1
        maximum: 1000
        usage: 0.75
      write:
        minimum: 1
        maximum: 200
        usage: 0.75

The corresponding CloudFormation template is:

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "The AWS CloudFormation template for this Serverless application",
  "Resources": {
    "ServerlessDeploymentBucket": {
      "Type": "AWS::S3::Bucket"
    },
    "testDynamoDBAutoscaleRoleTokensTableDevUseast1": {
      "DependsOn": [
        "TokensTable"
      ],
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                "Service": "application-autoscaling.amazonaws.com"
              }
            }
          ],
          "Version": "2012-10-17"
        },
        "Policies": [
          {
            "PolicyDocument": {
              "Statement": [
                {
                  "Action": [
                    "cloudwatch:PutMetricAlarm",
                    "cloudwatch:DescribeAlarms",
                    "cloudwatch:DeleteAlarms",
                    "cloudwatch:GetMetricStatistics",
                    "cloudwatch:SetAlarmState"
                  ],
                  "Effect": "Allow",
                  "Resource": "*"
                },
                {
                  "Action": [
                    "dynamodb:DescribeTable",
                    "dynamodb:UpdateTable"
                  ],
                  "Effect": "Allow",
                  "Resource": {
                    "Fn::Join": [
                      "",
                      [
                        "arn:aws:dynamodb:*:",
                        {
                          "Ref": "AWS::AccountId"
                        },
                        ":table/",
                        {
                          "Ref": "TokensTable"
                        }
                      ]
                    ]
                  }
                }
              ],
              "Version": "2012-10-17"
            },
            "PolicyName": "testDynamoDBAutoscalePolicyTokensTableDevUseast1"
          }
        ],
        "RoleName": "testDynamoDBAutoscaleRoleTokensTableDevUseast1"
      },
      "Type": "AWS::IAM::Role"
    },
    "testTableScalingPolicyReadTokensTableDevUseast1": {
      "DependsOn": [
        "TokensTable",
        "testAutoScalingTargetReadTokensTableDevUseast1"
      ],
      "Properties": {
        "PolicyName": "testTableScalingPolicyReadTokensTableDevUseast1",
        "PolicyType": "TargetTrackingScaling",
        "ScalingTargetId": {
          "Ref": "testAutoScalingTargetReadTokensTableDevUseast1"
        },
        "TargetTrackingScalingPolicyConfiguration": {
          "PredefinedMetricSpecification": {
            "PredefinedMetricType": "DynamoDBReadCapacityUtilization"
          },
          "ScaleInCooldown": 60,
          "ScaleOutCooldown": 60,
          "TargetValue": 75
        }
      },
      "Type": "AWS::ApplicationAutoScaling::ScalingPolicy"
    },
    "testAutoScalingTargetReadTokensTableDevUseast1": {
      "DependsOn": [
        "TokensTable",
        "testDynamoDBAutoscaleRoleTokensTableDevUseast1"
      ],
      "Properties": {
        "MaxCapacity": 1000,
        "MinCapacity": 1,
        "ResourceId": {
          "Fn::Join": [
            "",
            [
              "table/",
              {
                "Ref": "TokensTable"
              }
            ]
          ]
        },
        "RoleARN": {
          "Fn::GetAtt": [
            "testDynamoDBAutoscaleRoleTokensTableDevUseast1",
            "Arn"
          ]
        },
        "ScalableDimension": "dynamodb:table:ReadCapacityUnits",
        "ServiceNamespace": "dynamodb"
      },
      "Type": "AWS::ApplicationAutoScaling::ScalableTarget"
    },
    "testTableScalingPolicyWriteTokensTableDevUseast1": {
      "DependsOn": [
        "TokensTable",
        "testAutoScalingTargetWriteTokensTableDevUseast1"
      ],
      "Properties": {
        "PolicyName": "testTableScalingPolicyWriteTokensTableDevUseast1",
        "PolicyType": "TargetTrackingScaling",
        "ScalingTargetId": {
          "Ref": "testAutoScalingTargetWriteTokensTableDevUseast1"
        },
        "TargetTrackingScalingPolicyConfiguration": {
          "PredefinedMetricSpecification": {
            "PredefinedMetricType": "DynamoDBWriteCapacityUtilization"
          },
          "ScaleInCooldown": 60,
          "ScaleOutCooldown": 60,
          "TargetValue": 75
        }
      },
      "Type": "AWS::ApplicationAutoScaling::ScalingPolicy"
    },
    "testAutoScalingTargetWriteTokensTableDevUseast1": {
      "DependsOn": [
        "TokensTable",
        "testDynamoDBAutoscaleRoleTokensTableDevUseast1"
      ],
      "Properties": {
        "MaxCapacity": 200,
        "MinCapacity": 1,
        "ResourceId": {
          "Fn::Join": [
            "",
            [
              "table/",
              {
                "Ref": "TokensTable"
              }
            ]
          ]
        },
        "RoleARN": {
          "Fn::GetAtt": [
            "testDynamoDBAutoscaleRoleTokensTableDevUseast1",
            "Arn"
          ]
        },
        "ScalableDimension": "dynamodb:table:WriteCapacityUnits",
        "ServiceNamespace": "dynamodb"
      },
      "Type": "AWS::ApplicationAutoScaling::ScalableTarget"
    },
    "TokensTable": {
      "Type": "AWS::DynamoDB::Table",
      "Properties": {
        "TableName": "Tokens",
        "AttributeDefinitions": [
          {
            "AttributeName": "user_id",
            "AttributeType": "S"
          },
          {
            "AttributeName": "key_id",
            "AttributeType": "S"
          }
        ],
        "KeySchema": [
          {
            "AttributeName": "user_id",
            "KeyType": "HASH"
          },
          {
            "AttributeName": "key_id",
            "KeyType": "RANGE"
          }
        ],
        "ProvisionedThroughput": {
          "ReadCapacityUnits": 1,
          "WriteCapacityUnits": 1
        },
        "TimeToLiveSpecification": {
          "AttributeName": "ttl",
          "Enabled": true
        }
      }
    }
  },
  "Outputs": {
    "ServerlessDeploymentBucketName": {
      "Value": {
        "Ref": "ServerlessDeploymentBucket"
      }
    }
  }
}

Deploying a second time enables auto scaling as expected.

rasmushjulskov commented 7 years ago

Have the same issue. Have any of you found a solution? @sbstjn @pierreis

TimMensch commented 6 years ago

I have a similar issue, though it worked the first time.

Yes, the very first time I created a table with autoscaling it worked.

But I then removed the entire stack and redeployed. So, to be clear: The DynamoDB tables were completely gone. Nothing left.

After the second deploy, the tables were created, but no autoscaling was selected.

Wondering if some policy or IAM user or role that gets created when you enable autoscaling was still around, and the second deploy has an internal throw when creating that role fails.

sbstjn commented 6 years ago

I released v0.6.2 with the "fix" introduced in #25 . Does this change anything for you?

Maybe it's a CloudFormation behaviour with default configurations for DynamoDB …

TimMensch commented 6 years ago

Looks promising.

I can't do a full test right now, but I ran sls package before and after the upgrade, just to compare the CloudFormation templates, and sure enough, the new version at least has configuration in it related to the autoscaling. My previous version had zero autoscaling configuration in it.

I'll be testing it some time this week, but it looks likely to be fixed, at least for me.

Thanks!