Saltar al contenido

¿Cómo puedo crear y programar instantáneas manuales en OpenSearch Service?

11 minutos de lectura
0

Quiero crear una instantánea manual de mi dominio de Amazon OpenSearch Service. También quiero ejecutar automáticamente la instantánea de forma recurrente.

Descripción corta

Para crear una instantánea manual de tu dominio de OpenSearch Service, configura un bucket de Amazon Simple Storage Service (Amazon S3) para almacenar los datos de la instantánea. A continuación, registra el bucket de S3 como repositorio de instantáneas. Por último, utiliza el repositorio registrado para crear instantáneas manuales. También puedes usar los paneles de OpenSearch para tomar una instantánea del repositorio registrado.

Para programar automáticamente las instantáneas manuales para OpenSearch 2.1+, utiliza una política de instantáneas. Para las versiones anteriores de OpenSearch, utiliza una función de AWS Lambda con el programador de Amazon EventBridge.

Resolución

Nota: Si se muestran errores al ejecutar comandos de la Interfaz de la línea de comandos de AWS (AWS CLI), consulta Solución de problemas de AWS CLI. Además, asegúrate de utilizar la versión más reciente de la AWS CLI.

Requisitos previos:

  • Tu dominio ejecuta OpenSearch 1.0+.
  • La política de AWS Identity and Access Management (IAM) de tu usuario o rol tiene los permisos CreateBucket y PutBucketPolicy necesarios para administrar el bucket.
  • La política de IAM de tu usuario o rol tiene el permiso IAMFullAccess necesario para crear una política y un rol de IAM.
  • La política de IAM de tu usuario o rol tiene el permiso ESHttpPut necesario para registrar el repositorio.

Configuración de un bucket de S3

Sigue estos pasos:

  1. Crea un nuevo bucket en la misma región de AWS que tu dominio de OpenSearch Service.

  2. Utiliza la consola de IAM o la AWS CLI para crear una política de IAM que conceda los permisos necesarios para acceder al bucket de S3.
    Ejemplo de política:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "s3:ListBucket",
            "s3:GetBucketLocation"
          ],
          "Resource": [
            "arn:aws:s3:::your-bucket-name"
          ]
        },
        {
          "Effect": "Allow",
          "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:DeleteObject",
            "iam:PassRole"
          ],
          "Resource": [
            "arn:aws:s3:::your-bucket-name/*"
          ]
        }
      ]
    }

    Nota: Sustituye your-bucket-name por el nombre de tu bucket.

  3. Utiliza la consola de IAM o la AWS CLI para crear un rol de IAM para OpenSearch Service.
    El siguiente ejemplo del comando create-role crea un rol denominado TheSnapshotRole y adjunta una política de confianza al rol:

    aws iam create-role --role-name TheSnapshotRole --assume-role-policy-document '{
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "opensearchservice.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }'
  4. Utiliza la consola de IAM o la AWS CLI para adjuntar la política de acceso de Amazon S3 al rol.

  5. Utiliza la consola de IAM o la AWS CLI para crear una política con permisos iam:PassRole.
    Ejemplo de política:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "iam:PassRole",
                "Resource": "arn:aws:iam::account-id:role/TheSnapshotRole"
            },
            {
                "Effect": "Allow",
                "Action": "es:ESHttpPut",
                "Resource": "arn:aws:es:region:account-id:domain/domain-name/*"
            }
        ]
    }

    Nota: Sustituye account-id por el ID de tu cuenta de AWS, region por tu región y domain-name por el nombre de tu dominio de OpenSearch Service.

  6. Ejecuta el siguiente comando attach-user-policy para adjuntar la política iam:PassRole al usuario de IAM que configuraste para usar la AWS CLI:

    aws iam attach-user-policy --user-name YOUR_IAMUSERNAME --policy-arn arn:aws:iam::account-id:policy/PassRolePolicy

    Nota: Sustituye YOUR_IAMUSERNAME por el nombre de usuario y account-id por el ID de tu cuenta.

Registro del repositorio de instantáneas

Para registrar el repositorio de instantáneas, debes firmar la solicitud con la versión 4 de AWS Signature. Los nombres de los repositorios no pueden empezar por cs. Además, no es recomendable escribir en el mismo repositorio desde varios dominios. Configura solo un dominio para que tenga acceso de escritura al repositorio.

