¿Cómo puedo utilizar Step Functions para detener una instancia de Amazon RDS por más de 7 días?

11 minutos de lectura
1

Quiero utilizar AWS Step Functions para detener un servicio de base de datos relacional de Amazon (Amazon RDS) por más de 7 días.

Descripción breve

De forma predeterminada, se puede detener una instancia de la base de datos de Amazon RDS durante un máximo de siete días por vez. Transcurridos los siete días, la instancia se reiniciará para que no se pierda ninguna actualización de mantenimiento.

Para detener la instancia durante más de 7 días, se puede utilizar Step Functions para automatizar el flujo de trabajo sin perder ningún período de mantenimiento.

Nota: Para una solución alternativa, consulte ¿Cómo puedo utilizar una función de AWS Lambda para detener una instancia de Amazon RDS durante más de siete días?

Solución

Configurar los permisos de IAM

Cree una política de AWS Identity and Access Management (IAM) que permita que Step Functions inicie y detenga una instancia y recupere la información de la instancia:

1.    Abra la consola de IAM.

2.    En el panel de navegación, seleccione Políticas. A continuación, seleccione Crear política.

3.    Seleccione la pestaña JSON. A continuación, introduzca la siguiente política para conceder los permisos necesarios de IAM:

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

4.    Seleccione Siguiente: Etiquetas.

5.    (Opcional) Para añadir una etiqueta, seleccione Agregar etiqueta y, a continuación, introduzca los valores correspondientes en los campos Clave y Valor.

6.    Seleccione Siguiente: Revisar.

7.    Introduzca el nombre de la política. Por ejemplo, escriba política-rds-iniciar-detener-con-step-functions. Para revisar los permisos otorgados a la política, consulte la sección Resumen.

8.    Seleccione Crear política.

Para obtener más información, consulte Creación de políticas mediante el editor JSON.

Crear un rol de IAM y adjuntar las políticas necesarias

1.    Abra la consola de IAM.

2.    En el panel de navegación, seleccione Roles. A continuación, seleccione Crear rol.

3.    En Seleccionar el tipo de entidad de confianza elija Servicio de AWS.

4.    En la lista desplegable Ejemplos de uso de otros servicios de AWS, seleccione Step Functions. A continuación, seleccione la opción Step Functions.

5.    Seleccione Siguiente.
**Nota:**No realice ninguna acción en la página Añadir permisos. Primero cree el rol y, a continuación, edite los permisos predeterminados.

6.    Seleccione Siguiente.

7.    En Nombre del rol, introduzca el nombre del rol. Por ejemplo, escriba rol-rds-iniciar-detener-con-step-functions.
(Opcional) Actualice la descripción del rol.
(Opcional) Para añadir una etiqueta, introduzca los valores correspondientes en los campos Clave y Valor.

8.    Seleccione Crear rol. Esto le devolverá a la lista Roles.

9.    En el cuadro de búsqueda, introduzca el nombre del rol que haya creado. A continuación, seleccione esa función para ver los detalles.

10.    En la pestaña Permisos, seleccione la lista desplegable Añadir permisos. A continuación, seleccione Adjuntar políticas.

11.    Introduzca en la sección Configurar permisos de IAM el nombre de la política que haya creado. Por ejemplo, escriba política-rds-iniciar-detener-con-step-functions. Cuando considere esta como una opción, selecciónela.

12.    En la pestaña Permisos, seleccione la política gestionada por AWS de AWSLambdaRole y, a continuación, seleccione Eliminar.

Para obtener más información, consulte Crear el rol de un servicio de AWS (consola).

Añadir etiquetas a las instancias de la base de datos

1.    Abra la consola de Amazon RDS.

2    En el panel de navegación seleccione Bases de datos.

3.    Seleccione la instancia de la base de datos que desee iniciar y detener automáticamente.

4.    Seleccione la pestaña Etiquetas.

5.    Seleccione Añadir. En Clave de etiqueta escriba autostart. En Valor introduzca .

6.    Seleccione ** Añadir otra etiqueta**. En Clave de etiqueta escriba autostop. En Valor, introduzca .

7.    Para guardar estas etiquetas, seleccione Añadir.

Para obtener más información, consulte Añadir, publicar y eliminar etiquetas.

Crear una máquina de estados para iniciar y detener las instancias etiquetadas de la base de datos

1.    Abra la consola de Step Functions.

2.    En el panel de navegación de la izquierda seleccione Máquinas de estados. A continuación, seleccione Crear máquina de estados.

3.    Seleccione Escribir el flujo de trabajo en código.

