EC2 Systems ManagerでAMIの日次取得をやってみた

アイキャッチ AWS EC2

こんにちわ。大阪のガノタです。
EC2 Systems Managerの「Maintenance Windows」を使って、AMIを日次取得してみる機会があったのでご紹介します。
基本的には、過去のブログエントリの組み合わせで実現可能ですが、今回は設定の最初から最後までご紹介したいと思います。

今回の概要

以下の内容で行ってみたいと思います。

  • 特定タグの付いたインスタンスのAMIを日次で取得
  • 対象はAmazon Linuxを利用
  • AMIの保持は3世代
    • 指定世代よりも古いAMIは削除
  • AWS CLIでAMIの取得と簡易的な世代管理

手順の概要

主な作業項目は下記の通りです。

  • 対象インスタンスにSSM Agentのインストール
  • 対象インスタンスにタグ設定
  • IAM Roleの作成
  • メンテナンスウィンドウの作成
  • メンテナンスウィンドウにターゲットを設定
  • メンテナンスウィンドウにタスクを設定

それでは見ていきたいと思います。

作業手順

SSM Agentインストール

最初に対象インスタンスにSSM Agentをインストールします。インストール手順は下記に詳細があります。インストール作業はドキュメントの通りで難しいものではないので、詳細は割愛させて頂きます。

SSM エージェントのインストール - Amazon EC2 Systems Manager

対象インスタンスにタグ設定

今回は、「ami-backup」というタグが「true」になっているEC2を対象にしたいと思います。下記では3台のうち1台が停止している為、実際にAMIを作成できるのは稼働している2台になります。

01-ec2

IAM Roleの作成

まず、Maintenance Windowを実行するためのRoleを作成します。今回は「MySsmMainteWindow」という名前で作成し、「AmazonSSMMaintenanceWindowRole」 というポリシーをアタッチします。

02-ssmmainterole

次に信頼関係として 「ssm.amazonaws.com」 を追加します。

03-trustssm

追加するには 「Trust Relationships」 タブをクリックします。下記の様に「ssm.amazonaws.com」を追加します。

04-editrelation

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "ssm.amazonaws.com",
          "ec2.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

次にAMIを取得・削除するための権限をEC2のIAM Roleに追加します。また、AMIの取得は「Run Command」で実行される為、AmazonEC2RoleforSSMポリシーも追加します。

05-ec2rolessm

