Breaking

Post Top Ad

Your Ad Spot

martes, 25 de junio de 2019

Automatización de la gestión de AWS EC2 con Python y Boto3

Introducción

En este artículo, demostraré el uso de Python junto con el Kit de desarrollo de software (SDK) de Boto3 Amazon Web Services (AWS), que permite a las personas con conocimientos de programación de Python utilizar las complejas API de REST de AWS para administrar sus recursos de nube. Debido a la inmensidad de la API REST de AWS y los servicios de nube asociados, me centraré solo en el servicio de cómputo en la nube elástica de AWS (EC2).
Estos son los temas que trataré:
  • Iniciando una instancia de EC2
  • Deteniendo una instancia de EC2
  • Terminando una instancia de EC2
  • Copia de seguridad de una instancia de EC2 creando una imagen
  • Creando una instancia de EC2 desde una imagen
  • Programación de copias de seguridad y limpieza utilizando cron en un servidor y AWS Lambda

Dependencias y configuración del entorno

Para comenzar, tendré que crear un usuario en mi cuenta de AWS que tenga acceso programático a las API de REST. Para simplificar, otorgaré a este usuario derechos de administrador, pero tenga en cuenta que es solo para simplificar la creación de este tutorial. Si lo sigue, debe consultar las políticas de seguridad de TI de su organización antes de utilizar a este usuario en un entorno de producción.
Paso 1: En mi consola de AWS debo ir a la sección IAM en el menú de servicios, luego hacer clic en el enlace Usuarios y, finalmente, hacer clic en el botón Agregar usuario que me lleva a la pantalla que se muestra a continuación. En esta pantalla, le doy al usuario el nombre "boto3-usuario" y reviso la casilla de acceso programático antes de hacer clic en el botón siguiente.
Paso 2: En la pantalla de permisos, hago clic en el mosaico Adjuntar políticas existentes directamentey, a continuación, selecciono la casilla de verificación de Acceso de administrador antes de hacer clic en el siguiente, como se muestra a continuación.
Paso 3: haga clic en siguiente para no agregar ninguna etiqueta opcional.
Paso 4: reviso al usuario que está a punto de crearse y luego hago clic en Crear usuario .
Paso 5: Finalmente, descargo las credenciales como un archivo CSV y las guardo.
A continuación, necesito instalar las bibliotecas de Python 3 necesarias de forma local dentro de un entorno virtual, así:
$ python -m venv venv
$ source venv/bin/activate
(venv)$ pip install boto3 pprint awscli
Por último, configuro las credenciales para la biblioteca boto3 utilizando la biblioteca awscliasegurándome de agregar las credenciales para la clave de acceso y la clave secreta que descargué en el paso 5 anterior.
$ aws configure
AWS Access Key ID [****************3XRQ]: **************  
AWS Secret Access Key [****************UKjF]: ****************  
Default region name [None]:  
Default output format [None]:  

Creación y instancia de EC2 para trabajar

En esta sección voy a ver cómo crear una sesión de boto3 específica de la región de AWS, así como crear una instancia de un cliente EC2 utilizando el objeto de sesión activa. Luego, al utilizar ese cliente de EC2 boto3, interactuaré con las instancias de EC2 de esa región que administran el inicio, el cierre y la terminación.
Para crear una instancia de EC2 para este artículo, tomo los siguientes pasos:
Paso 1: Hago clic en el enlace EC2 dentro del menú Servicios para abrir el Panel de EC2 y luego hago clic en el botón Iniciar instancia en el centro de la pantalla.
Paso 2: En la página Elegir imagen de máquina de Amazon (AMI), hago clic en el botón Seleccionarjunto a la AMI de Amazon Linux.
Paso 3: Acepte el tipo de instancia t2.micro predeterminado y haga clic en el botón Revisar y lanzar .
Paso 4: en la página de revisión, amplío la sección Etiquetas y hago clic en Editar etiquetas para agregar etiquetas para Nombre y Copia de seguridad , luego hago clic en Iniciar revisión y en Iniciarnuevamente para volver a la página de revisión antes de finalmente hacer clic en el botón Iniciar para iniciar la instancia.
Ahora tengo una instancia de EC2 en ejecución, como se muestra a continuación.

