コネヒト開発者ブログ

コネヒト開発者ブログ

AWSコスト削減の一環でecrmを使ってECRの不要イメージを削除した話

こんにちは、コネヒト プラットフォームグループの@yosshiです。

昨今、円安の進行によりAWSのコスト増が無視できない状況となっています。
このような状況下で、コスト削減関連のイベントに注目が集まるなど、コスト削減への関心が徐々に高まってきているように感じます。

弊社でもさまざまな方法でコスト削減施策を進めており、今回はその一環で「ecrm」というツールを使用しECRイメージを削除した話をしたいと思います。

弊社では、コンテナのオーケストレーションにAmazon ECSを主に使用しています。 ECSにタスクをデプロイする場合は、イメージをビルドした上でAmazon ECRにpushし、そのECRのイメージを使用しタスクを起動しています。 ECRはイメージが増えれば増えるほど、容量に応じてコストがかかるので、この機会に対応したいと考えていました。

ECRで発生するコスト

ECRではデータストレージの容量に応じて料金がかかります。
ap-northeast-1(アジアパシフィック(東京))のリージョンでは、GB/月当たり 0.10USDの料金が発生します。
※2024/01/17時点の情報。ECRでは上記とは別に転送コストなどが発生します。

参考:https://aws.amazon.com/jp/ecr/pricing/

ecrmとは?

ecrmはAmazon ECRから不要なイメージを安全に削除するOSSです。
github.com

こちらのブログに詳細が書いてありますので、詳しくはこちらをご確認ください。
techblog.kayac.com

ECRには元々ライフサイクルポリシーという機能があり、世代数やイメージプッシュからの日数に基づき古いイメージを自動的に削除することができるのですが、「現在のECSタスクで使用しているもの」という観点でチェックをしてくれるわけではないので、使用中のイメージを削除してしまうリスクがあると感じていました。

そこで調べていたところecrmの存在を知り、試してみることにしました。

試してみる

インストール(macOS で brew を使う場合)

$ brew install fujiwara/tap/ecrm

イメージ削除にあたり、削除対象を決めるための設定ファイルが必要になります。
AWSアカウントのcredentialを適切に環境変数などで設定した状態で 以下コマンドを実行することで、アカウントに存在するECRやECS、Lambdaのリソースを元に、設定ファイル(ecrm.yaml)を自動生成してくれます。

$ ecrm generate

実行すると設定ファイル(ecrm.yaml)が作成されました。
クラスタやタスク定義はワイルドカードのパターンで指定でき、prefixが記号([_/-])で区切れてまとめられそうなものは、適宜まとめたパターンで自動生成してくれます。

ecrm.yaml

clusters:
  - name_pattern: <cluster1>-*
  - name_pattern: <cluster2>-*
    ・
    ・
task_definitions:
  - name_pattern: <task_definition1>-*
    keep_count: 5
  - name_pattern: <task_definition2>-*
    keep_count: 5
    ・
    ・
lambda_functions:
  - name_pattern: <lambda_function1>-*
    keep_count: 5
    keep_aliase: true
  - name_pattern: <lambda_function2>-*
    keep_count: 5
    keep_aliase: true
    ・
    ・
repositories:
  - name_pattern: <repository1>-*
    expires: 30d
    keep_count: 5
    keep_tag_patterns:
      - latest
  - name_pattern: <repository2>-*
    expires: 30d
    keep_count: 5
    keep_tag_patterns:
      - latest
    ・
    ・

この設定ファイル(ecrm.yaml)を弊社の都合に合わせて修正していきます。

