78. ECRは内容のハッシュで引く倉庫である — タグは動く名札、ダイジェストは動かない指紋
ECRのなかで、なぜ「タグは動く名札」で「ダイジェストは動かない指紋」になるのか、イメージの指し方が2通りある理由を図で追っていきます。
① レジストリ ⊃ リポジトリ ⊃ イメージ — 3階層の入れ子
- レジストリのURIは {aws_account_id}.dkr.ecr.{region}.amazonaws.com。アカウントIDとリージョンで一意に決まる入口。
- ECRは「private repositories with resource-based permissions using AWS IAM」。リポジトリ単位でIAMのリソースベースポリシーを貼り、誰が push/pull できるかを縛る。
- リポジトリにはDockerイメージ・OCIイメージ・OCI互換アーティファクト(署名・SBOM・Helmチャート・スキャン結果・アテステーション等)が入る。
ECRは「入口(レジストリ)→アプリ棚(リポジトリ)→中身(イメージ)」の入れ子。アクセス制御はリポジトリという棚の単位でIAMポリシーとして貼る。API Gateway編で見た「AWSリソースにはIAMのリソースベースポリシーで境界を引く」のと同じ構図。
② イメージの指し方は2通り — 名札とハッシュ
- pull時の名前の形式は、タグ指定が {registry}/{repository}[:{tag}]、ダイジェスト指定が {registry}/{repository}[@{digest}]。
- ダイジェストの実例は sha256:f1d4ae3f7261a72e98c6ebefe9985cf10a0ea5bd762585a43e0700ed99863807(ECR公式のサンプル)。
- ダイジェスト=イメージマニフェスト(レイヤの一覧とメタデータ)のsha256ダイジェスト。ECRのAPI仕様が「The sha256 digest of the image manifest」と定義している。
- 1つのイメージが latest と 2016.09 の複数タグを同時に持てる一方、ダイジェストは中身から一意に決まる。
タグは人間が読むための名札で、あとから別のイメージに貼り替えられる。ダイジェストは中身をハッシュした指紋なので、中身が変わらない限り同じ値・中身が変われば必ず別の値になる。
③ コンテンツアドレッシング — 内容そのものが住所になる
- ダイジェスト指定のpullは、ハッシュが同じである限り常に完全に同一のバイト列を取得する。ハッシュは内容から一方向に決まるため、値が一致=中身が一致。
- これはDynamoDB編で見た「ハッシュは内容から一方向に決まる短い指紋」という性質が、そのままストレージの索引(住所)になっている実例。
- 設計としてはGitのコミットハッシュと同一の発想:名前(ブランチ名/タグ)ではなく内容のハッシュでオブジェクトを引く。
コンテンツアドレッシングとは「名前でなく内容そのものを住所にする」こと。だから本番で再現性を担保したいときは、動くタグではなく動かないダイジェストで固定する。
④ タグの怖さへの対策 — イミュータブルタグ
- リポジトリ作成時に何も指定しなければタグ可変性はデフォルトで MUTABLE(API仕様に「If this parameter is omitted, the default setting of MUTABLE will be used」と明記)。
- 「After tag immutability is turned on, the ImageTagAlreadyExistsException error is returned if you push an image with a tag that is already in the repository.」
- 「Tag immutability affects all tags. You cannot make some tags immutable while others aren't.」— IMMUTABLEは全タグ一律。
- 現行ドキュメントでは除外フィルタが存在する:CLIで --image-tag-mutability IMMUTABLE_WITH_EXCLUSION --image-tag-mutability-exclusion-filters filterType=WILDCARD,filter={filter-text}。逆にMUTABLEをベースに一部タグだけ不変化する MUTABLE_WITH_EXCLUSION(コンソールの「Mutable tag exclusion」)も用意されている。除外フィルタは1リポジトリあたり最大5個。
タグは動く名札ゆえ、latest は静かに別イメージへ貼り替わりうる。リポジトリをIMMUTABLEにすれば既存タグへの再pushを例外で弾き、名札を釘で打ち付けられる。前レッスンの「不変性」を、1レコードでなく運用ルール(リポジトリ設定)にまで広げた話。
⑤ 認証の両替 — IAMをDockerが話せる言葉に翻訳する
- 「The Docker CLI doesn't support native IAM authentication methods.」だからこの両替が要る。
- 「retrieve a base64-encoded authorization token containing the username AWS and an encoded password」「valid for 12 hours」。
- 「An authorization token's permission scope matches that of the IAM principal used to retrieve the authentication token.」— トークンの権限はIAMプリンシパルの権限のコピー。広くも狭くもならない。
- 1行の内訳: aws ecr get-login-password --region {region} | docker login --username AWS --password-stdin {account}.dkr.ecr.{region}.amazonaws.com
- HTTP APIでは Authorization: Basic $TOKEN として送る=Basic認証スキーム。
aws ecr get-login-password | docker login の1行は、IAM(SigV4)しか持たない自分を、Dockerが理解できるBasic認証トークン(ユーザー名AWS・12時間有効)に両替する処理。認証暗号編のSigV4と一時的認証情報の応用で、「プロトコルが違う相手には、IAMを相手の言葉へ翻訳して渡す」。トークンの権限は元のIAMと同じなので、翻訳しても権限は増えも減りもしない。
⑥ おまけ:ライフサイクルポリシー — 使われない指紋を規則で掃除する
- 「Lifecycle policies help with managing the lifecycle of the images in your repositories. You define rules that result in the cleaning up of unused images. You can test rules before applying them to your repository.」
ダイジェストで内容を貯め込む倉庫は放っておくと肥大するので、規則(ポリシー)で古い/未タグのイメージを自動削除する。S3編で見たライフサイクルの再登場で、対象がオブジェクトからコンテナイメージに変わっただけ。