Amazon ECR リポジトリに移行するときに、重複するコンテナイメージを自動的に識別する
Amazon Web Services、Rishabh Yadav と Rwest Singla
概要
注意: 新規のお客様への AWS CodeCommit の提供は終了しています。AWS CodeCommit の既存のお客様は、通常どおりサービスを引き続き使用できます。詳細
このパターンでは、異なるコンテナリポジトリに保存されているイメージが重複しているかどうかを識別するための自動化されたソリューションを提供します。このチェックは、他のコンテナリポジトリから Amazon Elastic Container Registry (Amazon ECR) にイメージを移行する場合に有益です。
基本的な情報として、このパターンでは、イメージダイジェスト、マニフェスト、タグなど、コンテナイメージのコンポーネントについても説明します。Amazon ECR への移行を計画するときは、イメージのダイジェストを比較して、コンテナレジストリ間でコンテナイメージを同期することができます。コンテナイメージを移行する前に、重複を防ぐために、これらのイメージが Amazon ECR リポジトリに既に存在するかどうかを確認する必要があります。ただし、イメージダイジェストを比較して重複を検出するのが難しく、初期移行フェーズで問題が発生する可能性があります。 このパターンでは、イメージを正確に比較するのに役立つように、異なるコンテナレジストリに保存されている 2 つの類似イメージのダイジェストを比較し、ダイジェストが異なる理由を説明します。
前提条件と制限
アクティブな AWS アカウント
Amazon ECR パブリックレジストリ
へのアクセス 次の内容に関する知識。AWS のサービス
CodeCommit 認証情報が設定されていること (手順を参照)
アーキテクチャ
コンテナイメージコンポーネント
次の図に、コンテナイメージのコンポーネントの一部を示します。これらのコンポーネントについては、図の後に説明します。

用語と定義
以下の用語は、「Open Container Initiative (OCI): Image Format Specification
レジストリ: イメージのストレージと管理のためのサービス。
クライアント: レジストリと通信し、ローカルイメージと連携するツール。
プッシュ: イメージをレジストリにアップロードするためのプロセス。
プル: イメージをレジストリからダウンロードするためのプロセス。
blob: レジストリによって保存され、ダイジェストによって対処できるコンテンツのバイナリ形式。
インデックス: さまざまなコンピュータプラットフォーム (x86-64、ARM 64 ビットなど) やメディアタイプの複数のイメージマニフェストを識別するコンストラクト。詳細については、「OCI Image Index Specification
」を参照してください。 マニフェスト: マニフェストのエンドポイントを介してアップロードされるイメージまたはアーティファクトを定義する JSON ドキュメント。マニフェストは、記述子を使用してリポジトリ内の他の blob を参照できます。詳細については、「OCI Image Manifest Specification
」を参照してください。 ファイルシステムレイヤー: イメージのシステムライブラリとその他の依存関係。
設定: アーティファクトメタデータを含み、マニフェストで参照される blob。詳細については、「OCI Image Configuration
」を参照してください。 オブジェクトまたはアーティファクト: blob として保存され、設定とともに付随するマニフェストに関連付けられている概念的なコンテンツ項目。
ダイジェスト: マニフェストの内容の暗号化ハッシュから作成される一意の識別子。イメージダイジェストは、イミュータブルなコンテナイメージを一意に識別するのに役立ちます。ダイジェストを使用してイメージをプルすると、オペレーティングシステムまたはアーキテクチャで毎回同じイメージがダウンロードされます。詳細については、「Digests
」を参照してください。 タグ: 人間が読めるマニフェスト識別子。イミュータブルなイメージダイジェストと比較すると、タグは動的です。イメージを指すタグは、変化し、イメージ間で移動することができますが、基になるイメージダイジェストは同じままです。
ターゲットアーキテクチャ
次の図に示すのはこのパターンで提供されるソリューションのアーキテクチャ概要です。このアーキテクチャは Amazon ECR とプライベートリポジトリに保存されているイメージを比較して、重複するコンテナイメージを識別します。

