OPS

AWS AMI の時間指定を行う方法とは?
夜間帯の運用負荷を軽減

2021.08.17

本記事のポイント

本記事では、夜間帯に出社したり、AWS Backupを使用したりせずに時間指定のAMI取得を可能にする方法をご紹介いたします。
また、時間指定をし「不定期作業を実行させる」AWS Lambdaの使い方も、合わせてお伝えします。

 

AWS AMIの取得における課題点

定期的なAmazon マシンイメージ(以下、AMI)の取得はAWS Backupで取得しているけれど、深夜帯の不定期なAMIの取得は手動で行っている、という方は多くいらっしゃるのではないでしょうか?

リモートワークでも、深夜帯の作業はできるだけ避けたいですよね。

そこで今回は、AWS Step FunctionsのWait機能を用いた時間指定での単発のAMI取得方法についてご紹介します。

>AWSの監視・運用代行サービス
>AWSが6%OFFで使える請求代行サービス

Step Functionsを用いた検証方法とは

今回の検証内容のイメージは以下の通りになります。

①AWSコンソールより、AMIを取得したいインスタンスIDとAMIの取得したい時間を入力
②Step FunctionsのWaitを用いて1.で指定した時間まで待機
③~⑤指定した時間を過ぎると、Lambdaが実行され停止→AMI取得→起動の処理が実行
⑥Step Functions完了後、指定の連絡先に完了報告が通知される

次は上記の検証を行うための事前準備をしていきます。

>AWSの監視・運用代行サービス
>AWSが6%OFFで使える請求代行サービス

時間指定のAWS AMI取得に必要な3つの準備

検証を行うために以下の事前準備が必要です。
・Lambda関数作成
・Simple Notification Service(以下、SNS)トピック作成
・Step Functions(ステートマシン)作成

Lambda関数の準備

今回の検証では以下4つの関数を使用します。
※検証ですので、Lambdaの実行ロールにAmazon EC2 Full Accessを付与しています。

1.Lambdaの名前:Get_status
機能:対象インスタンスのステータスを取得する
コード:下記を参照

import json
import boto3
   
ec2 = boto3.client('ec2')
def lambda_handler(event, context):
    instanceid = event
    print(instanceid)
    responce = ec2.describe_instances(
        InstanceIds=[
            instanceid,
            ],
        )
    return {
        'state': responce["Reservations"][0]["Instances"][0]["State"]["Name"],
    }


 

2.Lambdaの名前:Stop_instance
機能:対象インスタンスの停止を行う
コード:下記を参照

import json
import boto3
   
ec2 = boto3.client('ec2')
def lambda_handler(event, context):
    instanceid = event
    ec2.stop_instances(
        InstanceIds=[
            instanceid,
            ],
        )

 

3.Lambdaの名前:Start_instance
機能:対象インスタンスの起動を行う
コード:下記を参照

import json
import boto3
   
ec2 = boto3.client('ec2')
def lambda_handler(event, context):
    instanceid = event
    ec2.start_instances(
        InstanceIds=[
            instanceid,
            ],
        )

 

4.Lambdaの名前:Get_ami
機能:対象インスタンスのAMIを取得する
コード:下記を参照

import json
import boto3
ec2 = boto3.client('ec2')
def lambda_handler(event, context):
    instanceid = event["instanceid"]
    aminame = event["ami_name"]
    tagname = event["tag_name"]
    image_response = ec2.create_image(
        InstanceId = instanceid,
        Name = aminame,
        Description ='test',
        NoReboot=True,
    )
    ami_id = image_response["ImageId"]
    ec2.create_tags(
        Resources=[
            ami_id,
            ],
        Tags=[
        {
            'Key':'Name',
            'Value': tagname
        },
        ]
    )

SNSトピックの設定準備

まず、AWSマネジメントコンソールからAmazon SNSのダッシュボードに移動します。

・左側のナビゲーションペインからトピック→「トピックの作成」をクリック。
・タイプは、スタンダードを選択。名前は任意の値を入力。
・他の項目は全てデフォルトのまま、「トピックの作成」をクリック。
・トピックが作成された後は、「サブスクリプションの作成」をクリック
・プロトコルは、「Eメール」を選択し、エンドポイントは通知を受けたいメールアドレスを入力。
・他の項目は設定せず「サブスクリプションの作成」をクリック。
・エンドポイントに入力したメールアドレスに「AWS Notification – Subscription Confirmation」のメールを受信するので、本文内の「Confirm subscription」をクリック。
クリック後、サブスクリプションのステータスが「確認済み」になればトピックの作成は完了です。

Step Functions(ステートマシン)の作成

AWSマネジメントコンソールからAWS Step Functionsのダッシュボードに移動します。
左側のナビゲーションペインからステートマシン→「ステートマシンの作成」をクリック。
「コードでワークフローを記述」を選択。タイプは「標準」を選択。

以下コードを定義内にペーストします。
〓の箇所は各種リソースのARNとなるので、利用される際は〓の個所を適宜ARNに書き換えてください。