Sesión Boto3 y Cliente

¡Por fin puedo escribir algo de código! Empiezo por crear un archivo vacío, un módulo de Python, llamado awsutils.py y, en la parte superior, importo la biblioteca y boto3luego defino una función que creará un objeto Session específico de la región .
# awsutils

import boto3

def get_session(region):  
    return boto3.session.Session(region_name=region)
Si enciendo mi intérprete de Python e importo el módulo que acabo de crear arriba, puedo usar la nueva get_sessionfunción para crear una sesión en la misma región que mi instancia de EC2, y luego crear una instancia de un objeto EC2.Client , así:
>>> import awsutils
>>> session = awsutils.get_session('us-east-1')
>>> client = session.client('ec2')
Luego puedo usar este objeto cliente de EC2 para obtener una descripción detallada de la instancia pprinty hacer que las cosas sean un poco más fáciles de ver para ver el resultado de llamar describe_instancesal clientobjeto.
>>> import pprint
>>> pprint.pprint(client.describe_instances())
...
Estoy omitiendo la salida porque es bastante detallada, pero sé que contiene un diccionario con una Reservationsentrada, que es una lista de datos que describen las instancias de EC2 en esa región y ResponseMetadatasobre la solicitud que se acaba de realizar a la API REST de AWS.

Recuperando detalles de la instancia de EC2

También puedo usar este mismo describe_instancesmétodo junto con un Filterparámetro para filtrar la selección por valores de etiqueta. Por ejemplo, si quiero obtener mi instancia recientemente creada con la etiqueta Nombre con un valor de 'instancia de demostración', se vería así:
>>> demo = client.describe_instances(Filters=[{'Name': 'tag:Name', 'Values': ['demo-instance']}])
>>> pprint.pprint(demo)
...
Hay muchas formas de filtrar la salida describe_instancesy le remito a los documentos oficialespara más detalles.

Iniciar y detener una instancia de EC2

Para detener la instancia de demostración, utilizo el stop_instancesmétodo del clientobjeto, que instalé anteriormente, y le proporcioné el ID de instancia como un parámetro de lista de entrada única al InstanceIdsargumento como se muestra a continuación:
>>> instance_id = demo['Reservations'][0]['Instances'][0]['InstanceId']
>>> instance_id
'i-0c462c48bc396bdbb'  
>>> pprint.pprint(client.stop_instances(InstanceIds=[instance_id]))
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '579',
                                      'content-type': 'text/xml;charset=UTF-8',
                                      'date': 'Sat, 22 Dec 2018 19:26:30 GMT',
                                      'server': 'AmazonEC2'},
                      'HTTPStatusCode': 200,
                      'RequestId': 'e04a4a64-74e4-442f-8293-261f2ca9433d',
                      'RetryAttempts': 0},
 'StoppingInstances': [{'CurrentState': {'Code': 64, 'Name': 'stopping'},
                        'InstanceId': 'i-0c462c48bc396bdbb',
                        'PreviousState': {'Code': 16, 'Name': 'running'}}]
