如何调度EC2实例每小时启动并在Docker任务完成后停止以降本?
解决方案:按需启动EC2执行Docker任务后自动停止
这问题我之前帮朋友处理过,核心思路就是让EC2只在任务运行时段启动,执行完立刻停止,彻底避免闲置付费。结合EventBridge(原CloudWatch Events)、Lambda和EC2用户数据就能搞定,具体步骤拆解如下:
1. 配置EC2实例的启动自动执行脚本
在你的EC2实例(先处于停止状态)的**用户数据(User Data)**中添加启动脚本,让实例启动后自动完成:安装Docker(如果镜像没预装)、拉取你的镜像、运行容器,最后停止自身。
示例脚本(适配Amazon Linux 2,其他系统可调整包管理命令):
#!/bin/bash set -e # 遇到错误就退出,可选 # 安装Docker(如果实例镜像未预装) yum update -y amazon-linux-extras install docker -y systemctl start docker systemctl enable docker # 确保重启后Docker自动启动 usermod -a -G docker ec2-user # 拉取并运行你的Docker镜像(如果是私有镜像,要提前配置认证,比如ECR的IAM权限) docker pull your-docker-repo/your-image:your-tag docker run --rm your-docker-repo/your-image:your-tag # 任务执行完成后,停止当前实例 INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) aws ec2 stop-instances --instance-id $INSTANCE_ID --region us-east-1 # 替换为你的区域
注意:EC2实例需要关联一个IAM角色,该角色必须拥有
ec2:StopInstances权限(遵循最小权限原则,别给全量EC2权限)。你可以在IAM控制台创建角色,附加自定义策略后关联到EC2实例。
2. 创建Lambda函数负责启动EC2
写一个简单的Lambda函数,用来触发EC2实例启动。用Python的话,代码如下:
import boto3 def lambda_handler(event, context): ec2_client = boto3.client('ec2', region_name='us-east-1') # 替换为你的区域 target_instance_id = 'i-xxxxxxxxxxxxxxxxx' # 替换为你的EC2实例ID # 启动实例 response = ec2_client.start_instances(InstanceIds=[target_instance_id]) print(f"Successfully started instance {target_instance_id}, response: {response}") return { 'statusCode': 200, 'body': f"Started instance {target_instance_id}" }
同样,Lambda的执行角色需要拥有
ec2:StartInstances权限,确保能调用启动实例的API。
3. 设置EventBridge定时触发Lambda
用EventBridge创建一个定时规则,每小时触发一次Lambda,自动启动EC2:
- 进入EventBridge控制台,创建规则,选择计划类型
- 选择cron表达式,输入
0 * * * ? *(表示每小时整点触发) - 目标选择刚才创建的Lambda函数,完成配置
关键注意事项
- 实例状态:确保EC2实例平时处于停止状态,这样Lambda启动时才会触发用户数据脚本(如果实例是运行中,启动命令不会触发用户数据)。
- 私有镜像认证:如果你的Docker镜像存放在私有仓库(比如AWS ECR),要给EC2的IAM角色添加
ecr:GetDownloadUrlForLayer、ecr:BatchGetImage等权限,或者在用户数据里添加登录命令。 - 错误处理:如果Docker任务执行失败,你可以在脚本里加判断逻辑,比如发送SNS告警后再停止实例:
if docker run --rm your-image:tag; then echo "Task completed successfully" else echo "Task failed! Sending alert..." aws sns publish --topic-arn arn:aws:sns:us-east-1:123456789012:your-alert-topic --message "Docker task failed on instance $INSTANCE_ID" fi - 成本优化:可以选择按需实例,或者如果任务允许中断,用Spot实例进一步降低成本,但按需实例更稳定,3分钟的运行成本几乎可以忽略。
内容的提问来源于stack exchange,提问作者Sean Pianka
相关产品推荐
相关产品推荐

