如何使用 Step Functions 将 Amazon RDS 实例停止 7 天以上?

5 分钟阅读
0

我想使用 Amazon Step Functions 将 Amazon Relational Database Service (Amazon RDS) 停止 7 天以上。

简短描述

默认情况下,您一次最多可以将 Amazon RDS 数据库实例停止七天时间。七天后,实例会重新启动,以免错过任何维护更新

要将您的实例停止超过 7 天,您可以使用 Step Functions 来自动执行工作流,而不会错过维护时段。

**注意:**有关替代解决方案,请参阅如何使用 Amazon Lambda 函数将 Amazon RDS 实例停止 7 天以上?

解决方法

配置 IAM 权限

创建一个 Amazon Identity and Access Management (IAM) 策略,用于允许 Step Functions 启动和停止实例并检索有关该实例的信息:

  1. 打开 IAM 控制台

  2. 在导航窗格中,选择策略。然后,选择创建策略

3.    选择 JSON 选项卡。然后,输入以下策略以便授予所需的 IAM 权限:

{
    "Version": "2012-10-17",
    "Statement":
    [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "rds:DescribeDBInstances",
                "rds:StopDBInstance",
                "rds:StartDBInstance"
            ],
            "Resource": "*"
        }
    ]
}

4.    选择下一步: 标签

  1. (可选)要添加标签,请选择添加标签,然后为字段输入相应的值。

6.    选择下一步: 审核

  1. 输入策略的名称。例如,输入 step-functions-start-stop-rds-policy。要审核已为策略授予的权限,请参阅摘要部分。

8.    选择创建策略

有关更多信息,请参阅使用 JSON 编辑器创建策略

创建 IAM 角色并附加所需的策略

1.    打开 IAM 控制台

  1. 在导航窗格中,选择角色。然后,选择创建角色

  2. 对于选择受信任实体的类型,选择亚马逊云科技服务

4.在其他亚马逊云科技服务的用例下拉列表中,选择 **Step Functions **。然后,选择 Step Functions 选项。

5.    选择下一步
注意:请勿在添加权限页面上执行任何操作。首先创建角色,然后编辑默认权限。

6.    选择下一步

  1. 对于角色名称,输入角色的名称。例如,输入 step-functions-start-stop-rds-role
    (可选)更新角色描述。
    (可选)要添加标签,请在字段中输入相应的值。

8.    选择创建角色。这样会让您返回到角色列表。

  1. 在搜索框中,输入您创建的角色的名称。然后,选择该角色以查看其详细信息。

  2. 权限选项卡中,选择添加权限下拉列表。然后,选择附加策略

  3. 配置 IAM 权限部分中,输入您创建的策略的名称。例如,输入 step-functions-start-stop-rds-policy。当您看到此策略显示为一个选项时,请将其选中。

  4. 权限选项卡中,选择 AWSLambdaRole 亚马逊云科技托管策略,然后选择删除

有关更多信息,请参阅为亚马逊云科技服务创建角色(控制台)

为数据库实例添加标签

1.    打开 Amazon RDS 控制台

2.     在导航窗格中,选择数据库

  1. 选择要自动启动和停止的数据库实例。

  2. 选择标签选项卡。

  3. 选择添加。对于标签键,输入 autostart。对于,输入 yes

  4. 选择添加其他标签。对于标签键,输入 autostop。对于 “值”,输入 yes

  5. 要保存这些标签,请选择添加

有关更多信息,请参阅添加、列出和删除标签

创建状态机以启动和停止已标记的数据库实例

1.    打开 Step Functions 控制台

  1. 在导航窗格中,选择状态机。然后,选择创建状态机

  2. 选择用代码编写工作流

  3. 将默认类型保留为标准

  4. 定义编辑器中,删除示例 JSON 定义。然后,输入以下状态机定义:

{
  "Comment": "State Machine Definition to start and stop RDS DB instances",
  "StartAt": "Describe DBInstances to Start",
  "States": {
    "Describe DBInstances to Start": {
      "Type": "Task",
      "Parameters": {},
      "Resource": "arn:aws:states:::aws-sdk:rds:describeDBInstances",
      "Next": "Iterate on Instances to Start",
      "Retry": [
        {
          "ErrorEquals": [
            "Rds.InternalFailure",
            "Rds.ServiceUnavailable",
            "Rds.ThrottlingException",
            "Rds.SdkClientException"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 1,
          "MaxAttempts": 2
        }
      ]
    },
    "Iterate on Instances to Start": {
      "Type": "Map",
      "ItemProcessor": {
        "ProcessorConfig": {
          "Mode": "INLINE"
        },
        "StartAt": "Format Array before Start",
        "States": {
          "Format Array before Start": {
            "Type": "Pass",
            "Next": "Check If Instance stopped, if no Tags or if Tags contains 'autostart=yes'",
            "Parameters": {
              "DbInstanceStatus.$": "$.DBInstance.DbInstanceStatus",
              "DbInstanceIdentifier.$": "$.DBInstance.DbInstanceIdentifier",
              "TagList.$": "$.DBInstance.TagList",
              "TagsArrayLength.$": "States.ArrayLength($.DBInstance.TagList)",
              "TagContainsKey.$": "States.ArrayContains($.DBInstance.TagList,$.LookingFor)"
            }
          },
          "Check If Instance stopped, if no Tags or if Tags contains 'autostart=yes'": {
            "Type": "Choice",
            "Choices": [
              {
                "Not": {
                  "Variable": "$.DbInstanceStatus",
                  "StringEquals": "stopped"
                },
                "Next": "Instance is not in 'stopped' status"
              },
              {
                "Variable": "$.TagsArrayLength",
                "NumericEquals": 0,
                "Next": "No Tags found to Start"
              },
              {
                "Variable": "$.TagContainsKey",
                "BooleanEquals": true,
                "Next": "Tags found Start DBInstance"
              }
            ],
            "Default": "No Tags found to Start"
          },
          "Tags found Start DBInstance": {
            "Type": "Task",
            "Parameters": {
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            },
            "Resource": "arn:aws:states:::aws-sdk:rds:startDBInstance",
            "Retry": [
              {
                "ErrorEquals": [
                  "Rds.InternalFailure",
                  "Rds.ServiceUnavailable",
                  "Rds.ThrottlingException",
                  "Rds.SdkClientException"
                ],
                "BackoffRate": 2,
                "IntervalSeconds": 1,
                "MaxAttempts": 2
              }
            ],
            "Catch": [
              {
                "ErrorEquals": [
                  "States.ALL"
                ],
                "Next": "Failed to Start DBInstance"
              }
            ],
            "ResultSelector": {
              "message": "Instance Started",
              "DbInstanceIdentifier.$": "$.DbInstance.DbInstanceIdentifier"
            },
            "End": true
          },
          "Failed to Start DBInstance": {
            "Type": "Pass",
            "Parameters": {
              "message": "Failed to start instance",
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            },
            "End": true
          },
          "No Tags found to Start": {
            "Type": "Pass",
            "End": true,
            "Parameters": {
              "message": "No Tags found to Start",
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            }
          },
          "Instance is not in 'stopped' status": {
            "Type": "Pass",
            "End": true,
            "Parameters": {
              "message": "Instance is not in 'stopped' status",
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            }
          }
        }
      },
      "InputPath": "$.DbInstances",
      "Next": "Wait for 1 hour and 30 minutes",
      "ItemSelector": {
        "LookingFor": {
          "Key": "autostart",
          "Value": "yes"
        },
        "DBInstance.$": "$$.Map.Item.Value"
      }
    },
    "Wait for 1 hour and 30 minutes": {
      "Type": "Wait",
      "Seconds": 5400,
      "Next": "Describe DBInstances to Stop"
    },
    "Describe DBInstances to Stop": {
      "Type": "Task",
      "Parameters": {},
      "Resource": "arn:aws:states:::aws-sdk:rds:describeDBInstances",
      "Retry": [
        {
          "ErrorEquals": [
            "Rds.InternalFailure",
            "Rds.ServiceUnavailable",
            "Rds.ThrottlingException",
            "Rds.SdkClientException"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 1,
          "MaxAttempts": 2
        }
      ],
      "Next": "Iterate on Instances to Stop"
    },
    "Iterate on Instances to Stop": {
      "Type": "Map",
      "ItemProcessor": {
        "ProcessorConfig": {
          "Mode": "INLINE"
        },
        "StartAt": "Format Array before Stop",
        "States": {
          "Format Array before Stop": {
            "Type": "Pass",
            "Next": "Check If Instance available, if no Tags or if Tags contains 'autostop=yes'",
            "Parameters": {
              "DbInstanceStatus.$": "$.DBInstance.DbInstanceStatus",
              "DbInstanceIdentifier.$": "$.DBInstance.DbInstanceIdentifier",
              "TagList.$": "$.DBInstance.TagList",
              "TagsArrayLength.$": "States.ArrayLength($.DBInstance.TagList)",
              "TagContainsKey.$": "States.ArrayContains($.DBInstance.TagList,$.LookingFor)"
            }
          },
          "Check If Instance available, if no Tags or if Tags contains 'autostop=yes'": {
            "Type": "Choice",
            "Choices": [
              {
                "Not": {
                  "Variable": "$.DbInstanceStatus",
                  "StringEquals": "available"
                },
                "Next": "Instance is not in 'available' status"
              },
              {
                "Variable": "$.TagsArrayLength",
                "NumericEquals": 0,
                "Next": "No Tags found to Stop"
              },
              {
                "Variable": "$.TagContainsKey",
                "BooleanEquals": true,
                "Next": "Tags found Stop DBInstance"
              }
            ],
            "Default": "No Tags found to Stop"
          },
          "Tags found Stop DBInstance": {
            "Type": "Task",
            "Parameters": {
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            },
            "Resource": "arn:aws:states:::aws-sdk:rds:stopDBInstance",
            "Retry": [
              {
                "ErrorEquals": [
                  "Rds.InternalFailure",
                  "Rds.ServiceUnavailable",
                  "Rds.ThrottlingException",
                  "Rds.SdkClientException"
                ],
                "BackoffRate": 2,
                "IntervalSeconds": 1,
                "MaxAttempts": 2
              }
            ],
            "Catch": [
              {
                "ErrorEquals": [
                  "States.ALL"
                ],
                "Next": "Failed to Stop DBInstance"
              }
            ],
            "ResultSelector": {
              "message": "Instance Stopped",
              "DbInstanceIdentifier.$": "$.DbInstance.DbInstanceIdentifier"
            },
            "End": true
          },
          "Failed to Stop DBInstance": {
            "Type": "Pass",
            "Parameters": {
              "message": "Failed to stop instance",
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            },
            "End": true
          },
          "No Tags found to Stop": {
            "Type": "Pass",
            "End": true,
            "Parameters": {
              "message": "No Tags found to Stop",
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            }
          },
          "Instance is not in 'available' status": {
            "Type": "Pass",
            "End": true,
            "Parameters": {
              "message": "Instance is not in 'available' status",
              "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
            }
          }
        }
      },
      "InputPath": "$.DbInstances",
      "Next": "Workflow Finished",
      "ItemSelector": {
        "LookingFor": {
          "Key": "autostop",
          "Value": "yes"
        },
        "DBInstance.$": "$$.Map.Item.Value"
      }
    },
    "Workflow Finished": {
      "Type": "Succeed"
    }
  }
}

注意:出于测试目的,您可以修改等待 1 小时 30 分钟状态下的字段。此外,您还可以更改此值以延长或缩短维护时段。

6.    选择下一步

  1. 输入状态机名称。例如,输入 step-functions-start-stop-rds-state-machine

  2. 权限下,选择选择现有角色。然后,选择您创建的 IAM 角色。例如,选择 step-functions-start-stop-rds-role

  3. (可选)要添加标签,请在字段中输入相应的值。

  4. 选择创建状态机

执行工作流测试

要对处于已停止状态的已标记数据库实例执行功能测试,请完成以下步骤:

1.    打开 Step Functions 控制台

  1. 在导航窗格中,选择状态机

  2. 选择您为启动数据库实例而创建的状态机。

  3. 选择开始执行
    注意:此解决方法不需要事件有效负载。在开始执行对话框下,您可以删除事件有效负载或保留默认事件。

  4. 选择开始执行

创建计划

要为已标记的数据库实例计划每周维护时段,请创建 EventBridge 规则。此规则会在维护时段前 30 分钟自动启动数据库实例。

在以下示例用例中,维护时段是星期日的 22:00–22:30。示例规则会在每个星期日的 21:30 启动数据库实例。

  1. 打开 EventBridge 控制台

  2. 创建状态机以启动和停止已标记的数据库实例部分中,选择您之前创建的状态机。

  3. 总线下,选择规则

  4. 从下拉列表中选择默认事件总线。

  5. 选择创建规则

  6. 对于规则名称,输入要创建的规则的名称。例如,输入 step-functions-start-stop-rds-rule

  7. 对于规则类型,选择计划。对于此页面上的其他值,请保留默认设置。

  8. 选择继续使用 EventBridge 调度器

  9. 对于定期计划,选择出现次数。然后,对于计划类型,选择基于 cron 的计划

  10. 为自动计划添加 cron 表达式。例如,输入 cron(30 21 ? * SUN *)

  11. 对于弹性时间范围,选择关闭

12.    选择下一步

  1. 选择常用 API,然后选择 StartExecution

  2. StartExecution 下,选择您创建的状态机。例如,选择 step-functions-start-stop-rds-state-machine。保留输入的默认值 {}

15.    选择下一步

  1. 重试策略和死信队列 (DLQ) 下,清除重试策略以将其停用。

  2. 权限下,保留默认选项: 为此计划创建新角色

**注意:**EventBridge 会创建一个要担任的新角色并为您的特定工作流启动 StartExecution API。

  1. 选择下一步

  2. 计划详细信息下,确认接下来的 10 个调用日期是否与您的预期计划日期相符。

  3. 选择创建计划

当 EventBridge 调用规则时,它会开始 Step Functions 工作流。这会在维护时段前 30 分钟启动数据库实例。然后,工作流会在维护时段完成 30 分钟后停止数据库实例。例如,工作流在 21:30 启动您的数据库实例。维护时段是在 22:00–22:30。然后,工作流会在 23:00 停止您的实例。