La salida del último comando indica que la llamada al método está deteniendo la instancia. Si recupero la demo-instancia e imprimo la copia State, ahora veo que está detenida.
>>> demo = client.describe_instances(Filters=[{'Name': 'tag:Name', 'Values': ['demo-instance']}])
>>> demo['Reservations'][0]['Instances'][0]['State']
{'Code': 80, 'Name': 'stopped'}
Para iniciar la misma copia de seguridad de la instancia, hay un método de complemento llamado start_instancesque funciona de manera similar al stop_instancesmétodo que se muestra a continuación.
>>> pprint.pprint(client.start_instances(InstanceIds=[instance_id]))
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '579',
                                      'content-type': 'text/xml;charset=UTF-8',
                                      'date': 'Sat, 22 Dec 2018 19:37:02 GMT',
                                      'server': 'AmazonEC2'},
                      'HTTPStatusCode': 200,
                      'RequestId': '21c65902-6665-4137-9023-43ac89f731d9',
                      'RetryAttempts': 0},
 'StartingInstances': [{'CurrentState': {'Code': 0, 'Name': 'pending'},
                        'InstanceId': 'i-0c462c48bc396bdbb',
                        'PreviousState': {'Code': 80, 'Name': 'stopped'}}]}
La salida inmediata del comando es que está pendiente de inicio. Ahora, cuando recupero la instancia e imprimo su estado, muestra que se está ejecutando de nuevo.
>>> demo = client.describe_instances(Filters=[{'Name': 'tag:Name', 'Values': ['demo-instance']}])
>>> demo['Reservations'][0]['Instances'][0]['State']
{'Code': 16, 'Name': 'running'}

Enfoque alternativo para obtener, iniciar y detener

Además de la EC2.Clientclase con la que he estado trabajando hasta ahora, también hay una clase EC2.Instance que es útil en casos como este, donde solo necesito preocuparme por una instancia a la vez.
A continuación, uso el sessionobjeto generado anteriormente para obtener un objeto de recurso EC2, que luego puedo usar para recuperar e instanciar un Instanceobjeto para mi instancia de demostración.
>>> ec2 = session.resource('ec2')
>>> instance = ec2.Instance(instance_id)
En mi opinión, un gran beneficio de usar la Instanceclase es que está trabajando con objetos reales en lugar de un punto en el tiempo, la representación de la instancia, pero pierde la capacidad de poder realizar acciones en varias instancias a la vez que el EC2.Clientclase proporciona
Por ejemplo, para ver el estado de la instancia de demostración que acabo de crear una instancia arriba, es tan simple como esto:
>>> instance.state
{'Code': 16, 'Name': 'running'}
La Instanceclase tiene muchos métodos útiles, dos de los cuales son startstopque usaré para iniciar y detener mis instancias, como:
>>> pprint.pprint(instance.stop())
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '579',
                                      'content-type': 'text/xml;charset=UTF-8',
                                      'date': 'Sat, 22 Dec 2018 19:58:25 GMT',
                                      'server': 'AmazonEC2'},
                      'HTTPStatusCode': 200,
                      'RequestId': 'a2f76028-cbd2-4727-be3e-ae832b12e1ff',
                      'RetryAttempts': 0},
 'StoppingInstances': [{'CurrentState': {'Code': 64, 'Name': 'stopping'},
                        'InstanceId': 'i-0c462c48bc396bdbb',
                        'PreviousState': {'Code': 16, 'Name': 'running'}}]}
Después de esperar alrededor de un minuto para que se detenga por completo ... luego reviso el estado nuevamente:
>>> instance.state
{'Code': 80, 'Name': 'stopped'}
Ahora puedo empezar de nuevo.
>>> pprint.pprint(instance.start())
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '579',
                                      'content-type': 'text/xml;charset=UTF-8',
                                      'date': 'Sat, 22 Dec 2018 20:01:01 GMT',
                                      'server': 'AmazonEC2'},
                      'HTTPStatusCode': 200,
                      'RequestId': '3cfc6061-5d64-4e52-9961-5eb2fefab2d8',
                      'RetryAttempts': 0},
 'StartingInstances': [{'CurrentState': {'Code': 0, 'Name': 'pending'},
                        'InstanceId': 'i-0c462c48bc396bdbb',
                        'PreviousState': {'Code': 80, 'Name': 'stopped'}}]}
Luego comprobando el estado nuevamente después de un corto tiempo ...
>>> instance.state
{'Code': 16, 'Name': 'running'}

Creación de una imagen de copia de seguridad de una instancia de EC2.

