AWS Partner Network (APN) Blog – Brasil

Automatizando o Start/Stop das suas Instâncias EC2

Por Angelo Carvalho e Glauber Gallego, Partner Solution Architects

Dentre as muitas vantagens da computação em nuvem, uma das principais é o provisionamento sob demanda. O cliente provisiona recursos, como servidores e storage, somente quando eles são realmente necessários, pagando somente pelo que utiliza. Na maioria dos casos, os ambientes de desenvolvimento e qualidade, só são necessários em horário comercial. Algumas vezes isso também é verdade para ambientes de produção. Um bom exemplo disso são os ERPs em empresas que não operam fora do horário de expediente.

Considerando que um mês tem em média 30.5 dias, chegamos a um total de 732 horas, sendo 192 horas úteis. Considerando que os seus servidores ficarão ligados somente em horário comercial, você poderia ter uma economia aproximada de até 73% com o custo dos servidores EC2, caso os mantenha desligados no momento em que não são necessários. Importante lembrar que esta economia é referente somente ao EC2. Os custos com o block storage (EBS) não param quando as suas instâncias EC2 são desligadas.

Existem várias maneiras de se agendar o ligar/desligar dos servidores. Alguns parceiros da AWS oferecem excelentes produtos para isso. Se você procura por uma solução mais completa, faça uma pesquisa na web ou consulte o nosso marketplace em: https://aws.amazon.com/marketplace.

Se você procura uma solução mais simples para fazer este agendamento, pode utilizar o AWS Lambda para isso. O AWS Lambda permite a execução de funções escritas em Java, Node.js, C#, e Python. Você pode usar o Lambda para criar, executar e agendar desde funções simples até aplicações completas. Estamos disponibilizando duas funções que podem ser utilizadas para agendar o start/stop dos seus servidores. Siga as instruções a seguir para criar e agendar a execução das funções:

1) Abra o AWS console e escolha uma região que possua o serviço AWS Lambda. Neste tutorial iremos escolher a Região Virgínia;
2) Clique no botão: “Create a Lambda Function”. Selecione o blueprint “Blank Function”;
3) Na tela “Configure Triggers”, simplesmente clique “Next”. Podemos configurar o agendamento mais tarde;
4) Dê um nome para a sua função. Vamos começar pela função que inicia as instâncias. Neste tutorial usaremos o nome “start_ec2_instances”;
5) Escolha Python 2.7 como Runtime;
6) Copie e cole o conteúdo da função abaixo;

import boto3
import sys, traceback
from datetime import datetime
from time import sleep

def start_ec2_instances():
    start_time = datetime.now()

    # starting ec2 client
    ec2_client = boto3.client('ec2')

    regions = ec2_client.describe_regions()

    for region in regions['Regions']:
        try:
            print("Region: " + str(region['RegionName']))
            ec2_client = boto3.client('ec2', region_name=region['RegionName'])
            instances = ec2_client.describe_instances()
            instanceIds = list()
            
            for reservation in instances['Reservations']:
                for instance in reservation['Instances']:
                    if instance['State']['Name'] == "stopped" and not instance['Tags'] is None : 
                        for tag in instance['Tags']:
                            try:
                                if tag['Key'] == 'ScheduledStartStop' and tag['Value'] == 'True'    :
                                    instanceIds.append(instance['InstanceId'])
                            except:
                                print "Not expected error: ", traceback.print_exc()
                      
            if len(instanceIds) > 0 : 
                print "Starting instances: " + str(instanceIds)
                ec2_client.start_instances(InstanceIds=instanceIds)                                                   
                                                            
        except:
            print "Not expected error:", traceback.print_exc()
                                                           
    end_time = datetime.now()
    took_time = end_time - start_time
    print "Total time of execution: " + str(took_time)    

def lambda_handler(event, context):
    print('Starting instances... ')
    start_ec2_instances()

 

7) No campo “Role”, selecione a opção “Create a Custom Role”;
8) Escolha a opção “Create a new IAM Role” para o campo “IAM Role” e dê um nome para a sua Role. Neste tutorial usaremos o nome “start_stop_instances” e vamos reutilizar posteriormente esta Role para a função que pára as instâncias;
9) Clique em “View Policy Document”, depois em “Edit”. Copie e cole o conteúdo da policy abaixo:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstances",
        "ec2:DescribeRegions",
        "ec2:StartInstances",
        "ec2:StopInstances"
      ],   
      "Resource": "*"
    }	
  ]
}

10) Altere o Timeout para 5 minutos;
11) Clique “Next”, e depois em “Create Function”;
12) Clique no botão “Test” para testar a função.
13) Se a função rodou sem erros, é hora de criar o agendamento;
14) Clique na aba “Triggers”, em em “Add Trigger”;
15) Selecione a opção “CloudWatch Events – Schedule”;
16) Dê um nome para a sua regra. Neste tutorial, usaremos o nome “Start_Instances”;
17) Coloque uma expressão cron no campo “Schedule expression” que represente os dias e horários que você deseja executar a sua função. Para rodar de segunda a sexta feira às 8 da manhã, use a expressão “cron(0 10 ? * MON-FRI *)”. Perceba que a expressão usa o fuso horário UTC. Como atualmente (horário de verão) temos uma diferença de duas horas, usaremos 10 em vez de 8 para representar a hora de início;
18) Clique em submit e pronto, a sua função já está agendada;
19) A função acima só atuará em instâncias que possuam a Tag “ScheduledStartStop” com o valor “True”. Logo, adicione esta tag nas instâncias que você deseja que sejam iniciadas/paradas automaticamente;

Agora que você já configurou a sua primeira função Lambda, basta repetir os passos acima e criar a função que pára as instâncias, mas usando o script abaixo e alterando o horário do agendamento:

import boto3
import sys, traceback
from datetime import datetime
from time import sleep

def stop_ec2_instances():
    start_time = datetime.now()

    # starting ec2 client
    ec2_client = boto3.client('ec2')

    regions = ec2_client.describe_regions()

    for region in regions['Regions']:
        try:
            print("Region: " + str(region['RegionName']))
            ec2_client = boto3.client('ec2', region_name=region['RegionName'])
            instances = ec2_client.describe_instances()
            instanceIds = list()
            
            for reservation in instances['Reservations']:
                for instance in reservation['Instances']:
                    if instance['State']['Name'] == "running" and not instance['Tags'] is None : 
                        for tag in instance['Tags']:
                            try:
                                if tag['Key'] == 'ScheduledStartStop' and tag['Value'] == 'True'    :
                                    instanceIds.append(instance['InstanceId'])
                            except:
                                print "Not expected error: ", traceback.print_exc()
                      
            if len(instanceIds) > 0 : 
                print "Stopping instances: " + str(instanceIds)
                ec2_client.stop_instances(InstanceIds=instanceIds, Force=False)                                                   
                                                            
        except:
            print "Not expected error:", traceback.print_exc()
                                                           
    end_time = datetime.now()
    took_time = end_time - start_time
    print "Total time of execution: " + str(took_time)    

def lambda_handler(event, context):
    print('Stopping instances... ')
    stop_ec2_instances()

Pronto! Agora é só aproveitar a economia na sua próxima fatura mensal da AWS!