web-dev-qa-db-ja.com

EC2インスタンスを起動して、その中でpythonスクリプトを実行するようにスケジュールします。

AWSでpythonスクリプトをスケジュールしようとしていますが、インスタンスを常に実行したくないので、次のプロセスを自動化しようとしています。

  1. 特定の時間にEC2インスタンスを開始する
  2. その中でpythonスクリプトを実行します
  3. ジョブが完了したら、EC2インスタンスを停止します。

このスクリプトは、より多くのRAMを必要とする並列処理を実行するため、ラムダ関数として記述するのではなく、より大きなAWSインスタンスを選択するため、このスクリプトをラムダ関数として直接実行することはできません。また、このインスタンスは高価であるため、常に実行されているとは限りません。

これまでのところ、私は LambdaとCloudWatchを使用したAWS EC2インスタンスの自動開始と停止・matoski.com に従い、特定の時間にインスタンスを開始および停止するLambda関数を作成しましたが、見つかりませんでしたpythonスクリプトをインスタンスの起動後に実行する方法。

誰かが私を正しい方向に向けることができますか?

12
ds_user

MYアプリケーションは毎日13:39 USTのインスタンスを実行し、処理が完了すると自動的にシャットダウンします。以下を使用します

  1. クラウド監視イベントルールを使用したスケジュールされたラムダ関数

クラウド監視イベント/ルール設定

  1. ラムダトリガーはインスタンスを開始します(ハードコードされたIDで)
import boto3
def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name='ap-south-1')
    ec2.start_instances(InstanceIds=['i-xxxxxxx'])
    print('started your instances: ' + str('i-xxxxxx'))
    return
  1. これにより、cronが実行されているインスタンスがトリガーされ、Pythonスクリプトが実行されます

    @reboot python /home/Init.py

  2. スクリプトが完了すると、pythonジョブは以下のスニペットを使用して自身をシャットダウンします

import boto.ec2
import boto.utils
import logging
logger=logging.getLogger()
def stop_ec2():
    conn = boto.ec2.connect_to_region("ap-south-1") # or your region
    # Get the current instance's id
    my_id = boto.utils.get_instance_metadata()['instance-id']
    logger.info(' stopping EC2 :'+str(my_id))
    conn.stop_instances(instance_ids=[my_id])
8
Shambhurao Rane

この投稿のソリューションを使用してインスタンスを開始および停止するときに問題が発生しました。次に、私は https://aws.Amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/ の指示に従いましたが、それは本当に簡単でした。基本的に:

  1. https://console.aws.Amazon.com/iam/home#/home に移動し、左側にある[ポリシー]をクリックして、[ポリシーの作成]をクリックします。次に、JSONタブをクリックします。次に、これをコピーして貼り付け、新しいポリシーを作成します。
{
  "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": "*"
    }
  ]
}
  1. https://console.aws.Amazon.com/iam/home#/home に移動し、左側で[ロール]を選択します。 AWSサービスとしてLambdaを選択し、ステップ1で作成したポリシーをアタッチしてください。

  2. 次に、Lambdaコンソールに移動し、[関数の作成]をクリックします。 Python 3.7を選択し、[Permissions]と[Use an Existing Role]の横のドロップダウンをクリックして、ステップ2で作成したIAMロールをアタッチします。

  3. これをコードとして使用します。

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))
1
Corey Levinson

この質問に来る将来の開発者にとって、これに対する新しいアプローチは次のとおりです。

  1. AmazonEC2RoleforSSMポリシーを含むロールでEC2を作成します
  2. ウェイクアップ、コマンドの実行、シャットダウンを行うラムダを作成します
  3. Cloudwatchイベントを使用してラムダをトリガーする

そう:

  1. ここの手順に従ってください: https://docs.aws.Amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-Amazon-ec2.html

  2. 次のラムダスケルトンを使用します。

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

  1. ここの手順に従ってください: https://docs.aws.Amazon.com/AmazonCloudWatch/latest/events/RunLambdaSchedule.html
1
Gustavo Lopes