EC2 Image Builder のイメージ更新毎に古いイメージとEBSスナップショットを削除してみた
古いイメージとEBSスナップショットを削除したい。
こんにちは!AWS事業本部のおつまみです。
みなさん、EC2 Image Builderで作成したイメージが残り続けて困った経験はありますか?私はあります。
EC2 Image Builderを検証で動かし続け、気づいたら20個以上のイメージを生み出していました。。
EC2 Image Builder では、パイプラインを実行する度にイメージを自動で作成してくれます。
ただし、EC2 Image Builder には古いイメージを削除する機能はありません。
そのため、古いイメージが残り続けることで、AMIに関連付いているEBSスナップショットの料金が発生してしまいます。
そこで今回はEC2 Image Builder のイメージ(AMI)更新毎に古いイメージとEBSスナップショットを削除してみたいと思います。
構成図
今回構築する構成です。
以下の流れで処理を実行します。
- EC2 Image Builderパイプライン で AMI作成時に SNSトピックを通知するように設定
- このSNSトピック通知をトリガーに Lambda関数を実行
- このLambda関数でEC2 Image Builderで作成した最新のイメージ以外の古いイメージとEBSスナップショットを削除
なお、今回試した構成はこちらのブログからヒントを得ました。ありがとうございます。
やってみた
まずはEC2 Image Builder以外の部分を構築します。
今回はLambdaとSNSトピックの作成にAWS SAMを使用しました。
AWS SAM初心者の方は、こちらのブログをご確認ください。
SAMで構築(Lambda+SNSトピック)
新規プロジェクト作成
今回はAWS SAMをインストールするのが手間だったので、CloudShellから実行します。
CloudShell起動後、sam init
コマンドを実行し、SAMの実行環境を作成します。(今回ランタイムはpython3.7を使用しました。)
sam init --runtime python3.7 --name delete-old-image-and-ebs-every-imagebuilder-run
以下の内容が対話方式で聞かれるため順に答えていきます。
Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location
1 - AWS Quick Start Templates
を選択。
Choose an AWS Quick Start application template 1 - Hello World Example 2 - Multi-step workflow 3 - Serverless API 4 - Scheduled task 5 - Standalone function 6 - Data processing 7 - Infrastructure event management 8 - Lambda EFS example 9 - Machine Learning
1 - Hello World Example
を選択。
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]:
N
を選択。
Would you like to enable monitoring using CloudWatch Application Insights? [y/N]:
N
を選択。
ここまででSAMの実行環境が作成されます。
次に以下のファイルをCloudShellにアップロードします。
- template.yml
- SNSトピックの作成
- Lambdaのランタイム設定、トリガー、アクセス権限など
- app.py
- Lambdaのコード
template.yaml
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: "delete old image and ebs every imagebuilder run" Resources: # SNS topic SnsTopic: Type: AWS::SNS::Topic Properties: TopicName: sns-topic-for-imagebuilder # Lambda function Function: Type: AWS::Serverless::Function Properties: Description: "delete old image and ebs every imagebuilder run" CodeUri: scripts/ Handler: app.lambda_handler Runtime: python3.7 Events: EventBridgeRule: Type: SNS Properties: Topic: !Ref SnsTopic Policies: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - Version: '2012-10-17' Statement: - Effect: Allow Action: - ec2:DescribeImages - ec2:DeregisterImage - ec2:DeleteSnapshot Resource: '*'
ポイントは、Lambdaの実行に必要なPoliciesの設定です。
AWSLambdaBasicExecutionRole
(AWS管理ポリシー)- 以下の操作権限を許可(インラインポリシー)
- AMIイメージのリストを取得 (ec2:DescribeImages)
- AMIイメージを削除 (ec2:DeregisterImage)
- EBS Snapshotを削除 (ec2:DeleteSnapshot)
app.py
import boto3 # 設定 REGION = 'ap-northeast-1' OWNER_ID = '123456789012' # 自分のAWSアカウントIDを入力 # AWS SDK (boto3) クライアントの作成 ec2 = boto3.client('ec2', region_name=REGION) # Image BuilderのAMIイメージのリストを取得 response = ec2.describe_images( Owners=[OWNER_ID], Filters=[{'Name': 'tag:Name', 'Values': ['my-japanese-windows-image']}] ) # AMIにタグ付けしたNameをValuesに入力 # 最新イメージ以外を削除 sorted_images = sorted(response['Images'], key=lambda x: x['CreationDate'], reverse=True) latest_image = sorted_images.pop(0) print(f"最新イメージ: {latest_image['Name']} (Image ID: {latest_image['ImageId']}, 作成日: {latest_image['CreationDate']})") for image in sorted_images: # AMIイメージを削除 print(f"削除: {image['Name']} (Image ID: {image['ImageId']}, 作成日: {image['CreationDate']})") ec2.deregister_image(ImageId=image['ImageId']) # EBSスナップショットを削除 for bdm in image['BlockDeviceMappings']: if 'Ebs' in bdm: snapshot_id = bdm['Ebs']['SnapshotId'] print(f"削除: スナップショット (Snapshot ID: {snapshot_id})") ec2.delete_snapshot(SnapshotId=snapshot_id)
EC2 Image Builderで作成されたイメージをタグを条件に取得、作成日順にソートし、最新イメージ以外のイメージとEBSスナップショットを削除しています。
ハイライトがかかっている部分は、自分のAWS環境に合わせて変更してください。
- OWNER_ID = '123456789012' # 自分のAWSアカウントIDを入力
- Filters=[{'Name': 'tag:Name', 'Values': ['my-japanese-windows-image']}] # AMIにタグ付けしたNameをValuesに入力
※ EC2 Image Builderで作成されたイメージへのタグ付けの設定方法は記事後半で説明しています。
アップロードしたファイルを下記の場所に格納します。
delete-old-image-and-ebs-every-imagebuilder-run ∟ template.yml ∟ scripts ∟ app.py
ビルド・デプロイ
delete-old-image-and-ebs-every-imagebuilder-run
配下に移動し、以下のコマンドを実行します。
sam deploy --guided
で、SAM CLI によるプロンプトを用いたガイドを有効になるため、ガイドに従ってYES
選択でデプロイできます。
sam build sam deploy --guided
ここでCloudFormationが実行されます。
CloudShellにSuccessfully created/updated stack - in ap-northeast-1
が表示されることを確認します。
リソースの確認
SAMで作成されたリソースを確認します。
Lambdaのコンソールに移動し、作成されたLambda関数を選択します。
Lambdaのトリガー
SNSトピックがトリガーとして、紐づいています。
実行ロール
紐づいている実行ロールを選択します。
許可ポリシーが正しいことを確認します。
次に、EC2 Image Builderの設定を行います。
EC2 Image Builderの設定
パイプラインやイメージレシピの詳細説明は割愛します。
EC2 Image Builderの構築から行いたい方は、こちらのブログをご確認ください。
作成したパイプラインに、以下の設定を追加します。
1.インフラストラクチャ設定
SAMで作成したSNSを紐付けます。
これによりAMI作成時にSNSトピックを通知するよう設定することができます。
2.ディストリビューション設定
AMIタグで任意のNameを付けます。
今回はmy-japanese-windows-image
にしました。
このタグにより、Lambdaの処理でAMIイメージのリストを取得することができます。
任意のNameをつけた場合は、Lambdaのコード修正も併せて行なってください。
いざ検証
1回目
作成したパイプラインを実行して、イメージができあがるのを待ちます。
イメージが使用可能
になっていることを確認しました。
1回目であるため、イメージは削除されず、残っています。
2回目以降
再度パイプラインを実行して、イメージができあがるのを待ちます。
2回目のイメージのみ残っており、1回目のイメージは削除されていました!
EBSスナップショットも1つだけ残っており、削除されていそうです!
最後に
今回はEC2 Image Builderのイメージ(AMI)更新毎に古いイメージとEBSスナップショットを削除する方法をご紹介しました。
最新のイメージとEBSスナップショットだけが残るようになったので、コストだけでなく、管理面的にもニッコリです。
最後までお読みいただきありがとうございました!
どなたかのお役に立てれば幸いです。
以上、おつまみ(@AWS11077)でした!
備忘
最初は要件を叶えるために、弊社くらにゃん(ChatGPT)に構成を考えてもらいました。
すると、EventBridgeが使えると教えてもらいました。
教えてもらった通りに実装しようと思いました。
しかし、EventBridgeのイベントソースでは、EC2 Image Builderはサポートされていませんでした。
どうやらEC2 Image Builderをターゲットに指定することはできますが、2023/5時点ではイベントソースとしては使用できないようです。
再度くらにゃんに聞いたところ、やはりImageBuilderはサポートされていないようでした。
くらにゃん(ChatGPT)の言ったことをなんでも鵜呑みにせず、自分の頭で考えることも重要だと感じました。