自动关闭并启动Amazon EC2实例

时间:2010-03-09 22:21:39

标签: api amazon-ec2 amazon-web-services

我可以使用Amazon API自动启动和终止我的Amazon实例吗?你能描述一下如何做到这一点吗?理想情况下,我需要启动实例并每天以指定的时间间隔停止实例。

14 个答案:

答案 0 :(得分:100)

以防有人偶然发现这个旧问题,现在您可以通过向自动缩放组添加计划来实现相同的目的:在特定时间将自动缩放组中的实例数量增加到1并将其减少之后为0。

由于这个答案得到了很多观点,我想连接到一个非常有用的指南:Running EC2 Instances on a Recurring Schedule with Auto Scaling

答案 1 :(得分:26)

您可以尝试直接使用Amazon EC2 API工具。有 实际上只需要两个命令:ec2-start-instances和ec2-stop-instances。 确保环境变量,如EC2_HOME, AWS_CREDENTIAL_FILE,EC2_CERT,EC2_PRIVATE_KEY等正确 已配置和所有AWS凭据,证书和私钥文件 位于正确的位置 - 您可以在AWS EC2 API中找到更多信息 工具文档。

您可以先手动测试命令,然后当一切正常时, 在Windows上配置Unix crontab或Scheduled Tasks。你可以找到 以下示例为Linux / etc / crontab文件(不要忘记全部 需要提供上述环境变量 '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.

我是BitNami Cloud项目的开发人员,我们将其打包 AWS工具(包括我提到的那些)免费,易于使用 您可能想尝试的安装程序:BitNami CloudTools pack stack

答案 2 :(得分:17)

我建议你看一下EC2 Getting Started Guide,它会告诉你如何使用EC2命令行工具做你需要的工作。您可以轻松地将其编写为cron作业(在Linux / UNIX上)或Windows上的预定作业,以在给定时间调用启动和停止命令。

如果要从自己的代码中执行此操作,可以使用SOAP或REST API;有关详细信息,请参阅Developer Guide

答案 3 :(得分:15)

我使用Boto库在Python中编写代码来执行此操作。您可以根据自己的需要进行调整。确保将其作为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])

答案 4 :(得分:5)

我工作的公司让客户经常询问这个,所以我们在这里写了一个免费的EC2调度应用程序:

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

它适用于Windows和Mac,允许您创建多个每日/每周/每月计划,并允许您使用匹配过滤器轻松包含大量实例,或包括您将来添加的实例。

答案 5 :(得分:4)

如果它不是关键任务 - 一个简单的事情是安排批处理文件每天凌晨3点运行'SHUTDOWN'(窗口)。那么至少你不会冒不小心让无用的实例无限期地运行的风险。

显然这只是故事的一半!

答案 6 :(得分:2)

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

如果您希望排除几天开始(例如周末),请添加一个ShellCommandPrecondition对象。

在AWS Console / Data Pipeline中,创建一个新管道。编辑/导入定义(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"
}
}

将Bash脚本下载并作为S3存储桶中的前提条件执行

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

在周末激活并运行管道时,AWS控制台管道运行状况会读取误导性错误&#34; ERROR&#34;。 bash脚本返回错误(退出1)并且EC2未启动。在第1天到第5天,状态为&#34; HEALTHY&#34;。

要在办公时间结束时自动停止EC2,请在每日前提条件下使用AWS CLI命令。

答案 7 :(得分:1)

您可以查看Ylastic来执行此操作。替代方案似乎是让一台机器运行,使用cron作业或计划任务关闭/启动其他实例。

显然,如果你只想要一个实例这是一个昂贵的解决方案,因为一台机器必须始终运行,并且每台每台80美元的费用来运行cron作业并不符合成本效益。

答案 8 :(得分:1)

AutoScaling仅限于终止实例。如果要停止实例并保留服务器状态,则外部脚本是最佳方法。

您可以通过在另一个全天候运行的实例上运行作业,或者您可以使用第三方服务(如Ylastic(上文提到)或Rocket Peak)来执行此操作。

例如在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));
        }

答案 9 :(得分:1)

恕我直言,为自动缩放组添加时间表是最好的&#34; cloud like&#34;如前所述的方法。

但是,如果您无法终止实例并使用新实例,例如,如果您有与之相关的弹性IP等。

您可以创建一个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

使用amazon_start_stop查看Heroku Scheduler免费创建计划程序。

答案 10 :(得分:1)

尽管有很多方法可以使用自动缩放来实现这一点,但它可能不适合所有场合,因为它会终止实例。 Cron作业永远不会用于单个实例(尽管它可以完美地用于停止单个实例和在运行许多实例时调度其他实例的情况)。您可以使用StartInstancesRequestStopInstancesRequest之类的API调用来实现相同的功能,但您必须再次依赖第三个资源。有许多应用程序可以调度具有许多功能的AWS实例,但对于一个简单的解决方案,我建议使用免费的应用程序,如snapleaf.io

答案 11 :(得分:1)

是的,您可以使用AWS Lambda做到这一点。您可以在Cloudwatch中选择在UTC的Cron表达式上运行的触发器。

这里是相关链接https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/

另一种替代方法是使用awsclipipapt-getyum可用的brew,然后在运行aws configure时使用您的凭据从IAM导出并执行以下bash脚本,以停止已用Name: AppnameValue: Appname Prod标记的EC2。您可以使用awscli来标记您的实例,也可以从AWS控制台手动对其进行标记。 aws ec2 stop-instances将停止实例,而jq用于过滤json查询,并使用aws ec2 describe-instances中的标记获取正确的实例ID。

要验证aws configure是否成功并返回json输出,请运行aws ec2 describe-instances,并且正在运行的实例ID应该在输出中。这是示例输出

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

以下bash脚本是stop-ec2.sh中的/home/centos/cron-scripts/,其灵感来自this SO post

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

使用sh /home/centos/cron-scripts/stop-ec2.sh运行文件,并验证EC2实例是否已停止。要调试运行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。

然后在crontab -e中添加以下行

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

,它将把输出记录到/tmp/stop30 14 * * *是您可以在https://crontab.guru/中签入的UTC cron表达式。同样,用aws ec2 start-instances替换也可以启动实例。

答案 12 :(得分:0)

我认为最初的问题有点令人困惑。这取决于Pasta需要什么: 1.启动/终止(实例存储) - Auto Scaling是正确的解决方案(Nakedible的答案) 2.启动/停止EBS启动实例 - Auto Scaling无济于事,我使用远程调度脚本(即ec2 CLI)。

答案 13 :(得分:-8)

您不能自动执行此操作,或者至少在脚本文件中没有编程和API操作时也不能这样做。如果您想要一个可靠的解决方案来停止,重新启动和管理您的图像(可能是为了控制您环境中的成本),那么您可能需要查看LabSlice。免责声明:我为这家公司工作。