Apagado automático e inicio de la instancia Amazon EC2

90

¿Puedo iniciar y finalizar automáticamente mi instancia de Amazon con la API de Amazon? ¿Puede describir cómo se puede hacer esto? Idealmente, necesito iniciar la instancia y detenerla en intervalos de tiempo específicos todos los días.

Pasta
fuente
2
¿Qué sucede con los datos de su instancia EC2 cuando se apaga? ¿Persiste o tienes que reconstruirlo de nuevo?
Matthew Lock
Iniciar y finalizar automáticamente la instancia mediante la API de Amazon puede provocar pérdidas de datos en ese evento. Recomendaría las acciones de detención y recuperación mediante alarmas de AWS CloudWatch
Chetabahana
En lugar de la API de Amazon, sugiero programar el inicio / parada de EC2 con AWS Lambda , en su caso, le costará menos de $ 0,0004 USD / mes.
Chetabahana

Respuestas:

102

En caso de que alguien se tropiece con esta vieja pregunta, hoy en día puede lograr lo mismo agregando un cronograma a un grupo de autoescalado: aumente la cantidad de instancias en un grupo de autoescalado a 1 en ciertos momentos y luego vuelva a disminuirlo a 0 .

Y dado que esta respuesta está obteniendo muchas vistas, pensé en vincularme a una guía muy útil sobre esto: Ejecución de instancias EC2 en un programa recurrente con Auto Scaling

Desnudo
fuente
6
Probé el método descrito en el enlace y, de hecho, inicia / detiene las instancias en los momentos especificados en el tutorial. Sin embargo, noté en la consola web de AWS que cuando se inicia una instancia con este método, no se inicia con una clave (de modo que pueda acceder a ella), y tampoco parece tener las mismas cosas que yo. instalado en mi microinstancia que utilizo como prueba (no soy un experto en la nube, pero creo que esto significa que esta nueva instancia que se activa no está conectada a EBS). ¿Hay alguna manera de iniciar y detener la misma instancia en un horario?
Kiran K.
@KiranK. ¿Eso significa que la nueva instancia no se adjunta al volumen de EBS que se usa actualmente? que usaste
Sombrero de Paja
26

Puede intentar utilizar las herramientas API de Amazon EC2 directamente. En realidad, solo necesita dos comandos: ec2-start-instances y ec2-stop-instances. Asegúrese de que las variables de entorno como EC2_HOME, AWS_CREDENTIAL_FILE, EC2_CERT, EC2_PRIVATE_KEY, etc.estén configuradas correctamente y que todas las credenciales, certificados y archivos de claves privadas de AWS estén en la ubicación adecuada; puede encontrar más información en la documentación de las herramientas API de AWS EC2.

Puede probar el comando a mano primero y luego, cuando todo funcione bien, configurar crontab de Unix o Tareas programadas en Windows. Puede encontrar el ejemplo a continuación para el archivo Linux / etc / crontab (no olvide que todas las variables de entorno mencionadas anteriormente deben estar presentes para el usuario 'su-cuenta'.

/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.

Soy un desarrollador del proyecto BitNami Cloud, donde empaquetamos las herramientas de AWS (incluidas las que mencioné) en un instalador gratuito y fácil de usar que quizás desee probar: BitNami CloudTools pack stack

danoo
fuente
2
Para esto todavía necesita tener otra instancia. Porque apagar no es el problema sino la puesta en marcha. Crone o cualquier cosa no se ejecutará en una computadora muerta después de que se haya apagado.
Upul Doluweera
Seguí estos pasos para configurar las herramientas de la AWS CLI en mi instancia AMazon Linux. Detener la instancia funciona bien. Pero al iniciar una instancia ya detenida se produce un error 400, no se encontró el ID de instancia. ¿Cómo puedo iniciar una instancia ya detenida?
Amol Chakane
17

Le recomiendo que consulte la Guía de inicio de EC2 , que le muestra cómo hacer lo que necesita utilizando las herramientas de línea de comandos de EC2. Puede escribir esto fácilmente en un trabajo cron (en Linux / UNIX) o en un trabajo programado en Windows para llamar a los comandos de inicio y detención en un momento dado.

Si desea hacer esto desde su propio código, puede usar las API de SOAP o REST; consulte la Guía para desarrolladores para obtener más detalles.

gareth_bowles
fuente
15

Escribí código en Python, usando la biblioteca Boto, para hacer esto. Puede ajustar esto para su propio uso. Asegúrese de ejecutar esto como parte de un trabajo cron, y luego podrá iniciar o apagar tantas instancias como necesite durante la ejecución de los trabajos cron.

#!/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
fuente
1
¿Es esto posible también para los entornos Elastic Beanstalk?
Amol Chakane
5

Si no es una misión crítica: una cosa simplista es programar el archivo por lotes para que se ejecute 'APAGADO' (ventanas) a las 3 a. M. Todos los días. Entonces, al menos, no corre el riesgo de dejar accidentalmente una instancia no deseada ejecutándose indefinidamente.

¡Obviamente esto es solo la mitad de la historia!

AndyM
fuente
5

La empresa para la que trabajo tenía clientes que preguntaban regularmente sobre esto, por lo que hemos escrito una aplicación de programación EC2 gratuita disponible aquí:

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

Funciona en Windows y Mac, le permite crear múltiples programas diarios / semanales / mensuales y le permite usar filtros coincidentes para incluir fácilmente una gran cantidad de instancias o incluye las que agregue en el futuro.

Antónimo
fuente
2

AWS Data Pipeline funciona bien. https://aws.amazon.com/premiumsupport/knowledge-center/stop-start-ec2-instances/

Si desea excluir días del inicio (por ejemplo, fin de semana) agregue un objeto ShellCommandPrecondition.

En AWS Console / Data Pipeline, cree una nueva canalización. Es más fácil editar / importar una definición (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 el script de Bash para descargarlo y ejecutarlo como condición previa en su bucket de S3

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

Al activar y ejecutar la canalización los días de fin de semana, el estado de salud de la canalización de la consola de AWS muestra un "ERROR" engañoso. El script bash devuelve un error (salida 1) y EC2 no se inicia. En los días 1 a 5, el estado es "SALUDABLE".

Para detener EC2 automáticamente a la hora de cierre de la oficina, utilice el comando de la AWS CLI diariamente sin condiciones previas.

usuario3526918
fuente
1

Podrías mirar a Ylastic para hacer esto. La alternativa parece ser tener una máquina en ejecución que apague / inicie otras instancias usando un trabajo cron o una tarea programada.

Obviamente, si solo desea una instancia, esta es una solución costosa, ya que una máquina siempre debe estar en funcionamiento, y pagar ~ $ 80 al mes por una máquina para ejecutar trabajos cron no es rentable.

Chris S
fuente
1

AutoScaling se limita a terminar instancias. Si desea detener una instancia y conservar el estado del servidor, el mejor enfoque es un script externo.

Puede hacer esto ejecutando un trabajo en otra instancia que se ejecute las 24 horas del día, los 7 días de la semana, o puede usar un servicio de terceros como Ylastic (mencionado anteriormente) o Rocket Peak .

Por ejemplo, en C #, el código para detener un servidor es bastante sencillo:

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));
        }