Un tema importante en la administración del servidor es crear copias de seguridad para recurrir en caso de que un servidor se corrompa. En esta sección, voy a demostrar cómo crear una copia de seguridad de imagen de máquina de Amazon (AMI) de mi instancia de demostración, que AWS almacenará en su Servicio de almacenamiento simple (S3). Más tarde, se puede usar para recrear esa instancia de EC2, de la misma manera que usé la AMI inicial para crear la instancia de demostración.
Para comenzar, mostraré cómo usar la EC2.Clientclase y su create_imagemétodo para crear una imagen AMI de la instancia de demostración al proporcionar el ID de la instancia y un nombre descriptivo para la instancia.
>>> import datetime
>>> date = datetime.datetime.utcnow().strftime('%Y%m%d')
>>> date
'20181221'  
>>> name = f"InstanceID_{instance_id}_Image_Backup_{date}"
>>> name
'InstanceID_i-0c462c48bc396bdbb_Image_Backup_20181221'  
>>> name = f"InstanceID_{instance_id}_Backup_Image_{date}"
>>> name
'InstanceID_i-0c462c48bc396bdbb_Backup_Image_20181221'  
>>> pprint.pprint(client.create_image(InstanceId=instance_id, Name=name))
{'ImageId': 'ami-00d7c04e2b3b28e2d',
 'ResponseMetadata': {'HTTPHeaders': {'content-length': '242',
                                      'content-type': 'text/xml;charset=UTF-8',
                                      'date': 'Sat, 22 Dec 2018 20:13:55 GMT',
                                      'server': 'AmazonEC2'},
                      'HTTPStatusCode': 200,
                      'RequestId': '7ccccb1e-91ff-4753-8fc4-b27cf43bb8cf',
                      'RetryAttempts': 0}}
De manera similar, puedo usar el método de la Instanceclase create_imagepara realizar la misma tarea, que devuelve una instancia de una EC2.Imageclase que es similar a la EC2.Instanceclase.
>>> image = instance.create_image(Name=name + '_2')

Etiquetado de imágenes e instancias de EC2

Una característica muy poderosa, pero extremadamente simple, de las instancias EC2 y las imágenes AMI es la capacidad de agregar etiquetas personalizadas. Puede agregar etiquetas tanto a través de la consola de administración de AWS, como mostré al crear la instancia de demostración con las etiquetas Nombre y BackUp, así como mediante programación con boto3 y la API REST de AWS.
Dado que EC2.Instancetodavía tengo un objeto flotando en la memoria en mi intérprete de Python, lo usaré para mostrar las etiquetas de la instancia de demostración.
>>> instance.tags
[{'Key': 'BackUp', 'Value': ''}, {'Key': 'Name', 'Value': 'demo-instance'}]
Tanto la clase EC2.Instancecomo la EC2.Imageclase tienen un conjunto de create_tagsmétodos que funcionan de manera idéntica para agregar etiquetas a sus recursos representados. A continuación, muestro la adición de una etiqueta RemoveOn a la imagen creada anteriormente, que está emparejada con una fecha en la que se debe eliminar. El formato de fecha utilizado es "YYYYMMDD".
>>> image.create_tags(Tags=[{'Key': 'RemoveOn', 'Value': remove_on}])
[ec2.Tag(resource_id='ami-081c72fa60c8e2d58', key='RemoveOn', value='20181222')]
Nuevamente, lo mismo se puede lograr con la EC2.Clientclase al proporcionar una lista de ID de recursos, pero con el cliente puede etiquetar imágenes e instancias de EC2 al mismo tiempo, si lo desea, especificando sus ID en el parámetro de create_tagsfunción Resource , como :
>>> pprint.pprint(client.create_tags(Resources=['ami-00d7c04e2b3b28e2d'], Tags=[{'Key': 'RemoveOn', 'Value': remove_on}]))
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '221',
                                      'content-type': 'text/xml;charset=UTF-8',
                                      'date': 'Sat, 22 Dec 2018 20:52:39 GMT',
                                      'server': 'AmazonEC2'},
                      'HTTPStatusCode': 200,
                      'RequestId': '645b733a-138c-42a1-9966-5c2eb0ca3ba3',
                      'RetryAttempts': 0}}