4.    Mantenga el Tipo predeterminado como Estándar.

5.    En el editor Definición elimine la definición JSON de ejemplo. A continuación, introduzca la siguiente definición de la máquina de estados:

{
  "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"
    }
  }
}

Nota: Para realizar pruebas, se puede modificar el campo Segundos en el estado Esperar 1 hora y 30 minutos. Además, se puede ampliar este valor a un período de mantenimiento más largo o más corto.

6.    Seleccione Siguiente.

7.    Introduzca el nombre de la máquina de estado. Por ejemplo, escriba máquina-estado-rds-iniciar-detener-con-step-functions.

8.    En Permisos seleccione Elegir un rol existente. A continuación, seleccione el rol de IAM que haya creado. Por ejemplo, seleccione rol-rds-iniciar-detener-con-step-functions.

9.    (Opcional) Para añadir una etiqueta, introduzca los valores correspondientes en los campos Clave y Valor.

10.  Seleccione Crear máquina de estados.

Realizar una prueba del flujo de trabajo

Para realizar pruebas de funcionamiento en las instancias etiquetadas de la base de datos que estén en estado Detenido, siga estos pasos:

1.    Abra la consola de Step Functions.

2.    En el panel de navegación de la izquierda seleccione Máquinas de estados.

3.    Seleccione la máquina de estados que creó para iniciar las instancias de la base de datos.

4.    Seleccione Iniciar ejecución.
Nota: Esta solución no requiere ninguna carga útil de eventos. En el cuadro de diálogo Iniciar ejecución se puede eliminar la carga útil del evento o dejar el evento predeterminado.

5.    Seleccione Iniciar ejecución.

Crear el horario

Para programar el horario del período de mantenimiento semanal de las instancias etiquetadas de la base de datos, cree una regla de EventBridge. Esta regla iniciará automáticamente la instancia de la base de datos 30 minutos antes del período de mantenimiento.

En el siguiente ejemplo de caso práctico, el período de mantenimiento se produce entre las 22:00 y las 22:30 del domingo. La regla de ejemplo inicia la instancia de la base de datos todos los domingos a las 21:30.

1.    Abra la consola de EventBridge.

2.    Seleccione la máquina de estados que creó anteriormente en la sección Crear una máquina de estados para iniciar y detener las instancias etiquetadas de la base de datos.

3.    En Buses seleccione Reglas.

4.    En la lista desplegable seleccione el bus de eventos predeterminado.

5.    Seleccione Crear regla.

6.    En Nombre de la regla introduzca el nombre de la regla que desee crear. Por ejemplo, introduzca regla-rds-iniciar-detener-con-step-functions.

7.    En Tipo de regla seleccione Horario. Mantenga la configuración predeterminada del resto de valores de esta página.

8.    Seleccione Continuar con EventBridge Scheduler.

9.    En Horario recurrente seleccione Frecuencia. A continuación, en Tipo de horario seleccione Horario basado en cron.

10.    Añada una expresión cron al horario automatizado. Por ejemplo, introduzca cron(30 21 ? * SUN *).

11.    En el Ventana de tiempo flexible seleccione Desactivada.

12.    Seleccione Siguiente.

13.    Seleccione Las API de uso frecuente y, a continuación, seleccione StartExecution.

14.    En StartExecution seleccione la máquina de estados que haya creado. Por ejemplo, seleccione máquina-estados-rds-iniciar-detener-con-step-functions. Mantenga el valor predeterminado de la entrada de ** {}**.

15.    Seleccione Siguiente.

16.    En Política de reintentos y cola de mensajes fallidos (DLQ) borre la Política de reintentos para desactivarla.

17.    En Permisos mantenga la opción predeterminada: Cree un nuevo rol para este horario.

Nota: EventBridge crea un nuevo rol que asume e inicia la API StartExecution para el flujo de trabajo concreto.

18.    Seleccione Siguiente.

19.    En Detalles del horario compruebe que las siguientes 10 fechas de invocación coincidan con las fechas del horario previsto.

20.    Seleccione Crear horario.

Cuando EventBridge invoca la regla, inicia el flujo de trabajo de «Step Functions». Esto inicia las instancias de la base de datos 30 minutos antes del período de mantenimiento. A continuación, el flujo de trabajo detiene la instancia de la base de datos 30 minutos después de que finalice el período de mantenimiento.  Por ejemplo, el flujo de trabajo inicia la instancia de la base de datos a las 21:30. El período de mantenimiento tiene lugar entre las 22:00 y las 22:30. A continuación, el flujo de trabajo detiene la instancia a las 23:00.