简体   繁体   English

自动关闭并启动Amazon EC2实例

[英]Auto Shutdown and Start Amazon EC2 Instance

Can I automatically start and terminate my Amazon instance using Amazon API? 我可以使用Amazon API自动启动和终止我的Amazon实例吗? Can you please describe how this can be done? 你能描述一下如何做到这一点吗? I ideally need to start the instance and stop the instance at specified time intervals every day. 理想情况下,我需要启动实例并每天以指定的时间间隔停止实例。

Just in case somebody stumbles on this ye old question, nowadays you can achieve the same thing by adding a schedule to an auto scaling group: increase the amount of instances in an auto scaling group to 1 at certain times and decrease it back to 0 afterwards. 为了防止有人在这个旧问题上遇到麻烦,现在你可以通过向自动缩放组添加一个时间表来实现同样的目的:在某些时间将自动缩放组中的实例数量增加到1并在之后将其减少到0 。

And since this answer is getting a lot of views, I thought to link to a very helpful guide about this: Running EC2 Instances on a Recurring Schedule with Auto Scaling 由于这个答案得到了很多观点,我想链接到一个非常有用的指南: 使用Auto Scaling在循环计划上运行EC2实例

You can try using the Amazon EC2 API tools directly. 您可以尝试直接使用Amazon EC2 API工具。 There are really only two commands you need: ec2-start-instances and ec2-stop-instances. 实际上只需要两个命令:ec2-start-instances和ec2-stop-instances。 Make sure that environment variables such as EC2_HOME, AWS_CREDENTIAL_FILE, EC2_CERT, EC2_PRIVATE_KEY, etc. are properly configured and all AWS credentials, certificate and private key files are in proper location - you can find more info in the AWS EC2 API tools documentation. 确保正确配置了EC2_HOME,AWS_CREDENTIAL_FILE,EC2_CERT,EC2_PRIVATE_KEY等环境变量,并且所有AWS凭证,证书和私钥文件都位于正确的位置 - 您可以在AWS EC2 API工具文档中找到更多信息。

You can test the command by hand first and then, when everything works fine, configure Unix crontab or Scheduled Tasks on Windows. 您可以先手动测试命令,然后在一切正常时,在Windows上配置Unix crontab或Scheduled Tasks。 You can find the example below for the Linux /etc/crontab file (do not forget that all those environment variables mentioned above need to be present for 'your-account' user. 您可以在下面找到Linux / etc / crontab文件的示例(不要忘记,上面提到的所有环境变量都需要为“您的帐户”用户提供。

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

I am a developer for the BitNami Cloud project, where we package the AWS tools (including the ones I mentioned) in a free, easy to use installer that you may want to try: BitNami CloudTools pack stack 我是BitNami Cloud项目的开发人员,我们将AWS工具(包括我提到的工具)打包在一个您可能想要尝试的免费,易于使用的安装程序中: BitNami CloudTools包堆栈

I recommend you take a look at the EC2 Getting Started Guide , which shows you how to do what you need using the EC2 command line tools. 我建议您查看EC2入门指南 ,该指南向您展示如何使用EC2命令行工具执行所需操作。 You can easily script this into a cron job (on Linux / UNIX) or scheduled job on Windows to call the start and stop commands at a given time. 您可以轻松地将此脚本编写到cron作业(在Linux / UNIX上)或Windows上的预定作业,以在给定时间调用启动和停止命令。

If you want to do this from your own code, you can use the SOAP or REST APIs; 如果要从自己的代码中执行此操作,可以使用SOAP或REST API; see the Developer Guide for details. 请参阅开发者指南了解详细信息

I wrote code in Python, using the Boto library, to do this. 我使用Boto库在Python中编写代码来执行此操作。 You can adjust this for your own use. 您可以根据自己的需要进行调整。 Make sure to run this as part of a cron job, and then you will be able to start-up or shut-down as many instances as you need during the cron jobs run. 确保将其作为cron作业的一部分运行,然后您将能够在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])

The company I work for had customers regularly asking about this so we've written a freeware EC2 scheduling app available here: 我工作的公司让客户经常询问这个,所以我们在这里写了一个免费的EC2调度应用程序:

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

