计划启动EC2实例并在其中运行python脚本
我试图在AWS中安排python脚本,但是我不希望实例一直运行。因此,尝试将以下过程自动化:计划启动EC2实例并在其中运行python脚本,python,amazon-web-services,amazon-ec2,Python,Amazon Web Services,Amazon Ec2,我试图在AWS中安排python脚本,但是我不希望实例一直运行。因此,尝试将以下过程自动化: 在特定时间启动EC2实例 在其中运行python脚本 作业完成后停止EC2实例 我无法将此脚本直接作为Lambda函数运行,因为该脚本执行一些需要更多RAM的并行处理,因此选择更大的AWS实例,而不是将其作为Lambda函数编写。另外,我不希望这个实例一直运行,因为它很昂贵 到目前为止,我遵循并创建了一个Lambda函数来在特定时间启动和停止实例,但是在实例启动后,我找不到运行python脚本的方法 有
有人能给我指出正确的方向吗?我的应用程序每天运行一个实例@13:39 UST,处理完成后自动关闭。它在下面使用
导入boto3
def lambda_处理程序(事件、上下文):
ec2=boto3.客户('ec2',地区名称='ap-south-1')
ec2.start_实例(instanceId=['i-xxxxxxx'])
print('startedyour instances:'+str('i-xxxxxx'))
return
对于解决此问题的未来开发人员,一种更新的方法是:
amazonec2roleforsm
策略的角色创建EC2导入时间
进口boto3
地区名称='us-east-1'
工作目录=“”
COMMAND=”“”
回声:“你好,世界!"
"""
实例_ID=“”
def start_ec2():
ec2=boto3.client('ec2',region\u name=region\u name)
ec2.start\u实例(instanceId=[INSTANCE\u ID])
尽管如此:
response=ec2.描述实例状态(instanceId=[instance\u ID],includealInstances=True)
状态=响应['InstanceStatus'][0]['InstanceState']
打印(f“状态:{state['Code']}-{state['Name']}”)
#如果状态为16(“正在运行”),则继续,否则,等待5秒钟,然后重试
如果状态['Code']==16:
打破
其他:
时间。睡眠(5)
打印('EC2已启动')
def stop_ec2():
ec2=boto3.client('ec2',region\u name=region\u name)
ec2.stop_实例(instanceId=[INSTANCE_ID])
尽管如此:
response=ec2.描述实例状态(instanceId=[instance\u ID],includealInstances=True)
状态=响应['InstanceStatus'][0]['InstanceState']
打印(f“状态:{state['Code']}-{state['Name']}”)
#如果状态为80(“已停止”),则继续,否则等待5秒钟,然后重试
如果状态['Code']==80:
打破
其他:
时间。睡眠(5)
打印('实例已停止')
def run_命令():
client=bot3.client('ssm',region\u name=region\u name)
时间。睡眠(10)#我必须等待10秒才能“发送_命令”找到我的实例
cmd\u response=client.send\u命令(
InstanceId=[INSTANCE_ID],
DocumentName='AWS-RunShellScript',
DocumentVersion=“1”,
TimeoutSeconds=300,
MaxConcurrency=“1”,
CloudWatchOutputConfig={'CloudWatchOutputEnabled':True},
参数={
“命令”:[命令],
“executionTimeout”:[“300”],
“工作目录”:[工作目录],
},
)
command_id=cmd_response['command']['CommandId']
时间。睡眠(1)#再次,我必须等待1s才能获取_命令#调用识别我的命令#id
retcode=-1
尽管如此:
输出=client.get_命令_调用(
CommandId=命令\u id,
InstanceId=实例ID,
)
#如果ResponseCode为-1,则该命令仍在运行,因此请等待5秒钟,然后重试
retcode=output['ResponseCode']
如果重新编码!=-1:
打印('状态:',输出['Status'])
打印('StdOut:',输出['StandardOutputContent'])
打印('StdErr:',输出['StandardErrorContent'])
打破
打印('状态:',重新编码)
时间。睡眠(5)
打印(“命令成功完成”)#实际上,0表示成功,其他任何东西都表示失败,但这对我来说并不重要
返回代码
def lambda_处理程序(事件、上下文):
retcode=-1
尝试:
启动_ec2()
retcode=run_命令()
最后:#与发生的情况无关,尝试关闭EC2
停止_ec2()
返回代码
我在使用本文中的解决方案启动和停止实例时遇到问题。然后我按照上面的说明去做,真的很简单。基本上:
whichpython
,找到python的路径并将其写下来。然后,键入crontab-e
编辑您的CRON作业。不要使用sudo
…因为当您没有使用它来运行Python文件时,有时sudo
会把事情搞砸。在我的例子中,我有一个pgpass
文件存储我的密码,而sudo
看不到,但是删除sudo有效李>
import time
import boto3
REGION_NAME = 'us-east-1'
WORKING_DIRECTORY = '<YOUR WORKING DIRECTORY, IF ANY>'
COMMAND = """
echo "Hello, world!"
"""
INSTANCE_ID = '<YOUR INSTANCE ID>'
def start_ec2():
ec2 = boto3.client('ec2', region_name=REGION_NAME)
ec2.start_instances(InstanceIds=[INSTANCE_ID])
while True:
response = ec2.describe_instance_status(InstanceIds=[INSTANCE_ID], IncludeAllInstances=True)
state = response['InstanceStatuses'][0]['InstanceState']
print(f"Status: {state['Code']} - {state['Name']}")
# If status is 16 ('running'), then proceed, else, wait 5 seconds and try again
if state['Code'] == 16:
break
else:
time.sleep(5)
print('EC2 started')
def stop_ec2():
ec2 = boto3.client('ec2', region_name=REGION_NAME)
ec2.stop_instances(InstanceIds=[INSTANCE_ID])
while True:
response = ec2.describe_instance_status(InstanceIds=[INSTANCE_ID], IncludeAllInstances=True)
state = response['InstanceStatuses'][0]['InstanceState']
print(f"Status: {state['Code']} - {state['Name']}")
# If status is 80 ('stopped'), then proceed, else wait 5 seconds and try again
if state['Code'] == 80:
break
else:
time.sleep(5)
print('Instance stopped')
def run_command():
client = boto3.client('ssm', region_name=REGION_NAME)
time.sleep(10) # I had to wait 10 seconds to "send_command" find my instance
cmd_response = client.send_command(
InstanceIds=[INSTANCE_ID],
DocumentName='AWS-RunShellScript',
DocumentVersion="1",
TimeoutSeconds=300,
MaxConcurrency="1",
CloudWatchOutputConfig={'CloudWatchOutputEnabled': True},
Parameters={
'commands': [COMMAND],
'executionTimeout': ["300"],
'workingDirectory': [WORKING_DIRECTORY],
},
)
command_id = cmd_response['Command']['CommandId']
time.sleep(1) # Again, I had to wait 1s to get_command_invocation recognises my command_id
retcode = -1
while True:
output = client.get_command_invocation(
CommandId=command_id,
InstanceId=INSTANCE_ID,
)
# If the ResponseCode is -1, the command is still running, so wait 5 seconds and try again
retcode = output['ResponseCode']
if retcode != -1:
print('Status: ', output['Status'])
print('StdOut: ', output['StandardOutputContent'])
print('StdErr: ', output['StandardErrorContent'])
break
print('Status: ', retcode)
time.sleep(5)
print('Command finished successfully') # Actually, 0 means success, anything else means a fail, but it didn't matter to me
return retcode
def lambda_handler(event, context):
retcode = -1
try:
start_ec2()
retcode = run_command()
finally: # Independently of what happens, try to shutdown the EC2
stop_ec2()
return retcode
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ec2:Start*",
"ec2:Stop*"
],
"Resource": "*"
}
]
}
import boto3
region = 'us-west-1' # Dont use the specific, like instead of us-east-1d just write us-east-1
instances = ['i-xxxxxxxxxxxx']
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=instances)
print('started your instances: ' + str(instances))
import boto3
region = 'us-west-1' # Dont use the specific, like instead of us-east-1d just write us-east-1
instances = ['i-xxxxxxxxxxxx']
ec2 = boto3.client('ec2', region_name=region)
ec2.stop_instances(InstanceIds=instances)