設定した条件 (削除対象外とするもの)

  • 現在使用中のイメージ
    • ECSクラスタで現在実行中のタスクに含まれるイメージ
    • ECSサービスで指定されているタスク定義に含まれるイメージ
  • ECSタスク定義で指定されているイメージ(タスク定義最新リビジョンから5世代分
  • Lambda関数で指定されているイメージ(Lambda最新バージョンから5世代分)
  • 90日以内に作成されたイメージ
  • タグ名にlatest, releaseがついているイメージ ※弊社ではリリース対象に左記のようなタグ名をつけています

上記の下線部は可変にできるので、適宜適切な内容に置き換えてください。 設定ファイル(ecrm.yaml)は以下のようになりました

clusters:
  - name_pattern: <cluster1>-*
  - name_pattern: <cluster2>-*
    ・
    ・
task_definitions:
  - name_pattern: <task_definition1>-*
    keep_count: 5
  - name_pattern: <task_definition2>-*
    keep_count: 5
    ・
    ・
lambda_functions:
  - name_pattern: <lambda_function1>-*
    keep_count: 5
    keep_aliase: true
  - name_pattern: <lambda_function2>-*
    keep_count: 5
    keep_aliase: true
    ・
    ・
repositories:
  - name_pattern: <repository1>-*
    expires: 90d
    keep_count: 5
    keep_tag_patterns:
      - *latest*
      - *release*
  - name_pattern: <repository2>-*
    expires: 90d
    keep_count: 5
    keep_tag_patterns:
      - *latest*
      - *release*
    ・
    ・

設定ファイル(ecrm.yaml)の編集が完了したら、どの程度イメージが削減できそうか確認します。

削除対象は以下コマンドで確認できます。

$ ecrm plan

実行したところ以下のようになりました。

REPOSITORY     |   TYPE    |    TOTAL     |    EXPIRED    |    KEEP      
---------------------------+-------------+--------------+---------------+--------------
<repository1>  | Image     | 256 (38 GB)  | -187 (27 GB)  | 69 (11 GB)      
<repository2>  | Image     | 227 (44 GB)  | -209 (41 GB)  | 18 (3.2 GB)  
<repository3>  | Image     | 92 (13 GB)   | -82 (12 GB)   | 10 (1.5 GB)  
<repository4>  | Image     | 109 (307 GB) | -57 (181 GB)  | 52 (126 GB)  
<repository5>  | Image     | 63 (67 GB)   | -52 (53 GB)   | 11 (14 GB)   
<repository6>  | Image     | 251 (2.2 GB) | -236 (2.0 GB) | 15 (190 MB)  
<repository7>  | Image     | 771 (67 GB)  | -760 (66 GB)  | 11 (862 MB)  
<repository8>  | Image     | 150 (75 GB)  | -135 (67 GB)  | 15 (7.8 GB)  
<repository9>  | Image     | 65 (22 GB)   | -60 (20 GB)   | 5 (1.7 GB)   
<repository10> | Image     | 138 (29 GB)  | -128 (27 GB)  | 10 (2.1 GB)  
<repository11> | Image     | 116 (21 GB)  | -104 (19 GB)  | 12 (2.2 GB)  
<repository12> | Image     | 927 (129 GB) | -910 (126 GB) | 17 (2.8 GB)  
<repository13> | Image     | 284 (55 GB)  | -231 (44 GB)  | 53 (11 GB)   
<repository14> | Image     | 57 (546 MB)  | -21 (186 MB)  | 36 (360 MB) 

トータルのイメージに対して削除対象がどの程度あるか(EXPIRED)、残るイメージがどの程度あるか(KEEP)がわかります。

実際に削除を実行する際には以下コマンドを実行します。

$ ecrm delete

実行した後、実際に削除されたかどうかを確認したいので再度ecrm planを実行します。

$ ecrm plan

実行結果

REPOSITORY       |    TYPE     |    TOTAL    | EXPIRED |    KEEP      
-----------------+-------------+-------------+---------+--------------
<repository1>    | Image       | 69 (11 GB)  |         | 69 (11 GB)   
<repository2>    | Image       | 18 (3.2 GB) |         | 18 (3.2 GB)  
<repository3>    | Image       | 10 (1.5 GB) |         | 10 (1.5 GB)  
<repository4>    | Image       | 52 (126 GB) |         | 52 (126 GB)  
<repository5>    | Image       | 11 (14 GB)  |         | 11 (14 GB)   
<repository6>    | Image       | 15 (190 MB) |         | 15 (190 MB)  
<repository7>    | Image       | 11 (862 MB) |         | 11 (862 MB)  
<repository8>    | Image       | 15 (7.8 GB) |         | 15 (7.8 GB)  
<repository9>    | Image       | 5 (1.7 GB)  |         | 5 (1.7 GB)   
<repository10>   | Image       | 10 (2.1 GB) |         | 10 (2.1 GB)  
<repository11>   | Image       | 12 (2.2 GB) |         | 12 (2.2 GB)  
<repository12>   | Image       | 17 (2.8 GB) |         | 17 (2.8 GB)  
<repository13>   | Image       | 53 (11 GB)  |         | 53 (11 GB)   
<repository14>   | Image       | 36 (360 MB) |         | 36 (360 MB)  

EXPIREDの列がブランクとなり、対象の不要イメージが削除されたことがわかります。

結果

今回のケースでは685GBのイメージの削減に成功しました。 現時点のAWSのコストベース(GB/月当たり 0.10USD)で換算すると、月間68.5USDの削減となります。
※2024/01時点のAWS ECRのコスト

感想

今回はecrmを使用してECRイメージを削除した話をしました。

金額としては小さいかもしれませんが、もともと使っていないイメージに対する余分なコストだったので、このタイミングで簡単に削減できてよかったなと思います。

コスト削減に注目が集まっている状況だと思うので、各社のコスト削減の参考になれば幸いです。

今回は単発でイメージの削除を行いましたが、今後は自動で定期実行する仕組みなども合わせて検討していきたいと考えています。