Automatizar encendido y apagado de máquinas EC2 con Lambda AWS

Una buena forma de abaratar costes de infraestructura con aplicaciones que no requieren estar encendidas 24/7, es con la automatización del encendido y apagado de las máquinas EC2 donde tengamos alojada nuestra aplicación. El servicio Lambda y EventBridge permiten hacer esta tarea.

En primer lugar, se ha de crear una nueva función en Lambda, para este post se hará uso de la versión 3.8 de Python. El código quedaría de la siguiente forma:

import boto3
region = 'eu-west-1'
instances = ['id-instancia-ec2']
def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name=region)
    ec2.start_instances(InstanceIds=instances)Lenguaje del código: JavaScript (javascript)

Necesitaremos importar la librería boto3 de Python para trabajar con AWS. En la variable «region» se indicará la zona que tengamos en Amazon, en este caso Irlanda. Y por último, indicaremos una lista de todas las instancias de EC2 que nos interese encender. En caso de querer hacer lo contrario, podemos usar:

import boto3
region = 'eu-west-1'
instances = ['id-instancia-ec2']
def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name=region)
    ec2.stop_instances(InstanceIds=instances)Lenguaje del código: JavaScript (javascript)

La función Lambda creada tiene por defecto únicamente permisos de escritura en el log de Cloudwatch, por lo que será necesario ampliar los permisos del rol para acceder al servicio de EC2. Entrando en la función lambda y accediendo a Configuración > Permisos, haremos clic sobre el rol y se abrirá en una pestaña nueva el servicio IAM con la definición del rol. En la pestaña «Servicios» haciendo clic sobre la política nos abrirá el editor. Ahora solo tendremos que agregar los permisos que faltan, en este caso usaremos el editor JSON quedando la configuración de la siguiente forma:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:eu-west-1:XXXXXXXXXXXX:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:eu-west-1:XXXXXXXXXXXX:log-group:/aws/lambda/encender_ec2:*"
            ]
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": [
                "ec2:StartInstances"
            ],
            "Resource": "arn:aws:ec2:*:*:instance/*"
        },
        {
            "Effect": "Allow",
            "Action": "ec2:DescribeInstances",
            "Resource": "*"
        }
    ]
}Lenguaje del código: JSON / JSON con comentarios (json)

Los dos primeros «statement» vienen creados por defecto, en nuestro caso hemos de agregar los dos siguientes. El primero permite realizar la acción de «StartInstances» (o «StopInstances» según la configuración que nos interese) y aplicará este permiso sobre todas las instancias disponibles. El segundo permite realizar la acción de «DescribeInstances», es decir, listar las instancias EC2 disponibles.

Una vez guardados los permisos, si probamos la función Lambda desde su editor ya podrás comprobar como las máquinas se encienden o apagan tras la ejecución de la función.

Por último, queda automatizar la ejecución de las funciones Lambda. En este escenario queremos tener la aplicación encendida durante una jornada laboral de 8AM a 17PM.

Desde el servicio EventBridge, en el menú izquierdo entraremos en «Reglas» y «Crear regla». Le daremos un nombre, por ejemplo , «cron_start_ec2» y tipo de regla «programar». En este punto AWS permite configurar la periodicidad con una interfaz sencilla donde indicar cada cuantas horas queremos que se ejecute. O bien, para especificaciones más concretas podemos usar una expresión cron. En este caso usaremos la expresión para que se ejecute diariamente a las 7 AM (una hora antes comenzar los empleados su jornada laboral). La expresión quedaría de la siguiente forma:

cron (0, 7, * * ? *)

Es importante tener en cuenta la zona horaria, si los servidores están en Irlanda y usamos hora local, las 7 AM de Irlanda no corresponderá con las 7 AM hora española. Para evitar errores de este tipo, siempre es recomendable seleccionar GMT.

Finalmente, haremos lo propio con la función lambda que detiene el servidor a las 18h y ya tendremos automatizado un proceso que permitirá un ahorro importante en la factura a final de mes.