ツール
AWS のサービス
CloudFormation を使用すると、AWS リソースをセットアップし、迅速かつ一貫したプロビジョニングを行い、AWS アカウント とリージョン全体でライフサイクル全体にわたってリソースを管理できます。
AWS CodeBuild は完全マネージド型の構築サービスです。ソースコードのコンパイル、ユニットテストの実行、すぐにデプロイできるアーティファクトの生成を行います。
AWS CodeCommit は、独自のソースコントロールシステムを管理することなく、Git リポジトリを非公開で保存および管理できるバージョン管理サービスです。
AWS CodePipeline は、ソフトウェアリリースのさまざまな段階を迅速にモデル化および設定し、ソフトウェアの変更を継続的にリリースするために必要なステップを自動化するのに役立ちます。
Amazon Elastic Container Registry (Amazon ECR) は、セキュリティ、スケーラビリティ、信頼性を備えたマネージドコンテナイメージレジストリサービスです。
コード
このパターンのコードは、GitHub リポジトリの Automated solution to identify duplicate container images between repositories
ベストプラクティス
エピック
| タスク | 説明 | 必要なスキル |
|---|---|---|
Amazon ECR パブリックリポジトリからイメージをプルします。 | ターミナルから次のコマンドを実行して、Amazon ECR パブリックリポジトリからイメージ
ローカルマシンへのイメージのプルが完了すると、イメージインデックスを表す次のプルダイジェストが表示されます。
| アプリ開発者、AWS DevOps、AWS 管理者 |
Amazon ECR プライベートリポジトリにイメージをプッシュします。 |
| AWS 管理者、AWS DevOps、アプリ開発者 |
Amazon ECR プライベートリポジトリから同じイメージをプルします。 |
| アプリ開発者、AWS DevOps、AWS 管理者 |
| タスク | 説明 | 必要なスキル |
|---|---|---|
Amazon ECR パブリックリポジトリに保存されている、イメージのマニフェストを見つけます。 | ターミナルから次のコマンドを実行して、Amazon ECR パブリックリポジトリからイメージ
| AWS 管理者、AWS DevOps、アプリ開発者 |
Amazon ECR プライベートリポジトリに保存されている、イメージのマニフェストを見つけます。 | ターミナルから次のコマンドを実行して、Amazon ECR プライベートリポジトリからイメージ
| AWS DevOps、AWS システム管理者、アプリケーション開発者 |
Docker によってプルされたダイジェストと、Amazon ECR プライベートリポジトリ内のイメージのマニフェストダイジェストを比較します。 | ここでの疑問は、docker pull コマンドによって得られるダイジェストが、イメージ docker pull に使用されるダイジェストは、レジストリに保存されているイメージマニフェストのダイジェストを表します。このダイジェストは、マニフェストにダウンロードされて Docker にインポートされるコンテンツのハッシュが含まれるため、ハッシュチェーンのルートとみなされます。 Docker 内で使用されるイメージ ID は、このマニフェストで この情報を確認するには、Amazon ECR のパブリックリポジトリとプライベートリポジトリで docker inspect コマンドの出力を比較します。
結果で、両方のイメージに同じイメージ ID ダイジェストとレイヤーダイジェストがあることを確認します。 ID: レイヤー: また、ダイジェストは、ローカルで管理されるオブジェクトのバイト数 (ローカルファイルはコンテナイメージレイヤーの tar) またはレジストリサーバーにプッシュされる blob に基づいています。ただし、blob をレジストリにプッシュすると、tar が圧縮され、ダイジェストは圧縮された tar ファイルで計算されます。そのため、docker pull ダイジェスト値の差は、レジストリ (Amazon ECR プライベートまたはパブリック) レベルで適用される圧縮によって発生します。 注記この説明は、Docker クライアントの使用に固有のものです。この動作は、nerdctl や Finch などの他のクライアントでは表示されません。プッシュおよびプル操作中にイメージが自動的に圧縮されないためです。 | AWS DevOps、AWS システム管理者、アプリケーション開発者 |
| タスク | 説明 | 必要なスキル |
|---|---|---|
リポジトリをクローン作成します。 | このパターンの GitHub リポジトリをローカルフォルダにクローンします。
| AWS 管理者、AWS DevOps |
CI/CD パイプラインをセットアップします。 | GitHub リポジトリには、AWS CodePipeline でパイプラインをセットアップするための CloudFormation スタックを作成する
パイプラインは、プライベートリポジトリ内にありパブリックリポジトリにも存在するイメージを識別するために、2 つのステージ (アーキテクチャ図に示すように CodeCommit と CodeBuild) でセットアップされます。パイプラインには、次のリソースが設定されています。
| AWS 管理者、AWS DevOps |
CodeCommit リポジトリに入力します。 | CodeCommit リポジトリに入力するには、以下の手順を実行します。
| AWS 管理者、AWS DevOps |
クリーンアップを行います。 | 料金が今後発生しないように、以下の手順に従ってリソースを削除します。
| AWS 管理者 |
トラブルシューティング
| 問題 | ソリューション |
|---|---|
ターミナルまたはコマンドラインから、CodeCommit リポジトリへのプッシュ、リポジトリからのプル、またはこのリポジトリとの接続を試みると、ユーザー名およびパスワードの入力を求められるため、IAM ユーザーの Git 認証情報を入力する必要がある。 | このエラーの一般的な原因は以下のとおりです。
オペレーティングシステムおよびローカル環境によっては、認証情報マネージャーのインストール、オペレーティングシステム内の認証情報マネージャーの設定、またはローカル環境のカスタマイズを行い、認証情報ストレージを使用する必要がある場合があります。例えば、コンピュータで macOS が実行されている場合は、Keychain Access ユーティリティを使用して認証情報を保存できます。コンピュータで Windows が実行されている場合は、Git for Windows と一緒にインストールされている Git 認証情報マネージャーを使用できます。詳細については、CodeCommit ドキュメントの「Setup for HTTPS users using Git credentials」と、Git ドキュメントの「認証情報の保存 |
Amazon ECR リポジトリにイメージをプッシュすると、HTTP 403、つまり「no basic auth credentials」というエラーが発生する。 | aws ecr get-login-password コマンドを使用して Docker への認証に成功した場合でも、docker push コマンドまたは docker pull コマンドからこれらのエラーメッセージが表示されることがあります。既知の原因は次のとおりです。
|
関連リソース
Automated solution to identify duplicate container images between repositories
(GitHub リポジトリ) Private images in Amazon ECR (Amazon ECR ドキュメント)
AWS::CodePipeline::Pipeline resource (CloudFormation ドキュメント)
追加情報
Amazon ECR パブリックリポジトリ内のイメージの Docker 検査の出力
[ { "Id": "sha256:f7cee5e1af28ad4e147589c474d399b12d9b551ef4c3e11e02d982fce5eebc68", "RepoTags": [ "<account-id>.dkr.ecr.us-east-1.amazonaws.com/test_ecr_repository:latest", "public.ecr.aws/amazonlinux/amazonlinux:2018.03" ], "RepoDigests": [ "<account-id>.dkr.ecr.us-east-1.amazonaws.com/test_ecr_repository@sha256:52db9000073d93b9bdee6a7246a68c35a741aaade05a8f4febba0bf795cdac02", "public.ecr.aws/amazonlinux/amazonlinux@sha256:f972d24199508c52de7ad37a298bda35d8a1bd7df158149b381c03f6c6e363b5" ], "Parent": "", "Comment": "", "Created": "2023-02-23T06:20:11.575053226Z", "Container": "ec7f2fc7d2b6a382384061247ef603e7d647d65f5cd4fa397a3ccbba9278367c", "ContainerConfig": { "Hostname": "ec7f2fc7d2b6", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"/bin/bash\"]" ], "Image": "sha256:c1bced1b5a65681e1e0e52d0a6ad17aaf76606149492ca0bf519a466ecb21e51", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "DockerVersion": "20.10.17", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/bash" ], "Image": "sha256:c1bced1b5a65681e1e0e52d0a6ad17aaf76606149492ca0bf519a466ecb21e51", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": null }, "Architecture": "amd64", "Os": "linux", "Size": 167436755, "VirtualSize": 167436755, "GraphDriver": { "Data": { "MergedDir": "/var/lib/docker/overlay2/c2c2351a82b26cbdf7782507500e5adb5c2b3a2875bdbba79788a4b27cd6a913/merged", "UpperDir": "/var/lib/docker/overlay2/c2c2351a82b26cbdf7782507500e5adb5c2b3a2875bdbba79788a4b27cd6a913/diff", "WorkDir": "/var/lib/docker/overlay2/c2c2351a82b26cbdf7782507500e5adb5c2b3a2875bdbba79788a4b27cd6a913/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:d5655967c2c4e8d68f8ec7cf753218938669e6c16ac1324303c073c736a2e2a2" ] }, "Metadata": { "LastTagTime": "2023-03-02T10:28:47.142155987Z" } } ]
Amazon ECR プライベートリポジトリ内のイメージの Docker 検査の出力
[ { "Id": "sha256:f7cee5e1af28ad4e147589c474d399b12d9b551ef4c3e11e02d982fce5eebc68", "RepoTags": [ "<account-id>.dkr.ecr.us-east-1.amazonaws.com/test_ecr_repository:latest", "public.ecr.aws/amazonlinux/amazonlinux:2018.03" ], "RepoDigests": [ "<account-id>.dkr.ecr.us-east-1.amazonaws.com/test_ecr_repository@sha256:52db9000073d93b9bdee6a7246a68c35a741aaade05a8f4febba0bf795cdac02", "public.ecr.aws/amazonlinux/amazonlinux@sha256:f972d24199508c52de7ad37a298bda35d8a1bd7df158149b381c03f6c6e363b5" ], "Parent": "", "Comment": "", "Created": "2023-02-23T06:20:11.575053226Z", "Container": "ec7f2fc7d2b6a382384061247ef603e7d647d65f5cd4fa397a3ccbba9278367c", "ContainerConfig": { "Hostname": "ec7f2fc7d2b6", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"/bin/bash\"]" ], "Image": "sha256:c1bced1b5a65681e1e0e52d0a6ad17aaf76606149492ca0bf519a466ecb21e51", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "DockerVersion": "20.10.17", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/bash" ], "Image": "sha256:c1bced1b5a65681e1e0e52d0a6ad17aaf76606149492ca0bf519a466ecb21e51", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": null }, "Architecture": "amd64", "Os": "linux", "Size": 167436755, "VirtualSize": 167436755, "GraphDriver": { "Data": { "MergedDir": "/var/lib/docker/overlay2/c2c2351a82b26cbdf7782507500e5adb5c2b3a2875bdbba79788a4b27cd6a913/merged", "UpperDir": "/var/lib/docker/overlay2/c2c2351a82b26cbdf7782507500e5adb5c2b3a2875bdbba79788a4b27cd6a913/diff", "WorkDir": "/var/lib/docker/overlay2/c2c2351a82b26cbdf7782507500e5adb5c2b3a2875bdbba79788a4b27cd6a913/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:d5655967c2c4e8d68f8ec7cf753218938669e6c16ac1324303c073c736a2e2a2" ] }, "Metadata": { "LastTagTime": "2023-03-02T10:28:47.142155987Z" } } ]