如何使用 Step Functions 停止 Amazon RDS 執行個體超過 7 天?

6 分的閱讀內容
0

我想要使用 AWS Step Functions 停止 Amazon Relational Database Service (Amazon RDS) 超過 7 天持續時間。

簡短說明

依預設,您一次最多可停止 Amazon RDS 資料庫執行個體 7 天。7 天後,執行個體會重新啟動,因此不會錯過任何維護更新

若要停止執行個體超過 7 天,您可以使用 Step Functions 自動化工作流程,而不會錯過維護時段。

**注意:**如需替代解決方案,請參閱如何使用 AWS Lambda 函數停止 Amazon RDS 執行個體超過 7 天?

解決方法

設定 IAM 許可

建立 AWS 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.    選擇下一步: 標籤

5.    (選用) 若要新增標籤,請選擇新增標籤,然後在索引鍵欄位中輸入適當的值。

6.    選擇下一步: 檢閱

7.    輸入政策的名稱。例如,輸入 step-functions-start-stop-rds-policy。若要檢閱政策的授予許可,請參閱摘要章節。

8.    選擇建立政策

如需詳細資訊,請參閱使用 JSON 編輯器建立政策

建立 IAM 角色並連接必要的政策

1.    開啟 IAM 主控台

2.    在導覽窗格中,選擇角色。然後,選擇建立角色

3.    在選取受信任實體的類型中,選擇 AWS 服務

4.    在其他 AWS 服務的使用案例下拉式清單中,選擇 Step Functions。然後,選擇 Step Functions 選項。

5.    選擇下一步
注意:請勿在新增許可頁面採取任何動作。請先建立角色,然後編輯預設許可。

6.    選擇下一步

7.    在角色名稱中,輸入角色的名稱。例如,輸入 step-functions-start-stop-rds-role
(選用) 更新角色描述。
(選用) 若要新增標籤,請在索引鍵欄位中輸入適當的值。

8.    選擇建立角色。這會傳回角色清單。

9.    在搜尋方塊中,輸入您建立的角色名稱。然後,選取該角色,以查看其詳細資訊。

10.    在許可索引標籤中,選擇新增許可下拉式清單。然後,選擇連接政策

11.    在設定 IAM 許可區段中,輸入您建立的政策名稱。例如,輸入 step-functions-start-stop-rds-policy。若您將此政策視為選項,則選取該政策。

12.    在許可索引標籤中,選取 AWSLambdaRole AWS 受管政策,然後選擇移除

如需詳細資訊,請參閱為 AWS 服務建立角色 (主控台)

為資料庫執行個體新增標籤

1.    開啟 Amazon RDS 主控台

2.    在導覽窗格中,選擇資料庫

3.    選取您想要自動啟動和停止的資料庫執行個體。

4.    選擇標籤索引標籤。

5.   選取新增。在標籤鍵中,輸入自動啟動。在中,輸入 yes

6.    選擇新增其他標籤。在標籤鍵中,輸入 autostop。在「值」中,輸入 yes

7.    若要儲存這些標籤,請選擇新增

如需詳細資訊,請參閱新增、列出和移除標籤

建立狀態機器,以啟動和停止已標記的資料庫執行個體

1.    開啟 Step Functions 主控台

2.    在導覽窗格中,選擇狀態機器。然後,選擇建立狀態機器

3.    選擇使用程式碼撰寫工作流程

4.    將預設類型保持為標準

5.   在定義編輯器中,刪除範例 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.    選擇下一步

7.    輸入狀態機器名稱。例如,輸入 step-functions-start-stop-rds-state-machine

8.    在許可下,選擇選擇現有角色。然後,選取您建立的 IAM 角色。例如,選取 step-functions-start-stop-rds-role

9.    (選用) 若要新增標籤,請在索引鍵欄位中輸入適當的值。

10.  選擇建立狀態機器

執行工作流程測試

若要對處於已停止狀態的已標記資料庫執行個體執行函數測試,請完成下列步驟:

1.    開啟 Step Functions 主控台

2.    在導覽窗格中,選擇狀態機器

3.    選取您建立的狀態機器,以啟動資料庫執行個體。

4.    選擇開始執行
注意:此解決方案無需事件承載。在開始執行對話方塊下,您可以移除事件承載或保留預設事件。

5.    選擇開始執行

建立排程

若要針對已標記的資料庫執行個體排定每週維護時段,請建立 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.    選擇下一步

13.    選擇常用的 API,然後選擇 StartExecution

14.    在 StartExecution 下,選取您建立的狀態機器。例如,選取 step-functions-start-stop-rds-state-machine。保持輸入的預設值 {}

15.    選擇下一步

16.    在重試政策和無效字母佇列 (DLQ) 下,清除重試政策將其停用。

17.    在許可 ,保留預設選項: 為此排程建立新角色

**注意:**EventBridge 會建立一個要擔任的新角色,然後針對您的特定工作流程起始 StartExecution

18.    選擇下一步

19.    在排程詳細資訊下,確認接下來的 10 個叫用日期是否與預期排程的日期相符。

20.    選擇建立排程

EventBridge 叫用規則時,即會開始 Step Function 工作流程。此規則會在維護時段前 30 分鐘啟動資料庫執行個體。然後,工作流程會在維護時段完成後 30 分鐘停止資料庫執行個體。  例如,工作流程會在 21:30 啟動資料庫執行個體。維護時段發生在 22:00 至 22:30。然後,工作流程會在 23:00 停止執行個體。