【问题标题】:how to stop and start AWS EC2 instance automatically如何自动停止和启动 AWS EC2 实例
【发布时间】:2018-08-15 07:46:17
【问题描述】:

我是使用 AWS 的初学者。

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

有什么推荐的方法吗?

【问题讨论】:

  • AWS Lambda 是一个不错的选择,因为它有足够的免费层级访问权限,如果您对其进行正确编程,您可以使用 Cron 启动和停止 EC2 实例,如果它是每天使用的话。查看 lambda 定价,了解他们的新收费单位 GB-秒 :: RAM - 执行时间
  • 为什么不想重新启动?您是否了解当您停止实例(而不是终止它)时,实例会关闭,而不是进入睡眠状态? AWS 中没有睡眠选项(这会占用资源)。

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


【解决方案1】:

亚马逊最近(2018 年 2 月)发布了 EC2 实例调度工具:

AWS Instance Scheduler 是一个简单的 AWS 提供的解决方案, 使客户能够轻松配置自定义启动和停止计划 为他们的 Amazon Elastic Compute Cloud (Amazon EC2) 和 Amazon 关系数据库服务 (Amazon RDS) 实例。解决方案是 易于部署,有助于降低两者的运营成本 开发和生产环境。使用此功能的客户 在正常工作时间运行实例的解决方案最多可节省 与每天 24 小时运行这些实例相比,提高了 70%。

我在 15 分钟内就在我的帐户中启动并运行了它;使用非常简单,而且几乎免费。

https://aws.amazon.com/answers/infrastructure-management/instance-scheduler/

【讨论】:

  • 我想建议计划自动缩放,但我不确定是否可以定义 0 最小实例数。实例调度器看起来确实更简单
  • Cloudformation 非常不直观,可能会更新此答案以了解如何使用 Cloudformation 进行调度,因为他们的文档很糟糕
  • 这里有更详细的答案serverfault.com/questions/867642/…
【解决方案2】:

AWS 有一个很好的文档,解释了如何使用 Lambda 和 Cloudwatch 事件来实现这一点。你可以参考一下-https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/

这个方案可以修改为动态获取EC2列表,或者对一组实例进行操作,可以根据某个标签进行识别。

【讨论】:

    【解决方案3】:

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

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

    另一种选择是使用awscli,可从pipapt-getyumbrew 获得,然后使用来自 IAM 的凭据运行 aws configure 并执行以下 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 in /home/centos/cron-scripts/

    (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 表达式

    【讨论】:

      【解决方案4】:

      用于停止实例的 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)
      

      【讨论】:

        【解决方案5】:

        如果您使用 ASG,ASG 调度程序是管理 EC2 实例的最佳和最简单的选择。如果不使用 ASG,那么您可以使用 AWS 实例调度程序 CF 解决方案或带有 cloudwatch Cron 事件的 lambda。

        【讨论】: