Desligamento automático e inicialização da instância Amazon EC2

90

Posso iniciar e encerrar automaticamente minha instância da Amazon usando a API da Amazon? Você pode descrever como isso pode ser feito? Idealmente, preciso iniciar a instância e interrompê-la em intervalos de tempo especificados todos os dias.

Massa
fonte
2
O que acontece com os dados da sua instância EC2 quando ela é desligada? Ele persiste ou você precisa reconstruí-lo?
Matthew Lock
Iniciar e encerrar automaticamente a instância usando a API Amazon pode causar perdas de dados nesse evento. Eu recomendaria o Stop & Recover Actions using AWS CloudWatch Alarms
Chetabahana
Em vez da API da Amazon, eu sugiro agendar EC2 Start / Stop usando AWS Lambda , no seu caso custa menos de $ 0,0004 USD / mês.
Chetabahana

Respostas:

102

Caso alguém tropece nessa velha questão, hoje em dia você pode conseguir a mesma coisa adicionando uma programação a um grupo de auto scaling: aumente a quantidade de instâncias em um grupo de auto scaling para 1 em certos momentos e diminua de volta para 0 depois .

E como essa resposta está recebendo muitas visualizações, pensei em criar um link para um guia muito útil sobre isso: Como executar instâncias EC2 em uma programação recorrente com escalonamento automático

Nakedible
fonte
6
Tentei o método descrito no link, e ele realmente inicia / interrompe instâncias nos momentos especificados pelo tutorial. No entanto, percebi no console da web AWS que quando uma instância é iniciada por este método, ela não é iniciada com uma chave (de forma que você pode ssh para ela), e também não parece ter as mesmas coisas que eu instalado na minha micro-instância que eu uso como um teste (não sou um especialista em nuvem, mas acho que isso significa que esta nova instância que é girada não está conectada ao EBS?). Existe uma maneira de iniciar automaticamente e parar a mesma instância em um cronograma?
Kiran K.
@KiranK. isso significa que a nova instância não está anexada ao volume EBS usado atualmente? o que você usou?
Chapéu de palha
26

Você pode tentar usar as ferramentas de API do Amazon EC2 diretamente. Na verdade, você precisa de apenas dois comandos: ec2-start-instances e ec2-stop-instances. Certifique-se de que as variáveis ​​de ambiente, como EC2_HOME, AWS_CREDENTIAL_FILE, EC2_CERT, EC2_PRIVATE_KEY, etc., estejam configuradas corretamente e todas as credenciais AWS, certificados e arquivos de chave privada estejam no local adequado - você pode encontrar mais informações na documentação das ferramentas de API do AWS EC2.

Você pode testar o comando manualmente primeiro e depois, quando tudo funcionar bem, configurar o crontab Unix ou Tarefas agendadas no Windows. Você pode encontrar o exemplo abaixo para o arquivo Linux / etc / crontab (não se esqueça que todas as variáveis ​​de ambiente mencionadas acima precisam estar presentes para o usuário 'sua-conta'.

/etc/crontab
0 8     * * *   your-account ec2-start-instances <your_instance_id>
0 16    * * *   your-account ec2-stop-instances <your_instance_id>
# Your instance will be started at 8am and shutdown at 4pm.

Sou um desenvolvedor do projeto BitNami Cloud, onde empacotamos as ferramentas AWS (incluindo as que mencionei) em um instalador fácil de usar que você pode querer experimentar: BitNami CloudTools pack stack

Danoo
fonte
2
Para isso ainda precisa de outra instância. Porque o desligamento não é o problema, mas a inicialização. O velho ou qualquer coisa não funcionará em um computador morto depois que ele for desligado.
Upul Doluweera
Eu segui essas etapas para configurar as ferramentas AWS CLI em minha instância do AMazon Linux. Parar a instância funciona bem. Mas iniciar uma instância já interrompida dá erro 400, Id da instância não encontrada. Como posso iniciar a instância já parada?
Amol Chakane
17

Eu recomendo que você dê uma olhada no Guia de introdução do EC2 , que mostra como fazer o que você precisa usando as ferramentas de linha de comando do EC2. Você pode facilmente criar um script para um cron job (no Linux / UNIX) ou um trabalho agendado no Windows para chamar os comandos start e stop em um determinado momento.

Se quiser fazer isso a partir de seu próprio código, você pode usar as APIs SOAP ou REST; consulte o Guia do desenvolvedor para obter detalhes.

gareth_bowles
fonte
15

Eu escrevi código em Python, usando a biblioteca Boto, para fazer isso. Você pode ajustar isso para seu próprio uso. Certifique-se de executá-lo como parte de um cron job, e então você será capaz de iniciar ou desligar quantas instâncias forem necessárias durante a execução dos cron jobs.

#!/usr/bin/python
#
# Auto-start and stop EC2 instances
#
import boto, datetime, sys
from time import gmtime, strftime, sleep

# AWS credentials
aws_key = "AKIAxxx"
aws_secret = "abcd"

# The instances that we want to auto-start/stop
instances = [
    # You can have tuples in this format:
    # [instance-id, name/description, startHour, stopHour, ipAddress]
    ["i-12345678", "Description", "00", "12", "1.2.3.4"]
]

# --------------------------------------------

# If its the weekend, then quit
# If you don't care about the weekend, remove these three 
# lines of code below.
weekday = datetime.datetime.today().weekday()
if (weekday == 5) or (weekday == 6):
    sys.exit()

# Connect to EC2
conn = boto.connect_ec2(aws_key, aws_secret)

# Get current hour
hh = strftime("%H", gmtime())

# For each instance
for (instance, description, start, stop, ip) in instances:
    # If this is the hour of starting it...
    if (hh == start):
        # Start the instance
        conn.start_instances(instance_ids=[instance])
        # Sleep for a few seconds to ensure starting
        sleep(10)
        # Associate the Elastic IP with instance
        if ip:
            conn.associate_address(instance, ip)
    # If this is the hour of stopping it...
    if (hh == stop):
        # Stop the instance
        conn.stop_instances(instance_ids=[instance])
Suman
fonte
1
Isso também é possível para ambientes Elastic Beanstalk?
Amol Chakane
5

Se não for de missão crítica - Uma coisa simplista a fazer é agendar o arquivo em lote para executar 'SHUTDOWN' (Windows) às 3 da manhã todos os dias. Assim, pelo menos, você não corre o risco de deixar acidentalmente uma instância indesejada em execução indefinidamente.

Obviamente, essa é apenas metade da história!

AndyM
fonte
5

A empresa para a qual trabalho tinha clientes perguntando regularmente sobre isso, então escrevemos um aplicativo de agendamento EC2 freeware disponível aqui:

http://blog.simple-help.com/2012/03/free-ec2-scheduler/

Ele funciona no Windows e no Mac, permite que você crie várias programações diárias / semanais / mensais e permite que você use filtros correspondentes para incluir facilmente um grande número de instâncias ou incluir aquelas que você adicionar no futuro.

Antônimo
fonte
2

O AWS Data Pipeline está funcionando bem. https://aws.amazon.com/premiumsupport/knowledge-center/stop-start-ec2-instances/

Se desejar excluir dias do início (por exemplo, fim de semana), adicione um objeto ShellCommandPrecondition.

No AWS Console / Data Pipeline, crie um novo pipeline. É mais fácil editar / importar uma definição (JSON)

    {
"objects": [
{
  "failureAndRerunMode": "CASCADE",
  "schedule": {
    "ref": "DefaultSchedule"
  },
  "resourceRole": "DataPipelineDefaultResourceRole",
  "role": "DataPipelineDefaultRole",
  "pipelineLogUri": "s3://MY_BUCKET/log/",
  "scheduleType": "cron",
  "name": "Default",
  "id": "Default"
},
{
  "name": "CliActivity",
  "id": "CliActivity",
  "runsOn": {
    "ref": "Ec2Instance"
  },
  "precondition": {
    "ref": "PreconditionDow"
  },
  "type": "ShellCommandActivity",
  "command": "(sudo yum -y update aws-cli) && (#{myAWSCLICmd})"
},
{
  "period": "1 days",
  "startDateTime": "2015-10-27T13:00:00",
  "name": "Every 1 day",
  "id": "DefaultSchedule",
  "type": "Schedule"
},
{
  "scriptUri": "s3://MY_BUCKET/script/dow.sh",
  "name": "DayOfWeekPrecondition",
  "id": "PreconditionDow",
  "type": "ShellCommandPrecondition"
},
{
  "instanceType": "t1.micro",
  "name": "Ec2Instance",
  "id": "Ec2Instance",
  "type": "Ec2Resource",
  "terminateAfter": "50 Minutes"
}
],
"parameters": [
{
  "watermark": "aws [options] <command> <subcommand> [parameters]",
  "description": "AWS CLI command",
  "id": "myAWSCLICmd",
  "type": "String"
}
 ],
"values": {
"myAWSCLICmd": "aws ec2 start-instances --instance-ids i-12345678 --region eu-west-1"
}
}

Coloque o script Bash a ser baixado e executado como pré-condição em seu balde S3

#!/bin/sh
if [ "$(date +%u)" -lt 6 ]
then exit 0
else exit 1
fi

Ao ativar e executar o pipeline nos dias de fim de semana, o status de integridade do pipeline do console da AWS mostra um erro "ERROR". O script bash retorna um erro (saída 1) e o EC2 não é iniciado. Nos dias 1 a 5, o status é "SAUDÁVEL".

Para interromper o EC2 automaticamente no horário de fechamento do escritório, use o comando AWS CLI diariamente sem a condição prévia.

usuário3526918
fonte
1

Você poderia olhar para Ylastic para fazer isso. A alternativa parece ser ter uma máquina em execução que encerra / inicia outras instâncias usando um cron job ou tarefa agendada.

Obviamente, se você quiser apenas uma instância, esta é uma solução cara, pois uma máquina deve estar sempre em execução e pagar ~ $ 80 por mês para que uma máquina execute tarefas cron não é rentável.

Chris S
fonte
1

O escalonamento automático é limitado a instâncias de encerramento. Se você deseja interromper uma instância e manter o estado do servidor, um script externo é a melhor abordagem.

Você pode fazer isso executando um trabalho em outra instância que esteja funcionando 24 horas por dia, 7 dias por semana, ou pode usar um serviço de terceiros, como Ylastic (mencionado acima) ou Rocket Peak .

Por exemplo, em C #, o código para parar um servidor é bastante simples:

public void stopInstance(string instance_id, string AWSRegion)
        {
            RegionEndpoint myAWSRegion = RegionEndpoint.GetBySystemName(AWSRegion);
            AmazonEC2 ec2 = AWSClientFactory.CreateAmazonEC2Client(AWSAccessKey, AWSSecretKey, myAWSRegion);
            ec2.StopInstances(new StopInstancesRequest().WithInstanceId(instance_id));
        }
MrGreggs
fonte
1

IMHO adicionando uma programação a um grupo de escalonamento automático é a melhor abordagem "semelhante à nuvem", conforme mencionado antes.

Mas caso você não possa encerrar suas instâncias e usar novas, por exemplo, se você tiver Elastic IPs associados a etc.

Você pode criar um script Ruby para iniciar e parar suas instâncias com base em um intervalo de data e hora.

#!/usr/bin/env ruby

# based on https://github.com/phstc/amazon_start_stop

require 'fog'
require 'tzinfo'

START_HOUR = 6 # Start 6AM
STOP_HOUR  = 0 # Stop  0AM (midnight)

conn = Fog::Compute::AWS.new(aws_access_key_id:     ENV['AWS_ACCESS_KEY_ID'],
                             aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'])

server = conn.servers.get('instance-id')

tz = TZInfo::Timezone.get('America/Sao_Paulo')

now = tz.now

stopped_range = (now.hour >= STOP_HOUR && now.hour < START_HOUR)
running_range = !stopped_range

if stopped_range && server.state != 'stopped'
  server.stop
end

if running_range && server.state != 'running'
  server.start

  # if you need an Elastic IP
  # (everytime you stop an instance Amazon dissociates Elastic IPs)
  #
  # server.wait_for { state == 'running' }
  # conn.associate_address server.id, 127.0.0.0
end

Dê uma olhada em amazon_start_stop para criar um agendador gratuitamente usando o Heroku Scheduler .

Pablo Cantero
fonte
1

Embora existam maneiras de fazer isso usando o escalonamento automático, ele pode não ser adequado para todas as ocasiões, pois encerra as instâncias. Os cron jobs nunca funcionarão para uma única instância (embora possam ser perfeitamente usados ​​para situações como interromper uma única instância e agendar outras instâncias ao executar muitas instâncias). Você pode usar chamadas de API como StartInstancesRequest e StopInstancesRequest para conseguir o mesmo, mas novamente você precisa contar com um terceiro recurso. Existem muitos aplicativos para agendar instâncias da AWS com muitos recursos, mas para uma solução simples, eu recomendaria um aplicativo gratuito como o snapleaf.io

Upul Doluweera
fonte
1

Sim, você pode fazer isso usando o AWS Lambda. Você pode selecionar o gatilho no Cloudwatch que é executado em expressões Cron no UTC.

Aqui está um link relacionado https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/

Outra alternativa é usar awsclio que está disponível a partir pip, apt-get, yumou brew, e em seguida, executando aws configurecom suas credenciais exportados do IAM e executar o seguinte script bash, para parar um EC2 que foi marcado com Name: Appnamee Value: Appname Prod. Você pode usar awsclipara marcar suas instâncias ou marcá-las manualmente no console da AWS. aws ec2 stop-instancesinterromperá a instância e jqé usado para filtrar a consulta json e buscar o ID correto da instância usando as tags deaws ec2 describe-instances .

Para verificar se aws configurefoi bem-sucedido e retorna a saída json, execute aws ec2 describe-instancese o ID da instância em execução deve estar lá na saída. Aqui está um exemplo de saída

{
    "Reservations": [
        {
            "Instances": [
                {
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "PublicDnsName": "ec2-xxx.ap-south-1.compute.amazonaws.com",
                    "State": {
                        "Code": xx,
                        "Name": "running"
                    },
                    "EbsOptimized": false,
                    "LaunchTime": "20xx-xx-xxTxx:16:xx.000Z",
                    "PublicIpAddress": "xx.127.24.xxx",
                    "PrivateIpAddress": "xxx.31.3.xxx",
                    "ProductCodes": [],
                    "VpcId": "vpc-aaxxxxx",
                    "StateTransitionReason": "",
                    "InstanceId": "i-xxxxxxxx",
                    "ImageId": "ami-xxxxxxx",
                    "PrivateDnsName": "ip-xxxx.ap-south-1.compute.internal",
                    "KeyName": "node",
                    "SecurityGroups": [
                        {
                            "GroupName": "xxxxxx",
                            "GroupId": "sg-xxxx"
                        }
                    ],
                    "ClientToken": "",
                    "SubnetId": "subnet-xxxx",
                    "InstanceType": "t2.xxxxx",
                    "NetworkInterfaces": [
                        {
                            "Status": "in-use",
                            "MacAddress": "0x:xx:xx:xx:xx:xx",
                            "SourceDestCheck": true,
                            "VpcId": "vpc-xxxxxx",
                            "Description": "",
                            "NetworkInterfaceId": "eni-xxxx",
                            "PrivateIpAddresses": [
                                {
                                    "PrivateDnsName": "ip-xx.ap-south-1.compute.internal",
                                    "PrivateIpAddress": "xx.31.3.xxx",
                                    "Primary": true,
                                    "Association": {
                                        "PublicIp": "xx.127.24.xxx",
                                        "PublicDnsName": "ec2-xx.ap-south-1.compute.amazonaws.com",
                                        "IpOwnerId": "xxxxx"
                                    }
                                }
                            ],
                            "PrivateDnsName": "ip-xxx-31-3-xxx.ap-south-1.compute.internal",
                            "Attachment": {
                                "Status": "attached",
                                "DeviceIndex": 0,
                                "DeleteOnTermination": true,
                                "AttachmentId": "xxx",
                                "AttachTime": "20xx-xx-30Txx:16:xx.000Z"
                            },
                            "Groups": [
                                {
                                    "GroupName": "xxxx",
                                    "GroupId": "sg-xxxxx"
                                }
                            ],
                            "Ipv6Addresses": [],
                            "OwnerId": "xxxx",
                            "PrivateIpAddress": "xx.xx.xx.xxx",
                            "SubnetId": "subnet-xx",
                            "Association": {
                                "PublicIp": "xx.xx.xx.xxx",
                                "PublicDnsName": "ec2-xx.ap-south-1.compute.amazonaws.com",
                                "IpOwnerId": "xxxx"
                            }
                        }
                    ],
                    "SourceDestCheck": true,
                    "Placement": {
                        "Tenancy": "default",
                        "GroupName": "",
                        "AvailabilityZone": "xx"
                    },
                    "Hypervisor": "xxx",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xxx",
                            "Ebs": {
                                "Status": "attached",
                                "DeleteOnTermination": true,
                                "VolumeId": "vol-xxx",
                                "AttachTime": "20xxx-xx-xxTxx:16:xx.000Z"
                            }
                        }
                    ],
                    "Architecture": "x86_64",
                    "RootDeviceType": "ebs",
                    "RootDeviceName": "/dev/xxx",
                    "VirtualizationType": "xxx",
                    "Tags": [
                        {
                            "Value": "xxxx centxx",
                            "Key": "Name"
                        }
                    ],
                    "AmiLaunchIndex": 0
                }
            ],
            "ReservationId": "r-xxxx",
            "Groups": [],
            "OwnerId": "xxxxx"
        }
    ]
}

