如何自动停止和启动AWS EC2实例

7

我是AWS的初学者。

我想要自动定期停止和启动几个EC2实例(不是重启)。

有没有推荐的方法来实现这个功能?


1
AWS Lambda是一个不错的选择,因为它具有足够的免费层访问权限。如果您正确编写程序,可以使用Cron启动和停止EC2实例,而无需任何费用,如果是每天一次的话。请查看Lambda定价,以了解他们称为GB-second :: RAM -执行时间的新计费单位。 - devssh
为什么你不想重新启动?你明白当你停止一个实例(而不是终止它)时,实例是被关闭的,而不是被休眠。在 AWS 中没有休眠选项(这会占用资源)。 - kdgregory
6个回答

9
亚马逊最近(2018年2月)发布了EC2实例计划工具:
AWS Instance Scheduler是一种简单的由亚马逊提供的解决方案,使客户可以轻松地配置自定义启动和停止时间表,用于其Amazon Elastic Compute Cloud(Amazon EC2)和Amazon Relational Database Service(Amazon RDS)实例。该解决方案易于部署,可帮助减少开发和生产环境的运营成本。使用此解决方案在正常工作时间运行实例的客户可以节省高达70%的费用,与全天运行这些实例相比。
我在15分钟内在我的账户上运行了它;非常简单易用,几乎免费。
https://aws.amazon.com/answers/infrastructure-management/instance-scheduler/

我想建议定期自动缩放,但我不确定是否可以定义0个最小实例计数。实例调度程序似乎确实更简单。 - gusto2
Cloudformation非常不直观,也许需要更新这个答案以说明如何使用Cloudformation进行调度,因为他们的文档很糟糕。 - devssh
这里有一个更详细的答案:https://serverfault.com/questions/867642/how-to-start-and-stop-aws-ec2-instance-based-on-a-time-based-schedule - devssh

4

2
可以使用AWS Lambda来实现这个功能。您可以在Cloudwatch中选择触发器,它可以基于UTC上的Cron表达式运行。
这里是一个相关的链接:https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/ 另一个选择是使用`awscli`,它可以从`pip`、`apt-get`、`yum`或`brew`获取,并使用IAM中的凭据运行`aws configure`命令,然后执行以下bash脚本,以停止已标记为`Name: Appname`和`Value: 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"
        }
    ]
}

以下是位于/home/centos/cron-scripts/目录下的stop-ec2.sh Bash脚本。
(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 * * * 是 UTC cron 表达式,您可以在 https://crontab.guru/ 上检查它。


1
Lambda脚本停止实例:
import json
import boto3

# Enter the region your instances are in. Include only the region without specifying Availability Zone; e.g., 'us-east-1'
region = 'us-east-1'

def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name=region)

    filter = [{'Name': 'tag:Name', 'Values': ['****-env']}]  //give instance name here in place of ****-env

    instances = ec2.describe_instances(Filters=filter)

    #ec2.stop_instances(InstanceIds=instances)


    stop_instance = instances.get('Reservations')[0].get('Instances')[0].get('InstanceId')
    stop_instances = []
    stop_instances.append(stop_instance)

    ec2.stop_instances(InstanceIds=stop_instances)

启动实例的Lambda脚本:

import json
import boto3

# Enter the region your instances are in. Include only the region without specifying Availability Zone; e.g., 'us-east-1'
region = 'us-east-1'

def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name=region)

    filter = [{'Name': 'tag:Name', 'Values': ['****-env']}]

    instances = ec2.describe_instances(Filters=filter)

    #ec2.stop_instances(InstanceIds=instances)


    start_instance = instances.get('Reservations')[0].get('Instances')[0].get('InstanceId')
    start_instances = []
    start_instances.append(start_instance)

    ec2.start_instances(InstanceIds=start_instances)

0

如果您正在使用ASG,则ASG调度程序是管理EC2实例的最佳和最简单的选项。如果不使用ASG,则可以使用AWS实例调度程序CF解决方案或带有CloudWatch Cron事件的Lambda。


0

您现在可以使用EventScheduler,而且已经全部覆盖了

首先创建一个iAM策略,并在其中添加以下JSON

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "ec2Stop",
        "Effect": "Allow",
        "Action": "ec2:StopInstances",
        "Resource": "*"
    }
]

}

现在创建iAM角色,选择自定义信任策略并在信任策略中添加以下JSON

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "ec2Stop",
        "Effect": "Allow",
        "Action": "ec2:StopInstances",
        "Resource": "*"
    }
]

}

现在前往Amazon事件桥,创建一个调度程序并指定调度程序详细信息,您可以使用cron进行重复。然后在选择目标中选择所有API,并搜索ec2。然后搜索stopInstances API。选择它并添加实例ID。最后将角色附加到它上面,就可以自动停止实例了。

同样,以下是启动实例的策略,其余流程保持不变

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "EC2Start",
        "Effect": "Allow",
        "Action": "ec2:StartInstances",
        "Resource": "*"
    }
]

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接