ほりひログ

所属組織の製品 (Azure とか) に関連する内容が多めだけど、個人の見解であって、所属組織を代表する公式情報ではないです。

ACRの大掃除

Azure Container Registry(以下、ACR)、掃除してますか?

気づいたらAzure Container Registry(以下、ACR)内に不要なイメージがたまっていることも。

実際、あるタグをつけてACRにpush、その後ソースを修正して同じタグでpush、また少し変えて同じタグでpush、push、push、、、ということやっていたら、タグのついていないイメージ(マニフェスト?)が大量になっていた*1

なので今回はそんなタグのついていないイメージを削除してACRのお掃除を。

こういうことをやってたらしい

一回目のpush。
タグにlatestを付ける。

マニフェストダイジェスト タグ
sha256:012345... latest

ソースコードやDockerfileやらを修正して二回目のpush。
タグは同じくlatestを使う。

マニフェストダイジェスト タグ
sha256:012345... -
sha256:abcdef... latest

二回目のpushで追加されたイメージにlatestタグが付く。
一方でもともとlatestタグを持っていた一回目のpushで追加されたイメージは、タグは外れるだけでそのまま残る。

三回目のpush。
タグは同じく(ry

マニフェストダイジェスト タグ
sha256:012345... -
sha256:abcdef... -
sha256:7890ab... latest

latestタグは三回目にpushしたイメージにつく。
いままでpushしたイメージはタグが外れても全部残っている。

これを延々と繰り返し、タグなしイメージが大量に出来上がっていた。

コンテナーイメージを使う側(AKS, ACA, ACI, App Service, etc...)がタグを使ってイメージを指定する運用の場合には、タグが付いていないイメージは使われていないはずなので*2、削除していいはず。

なので、タグのないイメージを問答無用で削除する。

タグなしイメージを削除する

大体の流れはこのドキュメントに書いてある。

learn.microsoft.com

今回はタグなしのイメージだけを消したいので、そのやり方を以下に。

削除対象イメージのリストアップ

どのイメージにタグが付いているか、逆にタグがついていないかは az acr manifest list-metadata でわかる。

learn.microsoft.com

例えば、ACR名が acrsampleリポジトリ名が hello-worldなら、以下のコマンドで各イメージのメタデータが取れ、その中にtagsのフィールドがある場合はそのイメージについているタグが列挙される。

$ az acr manifest list-metadata --registry acrsample --name hello-world
[
  {
    "architecture": "amd64".
      :
    "digest": "sha256:012345...",
      :
    "tags": [
      "latest",
        :
    ]
  },
    :
  {
  }
]

逆に、タグなしイメージにはtagsフィールドがないので、これを使ってフィルターできる。

出力フォーマットはJSONなので、いったん全部出力してjqでフィルターしてもいい。
けど、--queryオプションを使いこなすとカッコいいのでJMESPathにチャレンジ。

$ az acr manifest list-metadata --registry acrsample --name hello-world  --query "[?tags == null].digest"  --output tsv

--query使ったついでにdigestだけ持ってくると、タグなしイメージのマニフェストダイジェスト一覧の出来上がり。

イメージの削除

イメージの削除は az acr repository delete

learn.microsoft.com

オプション--imageが単数形のとおり、一つずつしか消せない。
せっかくマニフェストダイジェストの一覧を取ったけど、このイメージ削除のコマンドをスクリプトでループさせるしかなさそう。

シェルスクリプトならこんな感じになるはず。

#!/bin/bash
REGISTRY="acrsample"
REPOSITORY="hello-world"
UNTAGGED_DIGESTS=($(az acr manifest list-metadata --registry "${REGISTRY}" --name "${REPOSITORY}" --query "[?tags == null].digest" --output tsv))
for digest in "${UNTAGGED_DIGESTS[@]}" ; do
  az acr repository delete --name "${REGISTRY}" --image "${REPOSITORY}@${digest}" --yes
done

一応 az acr repository deleteの実行時には確認のプロンプトが出るけど、ここでは強気の--yesオプションを付けているので注意。
あと--nameオプションの意味がレジストリになったりレポジトリになったりで多少わかりづらい。

「もっと簡単に消したいんだけど。。。」

acr-cliというのを使うとできるらしい。

github.com

さっきのスクリプトと同様、ACR acrsample内のリポジトリ hello-worldのタグなしイメージを消すならこれ一発。

$ acr purge --registry acrsample --filter "hello-world:*"  --untagged

簡単だった。 ただacr purgeはまだプレビューらしい。

「自動で定期的に消してほしいんだけど。。。」

acr-cliとACR Taskを組み合わせるとできるらしい。

ACR TaskはACRを参照とか操作できるエージェントに、スクリプト/コマンドを実行させる機能。
cron式で定期的なスケジュール指定も可能。

このACR Taskでさっきのacr purgeを実行させれば、定期的にタグなしのイメージを消すことができる。

具体的な設定はこのドキュメントに書かれているので割愛。

learn.microsoft.com

タグなしのイメージはあまり意識しずらいけど、

  • ACRの容量は確実に使っている
  • 付属ストレージの容量を超えると追加で課金される
  • 古いイメージに脆弱性があると、Defender for Cloudから警告が上がってくる

とあまりいいことはないので、ACRのお掃除は忘れずに。


*1:まじめにコンテナーイメージを管理/運用してたらこんなことはないかもしれないけど。。。

*2:マニフェストダイジェスト(≠タグ)を使ってイメージを指定している場合は、タグがないイメージも使われている可能性はある