AMI操作のポリシー(DailyAmiBackup)は下記の内容で追加しています。要件に応じたポリシー内容にして下さい。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1491462535000",
            "Effect": "Allow",
            "Action": [
                "ec2:CreateImage",
                "ec2:DeregisterImage",
                "ec2:DescribeImages"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

メンテナンスウィンドウの作成

次にメンテナンスウィンドウを設定します。初めての場合は下記のようなページが表示されますが、このまま 「Create Maintenance Window」 をクリックします。

06-createmaintewindow

次の画面で詳細を設定します。
「Name」 はこのメンテナンスウィンドウの名称です。今回は「daily-ami-backup」としました。

実行タイミングは、今回は 「CRON」 形式を選択してcron(0 16 * * ? *)と設定しました。これは「日本時間のAM01:00」に指定の処理が実行されることを意味します。

その他の項目として「Duration」を「2」として、「Stop initiating tasks」を「1」にしています。これは 「メンテナンスウィンドウが終了する1時間前になれば新たなタスクは実行しない」 という意味になります。

07-settingwindow

尚、EC2 Systems Managerで指定できるCron書式は下記に詳細が記載されています。

Systems Manager の cron スケジュール - Amazon EC2 Systems Manager

メンテナンスウィンドウのターゲット設定

次に、メンテナンスウィンドウの実行対象を設定します。対象は 「ターゲット」 として設定します。

09-registertarget

他の設定方法として、画面下の「Targets」タブにある「Registar new targets」から設定しても構いません。

11-targets-regbuttom

今回は、タグを使ってターゲットを指定します。タグで制御できれば後から対象を変更することができて便利です。
下記のように 「Select targets by」 でターゲットの指定方法を 「Specifying tags」 にします。「Tag Filters」 でタグの指定と設定値を指定します。

10-target

ターゲットは複数設定できます。また、「Owner Information」 は任意の内容を入力して下さい。そのターゲットの内容が分かりやすいものがいいかと思います。無しでも構いません。

ターゲットの登録ができると下記のようになります。下記は複数のターゲットが設定されていますが、今回登録したターゲットは、タグ「ami-backup」が「true」のインスタンスになるので、「77c3〜」のIDのものになります。

16-targetdone

メンテナンスウィンドウにタスクを設定

次に、メンテナンスウィンドウのタスク内容を登録します。

12-task

タスクの登録は画面下の 「Tasks」 タブにある 「Schedule new task」 から設定しても構いません。

13-reg-taskbuttom

今回はAWS CLIを使うので、ドキュメントは 「AWS-RunShellScript」 を選択します。

14-document

「Task Priority」 はタスクの優先度です。複数タスクを登録する時はこの設定で制御します。今回は1つのタスクのみなので 「1」 にします。

「Resitered Targets」 は、このメンテナンスウィンドウで設定したターゲットの中から、実行したいターゲットを選択します。今回はタグ付けしたインスタンスが対象になるので、先程登録した「77c3〜」で始まるターゲットIDを選択します。

15-priority-targets

コマンドの内容は、実際に実行する内容を記載します。

17-commands

今回は下記の内容で登録します。

下記は、AMI名を 「AMI-<インスタンスID>-<取得年月日(yyyymmdd)>」 という形で取得して、「取得年月日」が3日前のAMIを削除するという内容になります。

空行があるとエラーになるので、ここでの表記として見やすくする為に「#」の行を入れています。

あくまでもサンプルなので、そのまま利用される際は自己責任でご利用下さい。

AMIDATE=`date "+%Y%m%d"`
AMIDATEVER=`date "+%Y%m%d" -d "-3 day"`
EC2ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
REGION=ap-northeast-1
###############################################################################
aws ec2 create-image \
  --region $REGION \
  --instance-id $EC2ID \
  --name "AMI-$EC2ID-$AMIDATE" \
  --description "AMI-$EC2ID-$AMIDATE" \
  --no-reboot
###############################################################################
DELAMIID=`aws ec2 describe-images \
  --region $REGION \
  --filters "Name=name,Values=AMI-$EC2ID-$AMIDATEVER" \
  --query "Images[*].ImageId" \
  --output text`
###############################################################################
aws ec2 deregister-image \
  --region $REGION \
  --image-id $DELAMIID

また、複数のEBSボリュームがアタッチされたインスタンスに対して、RootボリュームのEBSだけアタッチされたAMIを取得したいといった場合は、aws ec2 create-imageのオプションを追加する等コマンドを適宜修正して下さい。

例えば、下記のように--block-device-mappingsオプションで/dev/sdbとしてアタッチされている追加EBSは除外する、といった指定にします。

aws ec2 create-image \
  --region $REGION \
  --instance-id $EC2ID \
  --name "AMI-$EC2ID-$AMIDATE" \
  --description "AMI-$EC2ID-$AMIDATE" \
  --no-reboot \
  --block-device-mappings "[{\"DeviceName\": \"/dev/sdb\",\"NoDevice\":\"\"}]"

次の 「Role」 は、メンテナンスウィンドウ用に最初に作成した「MySsmMainteWindow」を選択します。

「Execute on」 はタスクを同時実行できるターゲットの数(Targets)、またはターゲット総数の割合(Percent)の指定です。今回のようにタグで多くのインスタンスを処理対象にしている場合に有用です。今回は数も少ないので 「1」 としています。

「Stop after」 は許容されるエラー数の指定です。新しいターゲットにタスクを送信する前に許容できるエラー数です。

18-role-concurrency-errors

マネージメントコンソールでは、実行結果が2500文字までとなる為、S3にも結果を出力しておくようにします。 次の「Advanced」の欄でバケット名などをそれぞれ指定します。

20-s3output

ここまでできたら、最後に「Register task」をクリックしてタスクを登録します。

マネジメントコンソール上の項目名について

先程設定した「Execute on」と「Stop after」の項目は、以前はそれぞれ「Max Concurrency」、「Max Errors」という表示でした。しかし今は変わっているので注意が必要です。

ただし、AWS CLIでは「MaxConcurrency」、「MaxErrors」と表示されるのでそれぞれの対応を覚えておくとよいかと思います。

マネジメントコンソールとの表記の違いをまとめると以下のようになります。

以前の表示名 今の表示名 AWS CLIの指定オプション名 AWS CLIの出力表示
Cutoff Stop initiating tasks --cutoff Cutoff
Max Concurrency Execute on --max-concurrency MaxConcurrency
Max Errors Stop after --max-errors MaxErrors

タスク実行と結果

以上の作業で日本時間のAM01:00になれば、対象インスタンスのAMIを取得して3日前のAMIが削除されます。
しかし、動作確認したいので、手動で実行時間を変えてしまいます。後で戻すことを忘れないようにしましょう。

下記のように対象のメンテナンスウィンドウを選んで 「Edit maintenance window」 を選択します。

21-editmainte

ここで実行時間を編集します。UTC での指定になります。

22-editschedule

タスクが実行される前のAMIは下記のようになっています。AMI名が 「AMI-[インスタンスID]-[yyyymmdd]」 となっています。
実行前は、「i-05ba〜」「i-0092〜」という2つのインスタンスのAMIが2017年4月4日〜6日の3つずつ存在しています。

23-beforeamis

タスクの実行が完了すると「History」タブに結果が表示されます。今回は成功したので「Status」に 「Success」 と表示されています。
詳細は「View datails」をクリックします。

24-history

次の画面でタスクが実行された詳細結果を確認できます。更に「View datails」をクリックします。

25-exehistory

上記で「View datails」をクリックすると、ターゲットの各インスタンスでの詳細を確認することが出来ます。
下記では「i-009〜」のインスタンスでの実行結果ですが「Run Command」として実行されていることが分かると思います。

26-datailruncmd

「Output」タブをクリックするとコマンド実行時の出力内容を確認出来ます。下記の「Output」欄にある「View Output」をクリックします。

27-output

aws ec2 create-imageを実行した結果が出力されています。

28-scriptoutput

S3バケットにも下記のように標準出力と標準エラー出力の2つのファイルが作成されていました。

29-s3output

標準出力の内容はこちらです。

30-stdout

話が少し外れてしまいましたが、AMIの結果も下記の通りとなり、4月7日取得のAMIが新たに作成されて、3日前の4月4日のAMIが削除されています。

32-afterami

最後に

AMIの定期的な作成はLambdaの方が柔軟にできると思いますが、EC2に関してはEC2 Systems Managerを活用すれば他にも色んなことができそうですね。
Lamnbdaの利用料金がどうしても気になる場合はこういった選択肢もあるかと思います。要件に応じて使い分けて頂ければと思います。

以上です。