{
  "Comment": "inputデータの記入時間まで待機",
  "StartAt": "Wait",
  "States": {
    "Wait": {
      "Comment": "インスタンス停止後、60秒待機する",
      "Type": "Wait",
      "TimestampPath": "$.data.expirydate",
      "OutputPath": "$",
      "InputPath": "$",
      "Next": "Get_status"
    },
    "Get_status": {
      "Type": "Task",
      "Resource": "〓作成したLambda(Get_ status)のARN〓",
      "InputPath": "$.data.instanceid",
      "ResultPath": "$.result",
      "OutputPath": "$",
      "Next": "Check_instance"
    },
    "Check_instance": {
      "Type": "Choice",
      "Comment": "上記以外は再度インスタンスを確認する",
      "Choices": [
        {
          "Comment": "インスタンスが停止済みの場合AMIの取得を行う",
          "Variable": "$.result.state",
          "StringEquals": "stopped",
          "Next": "Get_ami"
        },
        {
          "Comment": "インスタンスが起動中の場合、インスタンスを停止する",
          "Variable": "$.result.state",
          "StringEquals": "running",
          "Next": "Stop_instance"
        }
      ],
      "Default": "wait_two_minutes"
    },
    "wait_two_minutes": {
      "Comment": "インスタンス停止後、60秒待機する",
      "Type": "Wait",
      "Seconds": 120,
      "OutputPath": "$",
      "InputPath": "$",
      "Next": "Get_status"
    },
    "Stop_instance": {
      "Comment": "インスタンスの停止を行う",
      "Type": "Task",
      "Resource": "〓作成したLambda(Stop_instance)のARN〓",
      "InputPath": "$.data.instanceid",
      "ResultPath": "$.result",
      "OutputPath": "$",
      "Next": "wait_one_minutes"
    },
    "wait_one_minutes": {
      "Comment": "インスタンス停止後、60秒待機する",
      "Type": "Wait",
      "Seconds": 60,
      "OutputPath": "$",
      "InputPath": "$",
      "Next": "Get_status"
    },
    "Get_ami": {
      "Comment": "AMIの取得を行う、取得後インスタンスを起動",
      "Type": "Task",
      "Resource": "〓作成したLambda(Get_ami)のARN〓",
      "InputPath": "$.data",
      "OutputPath": "$",
      "ResultPath": "$.result",
      "Next": "Start_instance"
    },
    "Start_instance": {
      "Comment": "インスタンスを起動",
      "Type": "Task",
      "Resource": "〓作成したLambda(Start_instance)のARN〓",
      "InputPath": "$.data.instanceid",
      "OutputPath": "$",
      "Next": "Complete"
    },
    "Complete": {
      "Comment": "完了メール",
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "〓作成したトピックのARNを入力〓",
        "Message": "Complete Backup"
      },
      "End": true
    }
  }
}

本件で使用している定義の詳細は以下の表を参照してください。
▼States一覧

コード入力後、以下と同様のワークフローが作成されていることを確認し、「次へ」。

ステートマシン名は任意の名前を入力し、実行ロールは「新しいロールの作成」を選択します。 他の項目は設定せず、「ステートマシンの作成」をクリック。問題なく作成されればステートマシンの作成は完了です。
これにて事前準備が完了したので、実際に時間を指定してAMIの取得を行っていきます。

>AWSの監視・運用代行サービス
>AWSが6%OFFで使える請求代行サービス

時間指定をしてAMIを取得する方法を実践

早速ですが、時間を指定してAMIの取得を行っていきます。

1.AWSマネジメントコンソールからStep Functions選択
2.先程作成したステートマシンをクリック
3.「実行の開始」をクリック
4.以下の入力テンプレートを用いてデータを入力

■入力テンプレート
{
  "data":{
    "instanceid": "取得したいインスタンスのインスタンスID",
    "expirydate": "AMIの取得を行いたい時間(UTC表記)",
    "ami_name": "AMI名",
    "tag_name": "TAG名"
  }
}

■入力例
※日本時間の2021-04-01 3:00にAMIを取得したい場合
{
  "data":{
    "instanceid": "i-123456789abcdef",
    "expirydate": "2021-03-31T18:00:00Z",
    "ami_name": "Aminame",
    "tag_name": "Tagname"
  }
}

5.入力後、実行開始をクリックしexpirydateの時間まで待機され、expirydateの時間を経過すると処理が実行されます。

6.AMIの取得が完了すると以下のメールを受信します。

取得したAMIを確認していきます。
以下のように指定した内容のAMIが取得できています。
処理後のステートマシンの結果も確認していきます。

「Stop_instance」が実行されてから1分以内にインスタンスが停止したため「Wait_two_minutes」は実行されていません。

Waitを設ける理由は、待機時間を設定することで、「タスク遷移数が多くなり無料枠を超える」ことを防ぐことができるためです。
※緑色が成功。白色が未実行。

結果として、指定した時刻でAMIを取得することができました。

最後に

今回は、Step Functionsを用いた「時間指定をしてAMIの取得を行う方法」をご紹介しました。
事前に作業したい時間を指定しておけば、深夜帯でも早朝帯でも手作業をせずにゆっくり過ごすことができますね。

また、Lambdaの内容さえ変更すれば、他の作業も時間指定して実行させることが可能です。
不定期かつ頻度の高い作業は関数化して、Step Functionsで時間を指定して実行させていきましょう。

>AWSの監視・運用代行サービス
>AWSが6%OFFで使える請求代行サービス

なお、当社ではAmazon Web Service(以下、AWS)の構築支援や AWSの運用監視を代行するサービス、AWSが6%OFFで使える請求代行サービス をご提供しています。
AWSに関してお困りのことがございましたら、ぜひお気軽にご相談ください。

関連リンク

● AWSの監視・運用代行サービス
● AWSが6%OFFで使える請求代行サービス