Utiliza Python para registrar el repositorio de instantáneas en Lambda. O bien, para usar awscurl y la AWS CLI para registrar el repositorio de instantáneas, ejecuta el siguiente comando en la instancia:

read -r ACCESS_KEY SECRET_KEY SESSION_TOKEN <<< $(aws sts get-session-token --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' --output text)

awscurl \
  --access_key $ACCESS_KEY \
  --secret_key $SECRET_KEY \
  --session_token $SESSION_TOKEN \
  --region us-west-2 \
  --service es \
  -X PUT \
  -H "Content-Type: application/json" \
  'domain-endpoint/_snapshot/my-snapshot-repo' \
  -d '{
    "type": "s3",
    "settings": {
      "bucket": "bucketname",
      "region": "us-west-2",
      "role_arn": "arn:aws:iam::account-id:role/TheSnapshotRole"
    }
  }'

Nota: Sustituye my-snapshot-repo por el nombre de tu repositorio, bucketname por el nombre de tu bucket y us-west-2 por tu región. Además, sustituye domain-endpoint por el punto de enlace del dominio de OpenSearch Service, account-id por el ID de tu cuenta y TheSnapshotRole por el nombre de tu rol.

Para instalar awscurl, ejecuta el siguiente comando:

pip install awscurl

Para obtener más información, consulta awscurl en el sitio web de GitHub.

Creación de la instantánea manual

Usa los comandos curl para tomar una instantánea manual de tu dominio de OpenSearch Service. Para OpenSearch 2.5 o posterior, puedes usar los paneles de OpenSearch. Para obtener instrucciones, consulta Take a snapshot (Realizar una instantánea) en el sitio web de OpenSearch.

Después de crear la instantánea, puedes verla en el bucket de S3 o a través de los paneles de OpenSearch.

Programación de instantáneas manuales automatizadas

Para OpenSearch 2.1 o posterior, puedes usar una API o paneles de OpenSearch para crear una política de instantáneas con el repositorio registrado. Para obtener más información, consulta Snapshot management API (API de administración de instantáneas) y Creating an SM policy (Creación de una política de SM) en el sitio web de OpenSearch.

Para las versiones de OpenSearch anteriores a la 2.1, sigue estos pasos para programar las instantáneas manuales:

  1. Si tu dominio de OpenSearch Service está en una nube virtual privada (VPC), crea una nueva función de Lambda con la versión ejecutable de Python 3.13 en la misma VPC.
  2. Agrega la capa AWSSDKPandas-Python313 que incluye requests-aws4auth a la función. Para obtener más información, consulta AWS Lambda managed layers (Capas administradas por AWS Lambda) en el sitio web de AWS SDK para pandas y requests-aws4auth en el sitio web de Python.
  3. Introduce el siguiente código para la función de Lambda:
    import json
    import boto3
    import requests
    from requests_aws4auth import AWS4Auth
    from datetime import datetime
    
    def lambda_handler(event, context):
        # OpenSearch endpoint and repository details
        host = 'domain-endpoint'
        repository = 'my-snapshot-repo'
        snapshot = f"snapshot-{datetime.now().strftime('%Y%m%d%H%m%S')}"
        region = 'us-west-2'
        service = 'es'
    
        # Get AWS credentials
        credentials = boto3.Session().get_credentials()
        awsauth = AWS4Auth(
            credentials.access_key,
            credentials.secret_key,
            region,
            service,
            session_token=credentials.token
        )
    
        # API endpoint for creating snapshot
        url = f'https://{host}/_snapshot/{repository}/{snapshot}'
    
        # Snapshot creation parameters
        payload = {
            "indices": "*",
            "ignore_unavailable": True,
            "include_global_state": False
        }
    
        try:
            # Make the request
            response = requests.put(
                url,
                auth=awsauth,
                json=payload,
                headers={"Content-nt-Type": "application/json"}
            )
    
            # Check if request was successful
            if response.status_code == 200:
                return {
                    'statusCode': 200,
                    'body': json.dumps({
                        'message': 'Snapshot creation initiated successfully',
                        'snapshot_name': snapshot,
                        'response': response.json()
                    })
                }
            else:
                return {
                    'statusCode': response.status_code,
                    'body': json.dumps({
                        'message': 'Failed to create snapshot',
                        'error': response.text
                    })
                }
    
        except Exception as e:
            return {
                'statusCode': 500,
                'body': json.dumps({
                    'message': 'Error creating snapshot',
                    'error': str(e)
                })
            }
    Nota: Sustituye domain-endpoint por el punto de enlace de tu dominio, pero no incluyas https://. Además, sustituye my-snapshot-repo por tu repositorio de instantáneas y us-west-2 por tu región.
  4. Adjunta los siguientes permisos al rol adjunto a la función de Lambda:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "es:ESHttpPut",
                    "es:DescribeElasticsearchDomain"
                ],
                "Resource": "arn:aws:es:region:account-id:domain/domain-name/*"
            }
        ]
    }
    Nota: Sustituye region por tu región, account-id por tu ID de cuenta, my-snapshot-repo por el nombre de tu repositorio y domain-name por tu dominio.
  5. Usa el programador de EventBridge para invocar la función de Lambda en una programación.