It works on Windows and Mac, lets you create multiple daily/weekly/monthly schedules and lets you use matching filters to include large numbers of instances easily or includes ones that you add in the future. 它适用于Windows和Mac,允许您创建多个每日/每周/每月计划,并允许您使用匹配筛选器轻松包含大量实例,或包括您将来添加的实例。

If it's not mission critical - A simplistic thing to do is to schedule batch file to run 'SHUTDOWN' (windows) at 3am every day. 如果它不是关键任务 - 一个简单的事情是安排批处理文件每天凌晨3点运行'SHUTDOWN'(窗口)。 Then at least you don't run the risk of accidentally leaving an unwanted instance running indefinitely. 那么至少你不会冒不小心让无意义的实例无限期地运行的风险。

Obviously this is only half the story! 显然这只是故事的一半!

AWS Data Pipeline is working fine. AWS Data Pipeline工作正常。 https://aws.amazon.com/premiumsupport/knowledge-center/stop-start-ec2-instances/ https://aws.amazon.com/premiumsupport/knowledge-center/stop-start-ec2-instances/

If you wish exclude days from starting (eg weekend) add a ShellCommandPrecondition object. 如果您希望排除几天开始(例如周末),请添加一个ShellCommandPrecondition对象。

In AWS Console/Data Pipeline, create a new pipeline. 在AWS Console / Data Pipeline中,创建一个新管道。 It's easyer to edit/import a definition (JSON) 编辑/导入定义(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"
}
}

Put the Bash script to be dowloaded and executed as precondition in your S3 bucket 将Bash脚本下载并作为S3存储桶中的前提条件执行

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

On activating and running the pipeline on weekend days, the AWS console Pipeline Health Status reads a misleading "ERROR". 在周末激活和运行管道时,AWS控制台管道运行状况会读取误导性的“错误”。 The bash script returns an error (exit 1) and EC2 isn't started. bash脚本返回错误(退出1)并且未启动EC2。 On days 1 to 5, the status is "HEALTHY". 在第1天到第5天,状态为“健康”。

To stop EC2 automatically at closing office time, use the AWS CLI command daily wihtout precondition. 要在关闭办公时间自动停止EC2,请在每日前提条件下使用AWS CLI命令。

AutoScaling is limited to terminating instances. AutoScaling仅限于终止实例。 If you want to stop an instance and retain the server state then an external script is the best approach. 如果要停止实例并保留服务器状态,则外部脚本是最佳方法。

You can do this by running a job on another instance that is running 24/7 or you can use a 3rd party service such as Ylastic (mentioned above) or Rocket Peak . 您可以通过在另一个全天候运行的实例上运行作业来执行此操作,也可以使用第三方服务,例如Ylastic(上面提到的)或Rocket Peak

For example in C# the code to stop a server is quite straightforward: 例如,在C#中,停止服务器的代码非常简单:

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

IMHO adding a schedule to an auto scaling group is the best "cloud like" approach as mentioned before. 恕我直言,如上所述,向自动缩放组添加时间表是最好的“云状”方法。

But in case you can't terminate your instances and use new ones, for example if you have Elastic IPs associated with etc. 但是,如果您无法终止实例并使用新实例,例如,如果您有与之相关的弹性IP等。

You could create a Ruby script to start and stop your instances based on a date time range. 您可以创建一个Ruby脚本,以根据日期时间范围启动和停止实例。

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

Have a look at amazon_start_stop to create a scheduler for free using Heroku Scheduler . 看一下amazon_start_stop ,使用Heroku Scheduler免费创建一个调度程序

Even though there are ways to achieve this using auto scaling, it might not suitable for all the occasions as it terminates the instances. 尽管有很多方法可以使用自动缩放来实现这一点,但它可能不适合所有场合,因为它会终止实例。 Cron jobs will never work for a single instance (although it can perfectly be used for situations like stopping a single instance and scheduling other instances when running many instances). Cron作业永远不会用于单个实例(尽管它可以完美地用于停止单个实例和在运行许多实例时调度其他实例的情况)。 You can use API calls like StartInstancesRequest , and StopInstancesRequest to achieve the same but again you have to rely on a third resource. 您可以使用诸如StartInstancesRequestStopInstancesRequest之类的API调用来实现相同的功能,但您必须再次依赖第三个资源。 There are many applications to schedule AWS instances with many features but for a simple solution I would recommend a free app like snapleaf.io 有许多应用程序可以调度具有许多功能的AWS实例,但对于一个简单的解决方案,我建议使用像snapleaf.io这样的免费应用程序

