AWS Lambda Python で AMI の世代管理を自動化する


こちらの投稿で Lambda を使ってサーバレスに AMI の取得を自動化しました。
取得を自動化したら次は世代管理(一定数を超えたらpurge)の自動化ですね!
こちらも Lambda を使ってやってみました。

Lambda ファンクションの作成

AMI 取得の Lambda ファンクションと同様に、EC2 の操作権限のあるロールを指定します。

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

Code

今回も対象のインスタンス名を指定するかたちで、purge 処理を行います。
自身に紐付いている Image を取得順に並び替えて、保存したい世代数 GEM_NUM を超過した分を削除しています。
普通に Image を消すだけだと Snapshot との紐付けは消えるのですが、Snapshot 自体は残ってしまうので、Snapshot も明示的に削除するようにしています。

deregister_ami.py
# -*- coding: utf-8 -*-

import commands, boto3

TARGET_INSTANCE_NAME = "***" # Enter your target Instance Name
GEM_NUM = 2 # 保存世代数

def _(cmd):
    return commands.getoutput(cmd)

def handler(event, context):
    images = boto3.client('ec2').describe_images(Owners=["self"])["Images"]

    delete_count = len(images) - GEM_NUM
    targetImages = []
    for image in sorted(images, key=lambda x: x["CreationDate"]):
        if (delete_count == 0) :
            break
        elif image["Name"].count(TARGET_INSTANCE_NAME):
            targetImages.append(image)
            delete_count -= 1

    for targetImage in targetImages:
        ec2 = boto3.resource('ec2')
        ec2.Image(targetImage["ImageId"]).deregister()
        for block in targetImage["BlockDeviceMappings"]:
            ec2.Snapshot(block["Ebs"]["SnapshotId"]).delete()

Configuration

Handler は deregister_ami.handler としてください。
Timeout はデフォルトの 3秒終わらないことがあるかもしれません。
少し伸ばしましょう。

Event sources

私の場合は朝4時に AMI を取得しているので、
取得処理が終わっているであろう10分後に purge するように cron(10 4 ? * * *) としています。
-> 今回の本題からは外れますが AMI の取得は API を呼び出しに成功しても途中で失敗することがあります。
  ですので、例えば purge する Image がひとつもないときはその日の AMI 取得がうまくいかなかったとみなし、
  管理者に通知あるいはメールを送るといったことができるといいなーと思ってます。今度実装してみます。

制限

  • 対象インスタンス名は一つしか指定できません(取得の方も同様)が、これに関しては今回は Lambda を使うことが本題で対応しなかっただけで、対象を指定する変数を配列化すればすぐに修正できると思います。
  • 手動で取得した Image も削除対象になることがあります。purge判定は「指定したインスタンス名が含まれている」かつ「取得したタイミングが古い」の2点だけで判断しているためです。本当は自動で取った AMI に自動で取ったことがわかるようなタグを付与し、そのタグがあるものだけを自動 purge すべきです。これも実装しようと思えばできると思いますが、今回は対応していません。

まとめ

Python さえ書ければ運用スクリプトの多くを Lambda でサーバレス化できるような気がします。
次は、アプリロジックを書き、API Gateway と組み合わせて API を作ってみたいです。
アプリロジック書くなら Java にすべきでしょうか。
Lambda で採用する言語についてもいろいろ考察してみたいです。