Creación de una instancia de EC2 a partir de una imagen de respaldo

Me gustaría comenzar esta sección dándole algo en que pensar. Póngase en la incómoda mentalidad de un administrador del sistema, o incluso peor, un desarrollador que pretende ser un administrador de sistemas porque el producto en el que están trabajando no tiene uno (advertencia ... ese soy yo), y uno de sus servidores EC2 tiene corromperse
Eeek! Es un momento difícil ... ahora necesita averiguar qué tipo de sistema operativo, tamaño y servicios se estaban ejecutando en el servidor inactivo ... hurgar en la configuración e instalación del servidor base, además de las aplicaciones que pertenecen a él, y rezar todo sale correctamente
¡Uf! Respire y relájese porque estoy a punto de mostrarle cómo volver a funcionar rápidamente, además de ... alerta de spoiler ... Voy a jalar estos comandos únicos del intérprete de Python a un conjunto de scripts ejecutables en El fin para que puedas seguir modificando y poniendo en uso.
Ok, con ese ejercicio mental fuera del camino, déjame volver al trabajo. Para crear una instancia de EC2 a partir de una ID de imagen, utilizo el método de la EC2.Clientclase run_instancesy especifico la cantidad de instancias que se iniciarán y el tipo de instancia que se ejecutará.
>>> pprint.pprint(client.run_instances(ImageId='ami-081c72fa60c8e2d58', MinCount=1, MaxCount=1, InstanceType='t2.micro'))
...
Estoy omitiendo la salida de nuevo debido a su verbosidad. Por favor, eche un vistazo a los documentos oficiales para el método run_instances , ya que hay muchos parámetros para elegir para personalizar exactamente cómo ejecutar la instancia.

Eliminar imágenes de copia de seguridad

Idealmente, estaría haciendo imágenes de copia de seguridad en un intervalo bastante frecuente (es decir, al menos diariamente) y junto con todas estas copias de seguridad vienen tres cosas, una de las cuales es bastante buena y las otras dos son algo problemáticas. En el lado bueno de las cosas, estoy haciendo instantáneas de los estados conocidos de mi servidor EC2, lo que me da un punto en el tiempo para retroceder si las cosas van mal. Sin embargo, en el lado malo, estoy creando desorden en mis cubos de S3 y acumulando cargos con cada copia de seguridad adicional que guardo en almacenamiento.
Una forma de mitigar las desventajas del desorden y el aumento de los costos de almacenamiento es eliminar las imágenes de respaldo una vez transcurrido un tiempo predeterminado y, ahí es donde las etiquetas que creé anteriormente me salvarán. Puedo consultar mis imágenes de copia de seguridad de EC2 y ubicar las que tienen una etiqueta RemoveOn particular y luego eliminarlas.
Puedo comenzar utilizando el describe_imagesmétodo en la EC2.Clientinstancia de clase junto con un filtro para la etiqueta 'RemoveOn' para obtener todas las imágenes que etiqueté para eliminar en una fecha determinada.
>>> remove_on = '201812022'
>>> images = client.describe_images(Filters=[{'Name': 'tag:RemoveOn', 'Values': [remove_on]}])
A continuación, repaso todas las imágenes y llamo al método del cliente deregister_imagepasándole la ID de la imagen iterada y listo. No más imágenes.
>>> remove_on = '201812022'
>>> for img in images['Images']:
...     client.deregister_image(ImageId=img['ImageId'])

Terminando una instancia de EC2

