Arrêt automatique et démarrage de l'instance Amazon EC2

90

Puis-je démarrer et terminer automatiquement mon instance Amazon à l'aide de l'API Amazon? Pouvez-vous décrire comment cela peut être fait? Je dois idéalement démarrer l'instance et l'arrêter à des intervalles de temps spécifiés chaque jour.

Pâtes
la source
2
Qu'arrive-t-il aux données de votre instance EC2 lorsqu'elle est arrêtée? Est-ce qu'il persiste ou devez-vous le reconstruire à nouveau?
Matthew Lock
Le démarrage et l'arrêt automatiques de l'instance à l'aide de l'API Amazon peuvent entraîner des pertes de données lors de cet événement. Je recommanderais les actions d'arrêt et de récupération à l'aide des alarmes AWS CloudWatch
Chetabahana
Au lieu de l'API Amazon, je suggère de planifier EC2 Start / Stop à l'aide d'AWS Lambda , dans votre cas, cela vous coûte moins de 0,0004 USD / mois.
Chetabahana

Réponses:

102

Juste au cas où quelqu'un trébucherait sur cette vieille question, de nos jours, vous pouvez réaliser la même chose en ajoutant un calendrier à un groupe de mise à l'échelle automatique: augmentez le nombre d'instances dans un groupe de mise à l'échelle automatique à 1 à certains moments et réduisez-le à 0 par la suite. .

Et comme cette réponse suscite beaucoup de vues, j'ai pensé à créer un lien vers un guide très utile à ce sujet: Exécuter des instances EC2 selon un calendrier récurrent avec Auto Scaling

Nakedible
la source
6
J'ai essayé la méthode décrite dans le lien, et elle démarre / arrête effectivement les instances aux moments spécifiés par le tutoriel. Cependant, j'ai remarqué dans la console Web AWS que lorsqu'une instance est démarrée par cette méthode, elle ne démarre pas avec une clé (de sorte que vous pouvez y ssh), et elle ne semble pas non plus avoir les mêmes éléments que moi installé sur ma micro-instance que j'utilise comme test (je ne suis pas un expert du cloud, mais je pense que cela signifie que cette nouvelle instance qui est lancée n'est pas connectée à l'EBS?) Existe-t-il un moyen de démarrer et arrêter la même instance selon un calendrier?
Kiran K.
@KiranK. cela signifie-t-il que la nouvelle instance n'est pas attachée au volume EBS actuellement utilisé? qu'avez-vous utilisé?
Chapeau de paille le
26

Vous pouvez essayer d'utiliser directement les outils d'API Amazon EC2. Il n'y a vraiment que deux commandes dont vous avez besoin: ec2-start-instances et ec2-stop-instances. Assurez-vous que les variables d'environnement telles que EC2_HOME, AWS_CREDENTIAL_FILE, EC2_CERT, EC2_PRIVATE_KEY, etc. sont correctement configurées et que toutes les informations d'identification AWS, les certificats et les fichiers de clé privée sont au bon emplacement - vous pouvez trouver plus d'informations dans la documentation des outils d'API AWS EC2.