Mr Greggs
fuente
1

En mi humilde opinión, agregar un horario a un grupo de escalado automático es el mejor enfoque "similar a una nube" como se mencionó anteriormente.

Pero en caso de que no pueda terminar sus instancias y usar otras nuevas, por ejemplo, si tiene IP elásticas asociadas, etc.

Puede crear un script Ruby para iniciar y detener sus instancias en función de un rango de fecha y 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

Eche un vistazo a amazon_start_stop para crear un programador de forma gratuita con Heroku Scheduler .

Pablo Cantero
fuente
1

Aunque hay formas de lograr esto mediante el escalado automático, es posible que no sea adecuado para todas las ocasiones, ya que finaliza las instancias. Los trabajos cron nunca funcionarán para una sola instancia (aunque se puede usar perfectamente para situaciones como detener una sola instancia y programar otras instancias cuando se ejecutan muchas instancias). Puede usar llamadas a la API como StartInstancesRequest y StopInstancesRequest para lograr lo mismo, pero nuevamente debe confiar en un tercer recurso. Hay muchas aplicaciones para programar instancias de AWS con muchas características, pero para una solución simple, recomendaría una aplicación gratuita como snapleaf.io

Upul Doluweera
fuente
1

Sí, puede hacerlo con AWS Lambda. Puede seleccionar el disparador en Cloudwatch que se ejecuta en expresiones Cron en UTC.

Aquí hay un enlace relacionado https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/

Otra alternativa es el uso awsclique está disponible en pip, apt-get, yumo brew, y luego correr aws configurecon sus credenciales exportados de IAM y ejecutar el siguiente script bash, para detener una EC2 que ha sido etiquetado con Name: Appnamey Value: Appname Prod. Puede usar awsclipara etiquetar sus instancias o etiquetarlas manualmente desde la consola de AWS. aws ec2 stop-instancesdetendrá la instancia y jqse usa para filtrar la consulta json y obtener el ID de instancia correcto usando las etiquetas de aws ec2 describe-instances.

Para verificar que aws configurefue exitoso y devuelve la salida json, ejecute aws ec2 describe-instancesy su ID de instancia en ejecución debe estar allí en la salida. Aquí hay una salida de muestra

{
    "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"
        }
    ]
}

La siguiente secuencia de comandos bash se stop-ec2.shen /home/centos/cron-scripts/la que se inspira de este 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} )

Ejecute el archivo utilizando sh /home/centos/cron-scripts/stop-ec2.shy verifique que la instancia EC2 se detenga. Para depurar, ejecute 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 .[].InstanceIdy vea que devuelve el ID de instancia correcto que se ha etiquetado.

Luego en crontab -ela siguiente línea se puede agregar

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

que registrará la salida /tmp/stop. La 30 14 * * *es la expresión cron UTC que puede registrar https://crontab.guru/. De manera similar, reemplazar con aws ec2 start-instancespuede iniciar una instancia.

devssh
fuente
0

Creo que la pregunta inicial fue un poco confusa. Depende de lo que Pasta necesite: 1.lanzar / terminar (almacenamiento de instancias) - Auto Scaling es la solución correcta (la respuesta de Nakedible) 2.Iniciar / detener la instancia de arranque de EBS - Auto Scaling no ayudará, utilizo scripts programados remotos (es decir , ec2 CLI).

lk7777
fuente
-8

No puede hacer esto automáticamente, o al menos no sin algo de programación y manipulación de API en archivos de script. Si desea una solución confiable para detener, reiniciar y administrar sus imágenes (presumiblemente para controlar los costos en su entorno), es posible que desee mirar LabSlice . Descargo de responsabilidad: trabajo para esta empresa.

Simon en LabSlice-com
fuente