0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Lambda(python)でAWS Backupの最新イメージ(AMI)情報をパラメータストアへ登録する(EC2スポットインスタンス自動化1)

Last updated at Posted at 2023-09-03

背景

個人向けに最低費用で運用するため、Ec2をスポットインスタンスで使用しているが、時々スポットリクエストが中断される。その都度、再度スポットリクエストで立ち上げなおしているが、この処理を自動化したい。

大まかな流れ

スポットインスタンスの中断はイベント通知されるので、それをトリガとして、立ち上げ処理を行う。

①普段の処理

  1. 起動時に使用するAMIの最新IDを取得しておく。
    1. バックアップ(AWS Backup)でAMIが作成された際、CreateImageイベントが発生。
    2. EventBridgeでイベントを拾い、Lambda関数にて該当のAMIのIDを取得し、ParameterStoreへ保存しておく。

②中断イベント発生時の流れ

  1. スポットインスタンスの中断イベントが通知される。
  2. EventBridgeでイベントを拾う。
  3. イベントに連動して、Step Functionsへ連携。
  4. Step Functions内で以下の流れを作る。
    1. ParameterStoreから最新のAMI IDを取得し、スポットリクエストを発行。(Lambda関数)
      1. 起動状況を確認。
      2. ダメだったら、AZやインスタンスタイプを変更して再トライ。
    2. 起動に成功したか判定し、成功していればElastic IPを付け替える。(Lambda関数)
    3. 処理結果を通知。(LINE通知)
      ※AZとインスタンスタイプのパターンはリスト化して持っておく。(ParameterStore)

記事の全体

要素に分けて全5回で記載していきます。

  1. AWS BackupでEC2のAMIが作成されるので、その最新のAMI IDをイベントから取得してParameterStoreに登録する。←今回の内容

  2. AWS Lambda(python)でLINEへ通知する。

  3. AWS Lambda(python)でEC2スポットリクエストを実行する。

  4. AWS Lambda(Python,boto3)でElasticIPを付け替える。

  5. Step FunctionでLambdaでスポットリクエストを実行し、ElasticIPを付け替える。

調べたこと

  1. boto3でAMI IDを取得する方法。
    https://qiita.com/handa3/items/8ea3ee59145ccf55d525

  2. そもそもAWS BackupでAMIが作成された際に、CreateImageが通知されるので、EventBridge経由でLambdaを起動し、ParameterStoreに保存すればよい。
    https://zenn.dev/chittai/articles/20210325-update-ps-for-dr

2.の方法がよさそうなので、そちらで進める。

[参考]

BackupにてAMIが作成されると、CreateImageのEventが発行される。

(Eventのサンプル).json
{
    "version": "0",
    "id": "*******-*****-****-****-*********",
    "detail-type": "EC2 AMI State Change",
    "source": "aws.ec2",
    "account": "アカウントIDの番号",
    "time": "2023-08-05T03:34:14Z",
    "region": "ap-northeast-1",
    "resources": [
        "arn:aws:ec2:ap-northeast-1::image/ami-********"
    ],
    "detail": {
        "RequestId": "********-****-****-****-**********",
        "State": "available",
        "ImageId": "ami-*********",
        "ErrorMessage": ""
    }
}

AMIのIDは取れるものの、どのインスタンスのAMIなのかが判別できない。
AWS Backupで、AMIのタグにあるNameに取得元インスタンス名称を入れているので、それを取得する。

AMI情報取得にはアカウントIDを指定するが、以下の方法でコードに記載することなく取得可能。

(AMI情報サンプル).json
{
    "Images": [
        {
            "Architecture": "x86_64",
            "CreationDate": "2023-08-05T04:05:47.000Z",
            "ImageId": "ami-***********",
            "ImageLocation": "*********/AwsBackup_i-*************_********-****-****-****-******",
            "ImageType": "machine",
            "Public": false,
            "OwnerId": "*********",
            "PlatformDetails": "Linux/UNIX",
            "UsageOperation": "RunInstances",
            "ProductCodes": [
                {
                    "ProductCodeId": "aw0evgkw8e5c1q413zgy5pjce",
                    "ProductCodeType": "marketplace"
                }
            ],
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/sda1",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-********",
                        "VolumeSize": 20,
                        "VolumeType": "gp2",
                        "Encrypted": true
                    }
                }
            ],
            "Description": "This image is created by the AWS Backup service.",
            "EnaSupport": true,
            "Hypervisor": "xen",
            "Name": "AwsBackup_i-*************_********-****-****-****-******",
            "RootDeviceName": "/dev/sda1",
            "RootDeviceType": "ebs",
            "SriovNetSupport": "simple",
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "EC2のホスト名を入れておく"
                },
                {
                    "Key": "aws:backup:source-resource",
                    "Value": "i-********:*******_********-****-****-****-******"
                },
                {
                    "Key": "AWSBackup",
                    "Value": "EC2"
                }
            ],
            "VirtualizationType": "hvm"
        }
    ]

CreateImageイベント受信、ParameterStoreの登録用Lambda

(Lambda関数 getBackupAmiId).py
import boto3
import logging
import json

logger = logging.getLogger()
logger.setLevel(logging.INFO)

# Region
REGION = 'ap-northeast-1'
HOSTNAME = 'EC2のTagsのNameに登録しているホスト名'

def lambda_handler(event, context):
    logger.info('event[' + json.dumps(event) + ']')
    image_id = event['detail']['ImageId']

    ec2 = boto3.client('ec2', region_name=REGION)
    # アカウントIDを取得
    Owner_id = boto3.client('sts').get_caller_identity().get('Account')

    response = ec2.describe_images(
        Owners = [Owner_id],
        ImageIds = [image_id]
    )
    logger.info('image info[' + json.dumps(response) + ']')

    ssm = boto3.client('ssm', region_name=REGION)
    for idx, keyvalue in enumerate(response['Images'][0]['Tags']):

        # TagsのNameがホスト名と一致しているかチェック
        if( keyvalue['Key'] == 'Name' and keyvalue['Value'] == HOSTNAME ):

            # パラメータストアへAMIのimageIDを保存
            response_put =  ssm.put_parameter(
                Name = '/EC2Backup/latestAMI/' + HOSTNAME,
                Value = image_id,
                Type = 'String',
                Overwrite = True
            )
        #
        if( keyvalue['Key'] == 'aws:backup:source-resource' ):

            # パラメータストアへEC2インスタンスIDを保存
            response_put =  ssm.put_parameter(
                Name = '/EC2Backup/latestAMI/source-resource' ,
                Value = keyvalue['Value'].split(':')[0] ,
                Type = 'String',
                Overwrite = True
            )

Lambdaのロールには、AWSLambdaBasicExecutionRoleと、AMI情報取得、ParameterStoreの操作に必要そうな許可ポリシーを入れた。(合っている?)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeImages",
                "ssm:PutParameter",
                "sts:AssumeRole",
                "ssm:GetParameter"
            ],
            "Resource": "*"
        }
    ]
}

EventBridgeへの登録方法

ほぼデフォルト設定。
image.png
image.png
image.png

(イベントパターン).json
{
  "source": ["aws.ec2"],
  "detail-type": ["EC2 AMI State Change"],
  "detail": {
    "State": ["available"]
  }
}

Eventを受信したら、用意したLambdaが実行されるようにターゲットを指定。
image.png

ParameterStoreへの登録確認

AWS Backupでバックアップが取得されると、イベントから連動してパラメータストアに登録されました。
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?