Vous pouvez d'abord tester la commande à la main, puis, lorsque tout fonctionne correctement, configurer le crontab Unix ou les tâches planifiées sous Windows. Vous pouvez trouver l'exemple ci-dessous pour le fichier Linux / etc / crontab (n'oubliez pas que toutes les variables d'environnement mentionnées ci-dessus doivent être présentes pour l'utilisateur 'your-account'.

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

Je suis développeur pour le projet BitNami Cloud, où nous emballons les outils AWS (y compris ceux que j'ai mentionnés) dans un programme d'installation gratuit et facile à utiliser que vous voudrez peut-être essayer: BitNami CloudTools pack stack

danoo
la source
2
Pour cela, vous devez encore avoir une autre instance. Parce que l'arrêt n'est pas le problème mais le démarrage. Crone ou quoi que ce soit ne fonctionnera pas dans un ordinateur mort après qu'il a été arrêté.
Upul Doluweera
J'ai suivi ces étapes pour configurer les outils AWS CLI sur mon instance AMazon Linux. L'arrêt de l'instance fonctionne bien. Mais le démarrage d'une instance déjà arrêtée donne une erreur 400, ID d'instance introuvable. Comment puis-je démarrer une instance déjà arrêtée?
Amol Chakane
17

Je vous recommande de consulter le guide de démarrage EC2 , qui vous montre comment faire ce dont vous avez besoin à l'aide des outils de ligne de commande EC2. Vous pouvez facilement créer un script dans une tâche cron (sous Linux / UNIX) ou une tâche planifiée sous Windows pour appeler les commandes de démarrage et d'arrêt à un moment donné.

Si vous souhaitez le faire à partir de votre propre code, vous pouvez utiliser les API SOAP ou REST; consultez le Guide du développeur pour plus de détails.

gareth_bowles
la source
15

J'ai écrit du code en Python, en utilisant la bibliothèque Boto, pour ce faire. Vous pouvez régler cela pour votre propre usage. Assurez-vous de l'exécuter dans le cadre d'une tâche cron, et vous pourrez ensuite démarrer ou arrêter autant d'instances que vous le souhaitez pendant l'exécution des tâches 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
la source
1
Est-ce également possible pour les environnements Elastic Beanstalk?
Amol Chakane
5

Si ce n'est pas essentiel à la mission - Une chose simpliste à faire est de planifier le fichier de commandes pour qu'il exécute «SHUTDOWN» (Windows) à 3 heures du matin tous les jours. Alors au moins, vous ne courez pas le risque de laisser accidentellement une instance indésirable en cours d'exécution indéfiniment.

Évidemment, ce n'est que la moitié de l'histoire!

AndyM
la source
5

La société pour laquelle je travaille avait des clients qui posent régulièrement des questions à ce sujet, nous avons donc écrit une application de planification EC2 gratuite disponible ici:

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

Il fonctionne sur Windows et Mac, vous permet de créer plusieurs horaires quotidiens / hebdomadaires / mensuels et vous permet d'utiliser des filtres correspondants pour inclure facilement un grand nombre d'instances ou inclure celles que vous ajoutez à l'avenir.

Antonyme
la source
2

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

Si vous souhaitez exclure des jours du début (par exemple le week-end), ajoutez un objet ShellCommandPrecondition.

Dans AWS Console / Data Pipeline, créez un nouveau pipeline. Il est plus facile de modifier / importer une définition (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"
}
}

Placez le script Bash à télécharger et à exécuter comme condition préalable dans votre compartiment S3

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

Lors de l'activation et de l'exécution du pipeline les jours de week-end, l'état de santé du pipeline de la console AWS lit une "ERREUR" trompeuse. Le script bash renvoie une erreur (exit 1) et EC2 n'est pas démarré. Les jours 1 à 5, l'état est «SAIN».

Pour arrêter EC2 automatiquement à l'heure de fermeture du bureau, utilisez la commande AWS CLI quotidiennement sans condition préalable.

user3526918
la source
1

Vous pouvez consulter Ylastic pour ce faire. L'alternative semble avoir une machine en cours d'exécution qui arrête / démarre d'autres instances à l'aide d'une tâche cron ou d'une tâche planifiée.

De toute évidence, si vous ne voulez qu'une seule instance, c'est une solution coûteuse, car une machine doit toujours être en cours d'exécution, et payer ~ 80 $ par mois pour qu'une machine exécute des tâches cron n'est pas rentable.

Chris S
la source
1

La mise à l'échelle automatique est limitée à l'arrêt des instances. Si vous souhaitez arrêter une instance et conserver l'état du serveur, un script externe est la meilleure approche.

Vous pouvez le faire en exécutant une tâche sur une autre instance qui fonctionne 24h / 24 et 7j / 7 ou vous pouvez utiliser un service tiers tel que Ylastic (mentionné ci-dessus) ou Rocket Peak .

Par exemple en C #, le code pour arrêter un serveur est assez simple:

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
la source
1

IMHO l'ajout d'un calendrier à un groupe de mise à l'échelle automatique est la meilleure approche de type «cloud» comme mentionné précédemment.

Mais au cas où vous ne pouvez pas mettre fin à vos instances et en utiliser de nouvelles, par exemple si vous avez des adresses IP Elastic associées à etc.

Vous pouvez créer un script Ruby pour démarrer et arrêter vos instances en fonction d'une plage de dates et d'heures.

#!/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

Jetez un œil à amazon_start_stop pour créer un planificateur gratuitement à l'aide de Heroku Scheduler .

Pablo Cantero
la source
1

Même s'il existe des moyens d'y parvenir en utilisant la mise à l'échelle automatique, il peut ne pas convenir à toutes les occasions car il met fin aux instances. Les tâches Cron ne fonctionneront jamais pour une seule instance (bien qu'elles puissent parfaitement être utilisées dans des situations telles que l'arrêt d'une seule instance et la planification d'autres instances lors de l'exécution de plusieurs instances). Vous pouvez utiliser des appels d'API comme StartInstancesRequest et StopInstancesRequest pour obtenir la même chose, mais encore une fois, vous devez vous fier à une troisième ressource. Il existe de nombreuses applications pour planifier des instances AWS avec de nombreuses fonctionnalités, mais pour une solution simple, je recommanderais une application gratuite comme snapleaf.io