Bueno, habiendo cubierto el inicio, la detención, la creación y la eliminación de imágenes de copia de seguridad y el lanzamiento de una instancia de EC2 desde una imagen de copia de seguridad, estoy llegando al final de este tutorial. Ahora, todo lo que queda por hacer es limpiar mis instancias de demostración llamando a la EC2.Clientclase terminate_instancesy pasando los ID de instancia para terminar. De nuevo, lo usaré describe_instancescon un filtro para el nombre de la instancia de demostración para obtener los detalles y obtener su ID de instancia. Entonces puedo usarlo terminate_instancespara deshacerme de él para siempre.
Nota : Sí, esto es algo para siempre, así que ten mucho cuidado con este método.
>>> demo = client.describe_instances(Filters=[{'Name': 'tag:Name', 'Values': ['demo-instance']}])
>>> pprint.pprint(client.terminate_instances(InstanceIds=[instance_id]))
{'ResponseMetadata': {'HTTPHeaders': {'content-type': 'text/xml;charset=UTF-8',
                                      'date': 'Sat, 22 Dec 2018 22:14:20 GMT',
                                      'server': 'AmazonEC2',
                                      'transfer-encoding': 'chunked',
                                      'vary': 'Accept-Encoding'},
                      'HTTPStatusCode': 200,
                      'RequestId': '78881a08-0240-47df-b502-61a706bfb3ab',
                      'RetryAttempts': 0},
 'TerminatingInstances': [{'CurrentState': {'Code': 32,
                                            'Name': 'shutting-down'},
                           'InstanceId': 'i-0c462c48bc396bdbb',
                           'PreviousState': {'Code': 16, 'Name': 'running'}}]}

Reuniendo cosas para una secuencia de comandos de automatización

Ahora que he recorrido estas funcionalidades emitiendo comandos uno por uno con el intérprete de shell de Python (que recomiendo a los lectores que hagan al menos una vez por su cuenta para experimentar con las cosas) reuniré todo en dos scripts separados llamados ec2backup .py y amicleanup.py.
La secuencia de comandos ec2backup.py simplemente consultará todas las instancias de EC2 disponibles que tengan la etiqueta BackUp y luego creará una imagen AMI de respaldo para cada una, mientras las etiquetará con una etiqueta RemoveOn con un valor de 3 días en el futuro.
# ec2backup.py

from datetime import datetime, timedelta  
import awsutils

def backup(region_id='us-east-1'):  
    '''This method searches for all EC2 instances with a tag of BackUp
       and creates a backup images of them then tags the images with a
       RemoveOn tag of a YYYYMMDD value of three UTC days from now
    '''
    created_on = datetime.utcnow().strftime('%Y%m%d')
    remove_on = (datetime.utcnow() + timedelta(days=3)).strftime('%Y%m%d')
    session = awsutils.get_session(region_id)
    client = session.client('ec2')
    resource = session.resource('ec2')
    reservations = client.describe_instances(Filters=[{'Name': 'tag-key', 'Values': ['BackUp']}])
    for reservation in reservations['Reservations']:
        for instance_description in reservation['Instances']:
            instance_id = instance_description['InstanceId']
            name = f"InstanceId({instance_id})_CreatedOn({created_on})_RemoveOn({remove_on})"
            print(f"Creating Backup: {name}")
            image_description = client.create_image(InstanceId=instance_id, Name=name)
            images.append(image_description['ImageId'])
            image = resource.Image(image_description['ImageId'])
            image.create_tags(Tags=[{'Key': 'RemoveOn', 'Value': remove_on}, {'Key': 'Name', 'Value': name}])

if __name__ == '__main__':  
    backup()
La siguiente es la secuencia de comandos amicleanup.py, que consulta todas las imágenes AMI que tienen una etiqueta RemoveOn igual a la fecha del día en que se ejecutó en el formulario "YYYYMMDD" y las elimina.
# amicleanup.py

from datetime import datetime  
import awsutils

def cleanup(region_id='us-east-1'):  
    '''This method searches for all AMI images with a tag of RemoveOn
       and a value of YYYYMMDD of the day its ran on then removes it
    '''
    today = datetime.utcnow().strftime('%Y%m%d')
    session = awsutils.get_session(region_id)
    client = session.client('ec2')
    resource = session.resource('ec2')
    images = client.describe_images(Filters=[{'Name': 'tag:RemoveOn', 'Values': [today]}])
    for image_data in images['Images']:
        image = resource.Image(image_data['ImageId'])
        name_tag = [tag['Value'] for tag in image.tags if tag['Key'] == 'Name']
        if name_tag:
            print(f"Deregistering {name_tag[0]}")
        image.deregister()

if __name__ == '__main__':  
    cleanup()

Implementación Cron

Una forma relativamente sencilla de implementar la funcionalidad de estos dos scripts sería programar dos tareas cron en un servidor Linux para ejecutarlas. En un ejemplo a continuación, he configurado una tarea cron para que se ejecute todos los días a las 11PM para ejecutar el script ec2backup.py y luego otra a las 11:30 PM para ejecutar el script amicleanup.py.
0 23 * * * /path/to/venv/bin/python /path/to/ec2backup.py  
30 23 * * * /path/to/venv/bin/python /path/to/amicleanup.py  

Implementación de AWS Lambda

Una solución más elegante es usar AWS Lambda para ejecutar los dos como un conjunto de funciones. Hay muchos beneficios de usar AWS Lambda para ejecutar código, pero en este caso de uso de ejecutar un par de funciones de Python para crear y eliminar imágenes de copia de seguridad, las más relevantes son la alta disponibilidad y evitar el pago de recursos inactivos. Estos dos beneficios se logran mejor cuando se compara el uso de Lambda con la ejecución de los dos trabajos cron descritos en la sección anterior.
Si tuviera que configurar mis dos trabajos cron para que se ejecuten en un servidor existente, ¿qué sucede si ese servidor se cae? No solo tengo el dolor de cabeza de tener que hacer una copia de seguridad de ese servidor, sino que también corro la posibilidad de perder una ejecución programada de las tareas cron que controlan el proceso de copia de seguridad y limpieza del servidor EC2. Este no es un problema con AWS Lambda, ya que está diseñado con redundancia para garantizar una disponibilidad extremadamente alta.
El otro beneficio principal de no tener que pagar por los recursos inactivos se comprende mejor en un ejemplo en el que podría haber creado una instancia solo para administrar estos dos scripts que se ejecutan una vez al día. Este método no solo cae bajo el posible defecto de disponibilidad del último elemento, sino que se ha aprovisionado una máquina virtual completa para ejecutar dos scripts una vez al día que constituyen una cantidad muy pequeña de tiempo de cálculo y muchos recursos desperdiciados inactivos. Este es un caso principal para usar AWS Lambda para mejorar la eficiencia operativa.
Otra eficiencia operativa que resulta del uso de Lambda es no tener que perder tiempo manteniendo un servidor dedicado.
Para crear una función de AWS Lambda para las copias de seguridad de imagen de instancia de EC2, siga estos pasos:
Paso 1. En el menú Servicio, haga clic en Lambda dentro de la sección Calcular.
Paso 2. Haz clic en el botón Crear función .
Paso 3. Seleccione la opción Autor desde cero , escriba "ec2backup" como nombre de la función, seleccione Python 3.6 de las opciones de tiempo de ejecución, luego agregue el usuario boto3 para el rol y haga clic en Crear función como se muestra a continuación:
Paso 4. En el diseñador, seleccione CloudWatch Events y agregue un trabajo cron del cron(0 11 * ? * *)que hará que la función se ejecute todos los días a las 11PM.
Paso 5. En el editor de código agrega el siguiente código:
import boto3  
import os  
from datetime import datetime, timedelta

def get_session(region, access_id, secret_key):  
    return boto3.session.Session(region_name=region,
                                aws_access_key_id=access_id,
                                aws_secret_access_key=secret_key)

def lambda_handler(event, context):  
    '''This method searches for all EC2 instances with a tag of BackUp
       and creates a backup images of them then tags the images with a
       RemoveOn tag of a YYYYMMDD value of three UTC days from now
    '''
    created_on = datetime.utcnow().strftime('%Y%m%d')
    remove_on = (datetime.utcnow() + timedelta(days=3)).strftime('%Y%m%d')
    session = get_session(os.getenv('REGION'),
                          os.getenv('ACCESS_KEY_ID'),
                          os.getenv('SECRET_KEY'))
    client = session.client('ec2')
    resource = session.resource('ec2')
    reservations = client.describe_instances(Filters=[{'Name': 'tag-key', 'Values': ['BackUp']}])
    for reservation in reservations['Reservations']:
        for instance_description in reservation['Instances']:
            instance_id = instance_description['InstanceId']
            name = f"InstanceId({instance_id})_CreatedOn({created_on})_RemoveOn({remove_on})"
            print(f"Creating Backup: {name}")
            image_description = client.create_image(InstanceId=instance_id, Name=name)
            image = resource.Image(image_description['ImageId'])
            image.create_tags(Tags=[{'Key': 'RemoveOn', 'Value': remove_on}, {'Key': 'Name', 'Value': name}])
Paso 6. En la sección debajo del editor de código, agregue algunas variables de entorno.
  • REGIÓN con un valor de la región de las instancias de EC2 para respaldar que es us-east-1 en este ejemplo
  • ACCESS KEY ID con el valor de la clave de acceso de la sección donde se configuró el usuario de boto3
  • SECRET_KEY con el valor de la clave secreta de la sección donde se configuró el usuario de boto3
Paso 7. Haz clic en el botón Guardar en la parte superior de la página.
Para la funcionalidad de limpieza de la imagen, siga los mismos pasos con los siguientes cambios.
Paso 3. Le doy un nombre de "amicleanup"
Paso 4. Utilizo una configuración de tiempo ligeramente diferente cron(30 11 * ? * *)para correr a las 11:30 PM
Paso 5. Usa la siguiente función de limpieza:
import boto3  
from datetime import datetime  
import os

def get_session(region, access_id, secret_key):  
    return boto3.session.Session(region_name=region,
                                aws_access_key_id=access_id,
                                aws_secret_access_key=secret_key)

def lambda_handler(event, context):  
    '''This method searches for all AMI images with a tag of RemoveOn
       and a value of YYYYMMDD of the day its ran on then removes it
    '''
    today = datetime.utcnow().strftime('%Y%m%d')
    session = get_session(os.getenv('REGION'),
                          os.getenv('ACCESS_KEY_ID'),
                          os.getenv('SECRET_KEY'))
    client = session.client('ec2')
    resource = session.resource('ec2')
    images = client.describe_images(Filters=[{'Name': 'tag:RemoveOn', 'Values': [today]}])
    for image_data in images['Images']:
        image = resource.Image(image_data['ImageId'])
        name_tag = [tag['Value'] for tag in image.tags if tag['Key'] == 'Name']
        if name_tag:
            print(f"Deregistering {name_tag[0]}")
        image.deregister()

Conclusión

En este artículo he cubierto cómo utilizar la biblioteca Boto3 de AWS Python SDK para interactuar con los recursos de EC2. Demuestro cómo automatizar las tareas de administración operativa para la creación de copias de seguridad de imágenes AMI para instancias de EC2 y la posterior limpieza de esas imágenes de copias de seguridad usando trabajos cron programados en un servidor dedicado o utilizando AWS Lambda.
Si está interesado en aprender a usar Boto y el Servicio de almacenamiento simple (S3) de AWS, consulte el artículo de Scott Robinson aquí en StackAbuse.
Como siempre, gracias por leer y no tenga miedo de comentar o criticar a continuación.

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

Post Top Ad

Your Ad Spot

Páginas