O script bash seguinte é stop-ec2.shem /home/centos/cron-scripts/que é inspirado a partir deste post SO

(instance=$(aws ec2 describe-instances | jq '.Reservations[].Instances | select(.[].Tags[].Value | startswith("Appname Prod") ) |  select(.[].Tags[].Key == "Appname") |  {InstanceId: .[].InstanceId, PublicDnsName: .[].PublicDnsName, State: .[].State, LaunchTime: .[].LaunchTime, Tags: .[].Tags}  | [.]' | jq -r .[].InstanceId) && aws ec2 stop-instances --instance-ids ${instance} )

Execute o arquivo usando sh /home/centos/cron-scripts/stop-ec2.she verifique se a instância EC2 foi interrompida. Para depurar executeaws ec2 describe-instances | jq '.Reservations[].Instances | select(.[].Tags[].Value | startswith("Appname Prod") ) | select(.[].Tags[].Key == "Appname") | {InstanceId: .[].InstanceId, PublicDnsName: .[].PublicDnsName, State: .[].State, LaunchTime: .[].LaunchTime, Tags: .[].Tags} | [.]' | jq -r .[].InstanceId e veja se ele retorna o ID de instância correto que foi marcado.

Então, na crontab -eseguinte linha pode ser adicionado

30 14 * * * sh /home/centos/cron-scripts/stop-ec2.sh >> /tmp/stop

que registrará a saída /tmp/stop. A 30 14 * * *é a expressão cron UTC que você pode verificar https://crontab.guru/. Da mesma forma, substituir por aws ec2 start-instancespode iniciar uma instância.

devssh
fonte
0

Acho que a pergunta inicial foi um pouco confusa. Depende do que o Pasta precisa: 1. iniciar / encerrar (armazenamento de instância) - Auto Scaling é a solução certa (resposta da Nakedible) 2. iniciar / parar a instância de inicialização do EBS - Auto Scaling não vai ajudar, eu uso scripts remotos agendados (ex. , ec2 CLI).

lk7777
fonte
-8

Você não pode fazer isso automaticamente, ou pelo menos não sem alguma programação e manipulação de API nos arquivos de script. Se você deseja uma solução confiável para parar, reiniciar e gerenciar suas imagens (presumivelmente para controlar os custos em seu ambiente), você pode querer dar uma olhada no LabSlice . Aviso Legal: Eu trabalho para esta empresa.

Simon em LabSlice-com
fonte