(Opcional) Eliminación de instantáneas innecesarias

Para las instantáneas manuales que crea la política de instantáneas, utiliza el parámetro max_age o el periodo de retención para establecer una fecha de vencimiento. Para obtener más información e instrucciones, consulta Parameters (Parámetros) y Creating an SM policy (Creación de una política de SM) en el sitio web de OpenSearch.

Si la función de Lambda creó la instantánea manual, no puedes configurar una opción de vencimiento. En su lugar, utiliza otra función de Lambda para eliminar las instantáneas de OpenSearch.

La siguiente función de Lambda elimina las instantáneas de OpenSearch que tienen más de 30 días:

import json
import boto3
import requests
from requests_aws4auth import AWS4Auth
from datetime import datetime, timedelta
import re

def parse_date_from_snapshot_name(snapshot_name):
    # Pattern for format: snapshot-YYYY-MM-DDtHH-MM-SS
    try:
        # Skip "snapshot-" prefix and parse the date part
        date_str = snapshot_name[9:]  # Remove "snapshot-"
        return datetime.strptime(date_str, '%Y-%m-%dt%H-%M-%S')
    except (ValueError, IndexError):
        return None

def lambda_handler(event, context):
    # OpenSearch endpoint and repository details
    host = 'domain-endpoint'
    repository = 'my-snapshot-repo'
    region = 'us-west-2'
    service = 'es'

    # Get AWS credentials
    credentials = boto3.Session().get_credentials()
    awsauth = AWS4Auth(
        credentials.access_key,
        credentials.secret_key,
        region,
        service,
        session_token=credentials.token
    )

    try:
        # First, get all snapshots
        list_url = f'https://{host}/_snapshot/{repository}/_all'
        list_response = requests.get(
            list_url,
            auth=awsauth,
            headers={"Content-Type": "application/json"}
        )

        if list_response.status_code != 200:
            raise Exception(f"Failed to list snapshots: {list_response.text}")

        response_data = list_response.json()
        snapshots = response_data.get('snapshots', [])
        current_time = datetime.now()
        deletion_results = []

        # Process each snapshot
        for snapshot in snapshots:
            snapshot_name = snapshot.get('snapshot')
            try:
                snapshot_date = parse_date_from_snapshot_name(snapshot_name)

                if snapshot_date and (current_time - snapshot_date).days > 30:
                    # Delete snapshot
                    delete_url = f'https://{host}/_snapshot/{repository}/{snapshot_name}'
                    delete_response = requests.delete(
                        delete_url,
                        auth=awsauth,
                        headers={"Content-Type": "application/json"}
                    )

                    deletion_results.append({
                        'snapshot': snapshot_name,
                        'status': 'deleted' if delete_response.status_code == 200 else 'failed',
                        'response': delete_response.text
                    })
                else:
                    deletion_results.append({
                        'snapshot': snapshot_name,
                        'status': 'skipped',
                        'reason': 'Not older than 30 days or date not found in name'
                    })
            except Exception as e:
                deletion_results.append({
                    'snapshot': snapshot_name,
                    'status': 'error',
                    'error': str(e)
                })

        return {
            'statusCode': 200,
            'body': json.dumps({
                'message': 'Snapshot deletion process completed',
                'results': deletion_results
            })
        }

    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps({
                'message': 'Error in snapshot deletion process',
                'error': str(e)
            })
        }