You could look at Ylastic to do this. 你可以看看Ylastic这样做。 The alternative seems to be having one machine running that shuts down/starts other instances using a cron job or scheduled task. 替代方案似乎是让一台机器运行,使用cron作业或计划任务关闭/启动其他实例。

Obviously if you only want one instance this is an expensive solution, as one machine has to always be running, and paying ~$80 a month for one machine to run cron jobs isn't cost effective. 显然,如果你只想要一个实例,这是一个昂贵的解决方案,因为一台机器必须始终运行,并且每台为一台机器支付约80美元来运行cron作业是不划算的。

Yes, you can do that using AWS Lambda. 是的,您可以使用AWS Lambda执行此操作。 You can select the trigger in Cloudwatch which runs on Cron expressions on UTC. 您可以在Cloudwatch中选择在UTC上的Cron表达式上运行的触发器。

Here is a related link https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/ 这是一个相关的链接https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/

Another alternative is to use awscli which is available from pip , apt-get , yum or brew , and then running aws configure with your credentials exported from IAM and executing the following bash script, to stop an EC2 that has been tagged with Name: Appname and Value: Appname Prod . 另一种方法是使用可从pipapt-getyumbrew apt-get awscli ,然后使用从IAM导出的凭据运行aws configure并执行以下bash脚本,以停止已使用Name: Appname标记的EC2 Name: AppnameValue: Appname Prod You can use awscli to tag your instances or tag it manually from the AWS console. 您可以使用awscli标记实例或从AWS控制台手动标记它。 aws ec2 stop-instances will stop the instance and jq is used to filter the json query and fetch the correct instance id using the tags from aws ec2 describe-instances . aws ec2 stop-instances将停止实例, jq用于过滤json查询并使用aws ec2 describe-instances的标记获取正确的实例id。

To verify that aws configure was successful and returns json output run aws ec2 describe-instances and your running instance id should be there in the output. 要验证aws configure是否成功并返回json输出,请运行aws ec2 describe-instances并且您的运行实例ID应该在输出中。 Here is a sample output 这是一个示例输出

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

The following bash script is stop-ec2.sh in /home/centos/cron-scripts/ which is inspired from this SO post 以下bash脚本是/home/centos/cron-scripts/ stop-ec2.sh ,灵感来自这篇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} )

Run the file using sh /home/centos/cron-scripts/stop-ec2.sh and verify that the EC2 instance gets stopped. 使用sh /home/centos/cron-scripts/stop-ec2.sh运行该文件,并验证EC2实例是否已停止。 To debug run 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 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 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 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 and see that it returns the correct instance ID which has been tagged. 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并看到它返回已标记的正确实例ID。

Then in crontab -e the following line can be added 然后在crontab -e中添加以下行

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

which will log the output to /tmp/stop . 这会将输出记录到/tmp/stop The 30 14 * * * is the UTC cron expression that you can check in https://crontab.guru/ . 30 14 * * *是UTC cron表达式,您可以在https://crontab.guru/查看。 Similarly replacing with aws ec2 start-instances can start an instance. 同样,用aws ec2 start-instances替换可以启动一个实例。

I believe that the initial question was a little bit confusing. 我认为最初的问题有点令人困惑。 It depends on what Pasta needs: 1.launch/terminate (instance store) - Auto Scaling is the right solution( Nakedible's answer) 2.start/stop EBS boot instance - Auto Scaling won't help, I use remote scheduled scripts (ie, ec2 CLI). 这取决于Pasta需要什么:1。启动/终止(实例存储) - Auto Scaling是正确的解决方案(Nakedible的答案)2。启动/停止EBS启动实例 - Auto Scaling无济于事,我使用远程调度脚本(即,ec2 CLI)。

You cannot do this automatically, or at least not without some programming and API manipulation in script files. 您不能自动执行此操作,或者至少在脚本文件中没有编程和API操作时也不能这样做。 If you want to a reliable solution to stop, restart and manage your images (presumably to control costs in your environment) then you may want to look at LabSlice . 如果您想要一个可靠的解决方案来停止,重新启动和管理您的图像(可能是为了控制您环境中的成本),那么您可能需要查看LabSlice Disclaimer: I work for this company. 免责声明:我为这家公司工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM