Usando ASG Lifecycle hooks para disparar funciones Lambda

1 minute read

AWS ASG Lifecycle hooks


Recientemente necesitaba ejecutar algunas acciones después que una instancia EC2 fuese creada por una Auto Scaling Group. Al principio pensé en usar el userdata pero necesitaba crear unas alarmas en CloudWatch basadas en la misma instancia, y estas alarmas debían ser creadas dinámicamente como se hacían previamente con Terraform.

Lifecycle hooks

Los Auto Scaling Groups tienen Lifecycle hooks que puedes usar para disparar funciones lambdas al momento de iniciar o terminar una instancia para ejecutar acciones basadas en los datos contenidos en estos Lifecycle hooks. Por ejemplo puedes crear una regla de CloudWatch para usar el mensaje del evento y obtener la identificación de la instancia o el campo metadata del lifecycle hook. Un ejemplo de cómo luce este mensaje se muestra a continuación:

{
    "EC2InstanceId": "i-0030f3ac294a5764a",
    "AutoScalingGroupName": "sync-service",
    "LifecycleActionToken": "802cc943-c45a-c8c8-b25d-111222333440",
    "LifecycleHookName": "sync-service-StatusCheckFailed-0-launching-hook",
    "NotificationMetadata": {
        "EvaluationPeriods": 5,
        "Missing_data": "breaching",
        "AlarmActions": "arn:aws:sns:us-east-1:111111111111:sns-topic",
        "AlarmDescription": "The instance has not passed both instance and system status checks",
        "Namespace": "AWS/EC2",
        "Period": 60,
        "ComparisonOperator": "GreaterThanThreshold",
        "AlarmName": "sync-status-check",
        "Statistic": "Average",
        "Threshold": 0,
        "MetricName": "StatusCheckFailed"
    },
    

Aquí NotificationMetadata contiene un JSON con la definición de la alarma la cual será consumida por la función lambda para crearla.

Disparando la función lambda usando un evento de CloudWatch

Puedes hacer que CloudWatch responda a eventos del Auto Scaling Group y disparar un función lambda para pasar el mensaje.

AWS Lambda console

Función Lambda

Aquí coloco un ejemplo de la función lambda que obtiene el id de la instancia y el campo metadata del lifecycle:

import boto3
import json
import logging

# Create AWS clients
cw = boto3.client('cloudwatch')

LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)

# Retrieves instance id from CloudWatch event
def get_instance_id(event):
    try:
        return event['detail']['EC2InstanceId']
    except KeyError as err:
        LOGGER.error(err)
        return False

def get_metadata(event):
    try:
        return event['detail']['NotificationMetadata']
    except KeyError as err:
        LOGGER.error(err)
        return False

def lambda_handler(event, context):

    session = boto3.session.Session()
    instanceid = get_instance_id(event)
    metadata = get_metadata(event)
    
    LOGGER.info("instance-id: %s" % instanceid)
    LOGGER.info("metadata: %s" % metadata)

    # Create Metric
    cw.put_metric_alarm(
    AlarmName="%s-%s" % (metadata['AlarmName'], instanceid),
    AlarmDescription= metadata['AlarmDescription'],
    ActionsEnabled=True,
    AlarmActions=[
        metadata['AlarmActions']
    ],
    MetricName=metadata['MetricName'],
    Namespace=metadata['Namespace'],
    Statistic=metadata['Statistic'],
    Dimensions=[
        {
            'Name': 'InstanceId',
            'Value': instanceid
        },
    ],
    Period=metadata['Period'],
    EvaluationPeriods=metadata['EvaluationPeriods'],
    Threshold=metadata['Threshold'],
    TreatMissingData=metadata['Missing_data'],
    ComparisonOperator=metadata['ComparisonOperator']
    )


IAM Roles y Policies

Recuerda crear el ROLE y adjuntarle las policies necesarias a to función lambda.

Referencias:

Tags:

Categories:

Updated:

Leave a Comment