Nota: Sustituye domain-endpoint por el punto de enlace de tu dominio sin https://, region por tu región y my-snapshot-repo por el nombre de tu repositorio. Se recomienda configurar el tiempo de espera de la función de Lambda en 60 segundos.

Solución de problemas

Realiza las siguientes acciones en función del error que recibas.

Error «No permissions for [cluster:admin/snapshot/create]»

Si has activado un control de acceso detallado en tu dominio de OpenSearch Service, debes conceder a OpenSearch Service acceso al rol de la función de Lambda. Si no concedes acceso, recibirás el siguiente error de permisos:

«"statusCode": 403, "body": "{"message": "Failed to create snapshot", "error": "{\"error\":{\"root_cause\":[{\"type\":\"security_exception\",\"reason\":\"no permissions for [cluster:admin/snapshot/create] and User [name=arn:aws:iam::123456789012:role/service-role/Lambda_ES_Snapshot-role»

Para resolver este problema, ejecuta el siguiente comando para conceder a OpenSearch Service acceso al rol de la función de Lambda:

awscurl \
--access_key ABCDE \
--secret_key EXAMPLESECRET\
--region us-west-2 \
--service es \
-X PUT \
-H "Content-Type: application/json" \
'https://domain-endpoint/_plugins/_security/api/rolesmapping/all_access' \
-d '{"backend_roles": ["arn:aws:iam::account-id:role/service-role/Lambda_AOS_Snapshot-role"], "hosts": [], "users": ["master-user", "arn:aws:iam::account-id:user/second-primary-user" ]}'

Nota: Sustituye ABCDE por tu clave de acceso, EXAMPLESECRET por tu secreto y us-west-2 por tu región. Además, sustituye domain-endpoint por el punto de enlace de tu dominio de OpenSearch Service, account-id por el ID de tu cuenta y Lambda_AOS_Snapshot-role por el rol de tu función de Lambda.

Error «AccessDeniedException»

Si recibes el mensaje de error «AccessDeniedException», debes configurar una relación de confianza para el rol de IAM que accede al bucket de S3. Para solucionar este problema, usa el simulador de política de IAM para identificar qué parte de tu política de IAM debes actualizar.

Error «S3Exception»

Si recibes el mensaje de error «S3Exception: The bucket is in region 'us-west-1'», a continuación debes mover el bucket a la misma región que el dominio de OpenSearch Service.

Error «SignatureDoesNotMatch»

Si recibes el mensaje de error «SignatureDoesNotMatch», significa que tus credenciales de AWS han vencido o has utilizado información incorrecta en tu firma. Mantén tus credenciales de AWS actualizadas y asegúrate de que la región es correcta en tu firma.

Error «not authorized to perform: iam:PassRole»

Si no usas la versión 4 de AWS Signature, recibirás el siguiente mensaje de error:

«Message»:«User: anonymous is not authorized to perform: iam:PassRole on resource: arn:aws:iam::account-id:role/TheSnapshotRole because no resource-based policy allows the iam:PassRole action»

Para solucionar este error, consulta ¿Por qué aparece el error «User: anonymous is not authorized» al intentar acceder al clúster de OpenSearch Service?

Para obtener más información sobre la solución de problemas, consulta ¿Cómo soluciono el error de instantánea manual en mi clúster de OpenSearch Service?

Información relacionada

Unleash the power of Snapshot Management to take automated snapshots using OpenSearch Service (Potenciar la administración de instantáneas para tomar instantáneas automatizadas con OpenSearch Service)

Take manual snapshots and restore in a different domain spanning across various Regions and accounts in OpenSearch Service (Realización de instantáneas manuales y restauración de un dominio diferente que abarque varias regiones y cuentas en OpenSearch Service)

¿Cómo puedo restaurar los datos de un dominio de OpenSearch Service en otra cuenta de AWS?

OFICIAL DE AWSActualizada hace un año