Upul Doluweera
la source
1

Oui, vous pouvez le faire à l'aide d'AWS Lambda. Vous pouvez sélectionner le déclencheur dans Cloudwatch qui s'exécute sur des expressions Cron à UTC.

Voici un lien connexe https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/

Une autre alternative consiste à utiliser awsclice qui est disponible à partir depip de , apt-get, yumou brew, en cours d' exécution et puis aws configureavec vos informations d' identification exportées de l' AIM et l' exécution du script bash suivant, pour arrêter une EC2 qui a été marqué avec Name: Appnameet Value: Appname Prod. Vous pouvez utiliser awsclipour baliser vos instances ou les baliser manuellement à partir de la console AWS. aws ec2 stop-instancesarrêtera l'instance et jqest utilisé pour filtrer la requête json et récupérer l'ID d'instance correct à l'aide des balises deaws ec2 describe-instances .

Pour vérifier que cela aws configurea réussi et renvoie la sortie json, exécutez aws ec2 describe-instanceset votre ID d'instance en cours d'exécution doit être présent dans la sortie. Voici un exemple de sortie

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

Le script bash suivant est stop-ec2.shdans ce /home/centos/cron-scripts/qui est inspiré de ce SO poste

(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} )

Exécutez le fichier à l'aide de sh /home/centos/cron-scripts/stop-ec2.shet vérifiez que l'instance EC2 est arrêtée. Pour déboguer, exécutez 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 .[].InstanceIdet voyez qu'il renvoie l'ID d'instance correct qui a été balisé.

Ensuite, dans crontab -ela ligne suivante peut être ajouté

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

qui enregistrera la sortie dans /tmp/stop. Il 30 14 * * *s'agit de l'expression cron UTC que vous pouvez enregistrer https://crontab.guru/. De même en remplaçant paraws ec2 start-instances peut démarrer une instance.

devssh
la source
0

Je pense que la question initiale était un peu déroutante. Cela dépend de ce dont Pasta a besoin: 1. lancer / terminer (magasin d'instance) - Auto Scaling est la bonne solution (réponse de Nakedible) 2. démarrer / arrêter l'instance de démarrage EBS - Auto Scaling n'aidera pas, j'utilise des scripts planifiés à distance (ie , CLI ec2).

lk7777
la source
-8

Vous ne pouvez pas le faire automatiquement, ou du moins pas sans programmation et manipulation d'API dans les fichiers de script. Si vous voulez une solution fiable pour arrêter, redémarrer et gérer vos images (vraisemblablement pour contrôler les coûts dans votre environnement), vous pouvez vous tourner vers LabSlice . Avertissement: Je travaille pour cette entreprise.

Simon chez LabSlice-com
la source