ECR — イメージレジストリ
ECS と Lambda が取りに行くコンテナイメージをどこに保管するかを整理します。Amazon ECR の private / public の違い、IAM 認証、docker push / pull、イメージスキャン、タグ戦略、ライフサイクルポリシー、マルチアーキテクチャ(linux/amd64 + arm64)、VPC Endpoint とクロスアカウントアクセスまでを扱います。
直前の 第15章 ECS と Fargate でコンテナ運用の絵を固めました。ここで欠けているのは、その ECS / Fargate が取りに行くイメージがどこにあるのかです。Docker Hub のような外部レジストリも可能ですが、AWS の中では標準が Amazon ECR (Elastic Container Registry) です。
本章は ECR の構造をまとめて整理します — private / public の違い、IAM 認証、イメージのプッシュ / プル、セキュリティ(スキャン、タグの不変性)、運用(ライフサイクルポリシー、マルチアーキテクチャ)です。ここで固める push / pull の流れとライフサイクルポリシーは、4部 第22章 ECS Fargate デプロイの骨格 と 第24章 CI/CD パイプライン で毎回登場します。
イメージレジストリの役割 #
Docker の流れを思い出してみます。
docker build → ローカルイメージ
↓
docker push → レジストリ (リモート)
↓
docker pull (別のマシン) → そのイメージを取得して docker runレジストリはその中間地点です。誰が、どこで、どのバージョンのイメージを受け取れるかを決定します。
オプション比較 #
| レジストリ | 用途 |
|---|---|
| Docker Hub | 最も有名。無料だが pull 制限、public がデフォルト |
| GHCR (GitHub Container Registry) | GitHub アカウントと連携。private の無料枠が大きい |
| Amazon ECR Private | AWS の中で IAM で認証。ECS / Lambda / EKS と自然に連携 |
| Amazon ECR Public | OSS 配布用。誰でも anonymous pull |
| GCR / Azure ACR | 他クラウド用 |
ECS / Lambda / EKS が AWS の中にあるなら ECR が標準です。
- IAM で認証します — 別途のパスワード管理がありません。
- VPC Endpoint でインターネットを通らずに pull します (NAT コスト節約)。
- 同じリージョンなので pull が速いです。
- イメージスキャン (脆弱性の自動分析) が統合されます。
Private vs Public #
ECR は2種類です。
Private (ほとんどの場合) #
自分のアカウントのユーザー / ロールだけがアクセスできます。会社 / 運用ワークロードはほぼすべてここです。
- リージョン単位 (イメージごとにリージョンが刻まれます)
- IAM ポリシーでアクセス制御
- コスト: GB 保管 + Data Transfer
Public (OSS 配布 / 学習資料) #
世界中の誰でも anonymous pull が可能です。AWS が運用する Public Gallery に露出します。
- 常に
us-east-1にホスティング (グローバル) - Push は IAM 認証、Pull は無認証
- コスト: GB 保管 + Data Transfer (push 側)
本章は Private を基準に進めます。
Repository を作る #
ECR の単位は Repository です。1つの repo の中に同じアプリの複数のバージョン (タグ) を保管します。
aws ecr create-repository \
--repository-name myapp \
--region ap-northeast-2 \
--image-scanning-configuration scanOnPush=true \
--encryption-configuration encryptionType=AES256成功すると URI です。
123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myappこれがすべての push / pull のアドレスです。形は次のとおりです。
<アカウントID>.dkr.ecr.<リージョン>.amazonaws.com/<repo>:<タグ>オプション整理 #
| オプション | 意味 |
|---|---|
image-scanning-configuration scanOnPush=true | push 時に自動で脆弱性スキャン |
image-tag-mutability IMMUTABLE | 同じタグの上書き禁止 — 運用推奨 |
encryption-configuration encryptionType=KMS | ユーザー管理 KMS キーで暗号化 |
コンソールで GUI でも同じように作れます。
認証 — aws ecr get-login-password
#
Docker Hub と違い ECR は AWS IAM で認証します。パスワードが別途ありません。代わりに一時トークンを受け取って docker login します。
aws ecr get-login-password --region ap-northeast-2 \
| docker login --username AWS --password-stdin \
123456789012.dkr.ecr.ap-northeast-2.amazonaws.comトークンは 12時間有効です。CI では毎回新しく受け取って使うのが自然です (CI ジョブの開始時に一度)。
必要な権限 #
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage",
"ecr:BatchGetImage"
],
"Resource": "arn:aws:ecr:ap-northeast-2:123456789012:repository/myapp"
}
]
}GetAuthorizationToken だけが * 資源で、残りは特定の repo に制限します (第6章 セキュリティ基本 の最小権限)。
Pull だけする権限 #
ECS Task の Execution Role のように pull だけすればよいです。AWS マネージドポリシー AmazonECSTaskExecutionRolePolicy が ECR pull 権限を自動で含みます。
Push / Pull #
Push #
# ビルド
docker build -t myapp:v1 .
# タグ (ECR URI に)
docker tag myapp:v1 \
123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v1
# ログイン (上を参照)
aws ecr get-login-password --region ap-northeast-2 | docker login ...
# push
docker push \
123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v1イメージが 100MB なら最初の push は 100MB のアップロードです。次からはレイヤー単位のキャッシングなので変更された部分だけが上がり、通常は数 MB です。
Pull #
docker pull 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v1ECS / Lambda は自動で pull します。コンソールで直接やることはほとんどありませんが、デバッグ時に有用です。
タグ戦略 #
ECR repo の中で同じイメージの複数のバージョンをどう呼ぶかに関するルールです。よく見るパターンです。
1) Semver #
myapp:1.4.2
myapp:1.4
myapp:1
myapp:latestライブラリ / ツールのように外部に配布する用途に自然です。運用では latest が危険です (どの時点の latest なのか曖昧)。
2) Git SHA #
myapp:abc1234 ← short sha
myapp:abc1234567... ← full shaCI でビルドした commit と 1:1 でマッチします。運用に最もおすすめする方式です — どの commit が運用にあるかを即座に追跡できます。
3) 環境 + シーケンス #
myapp:prod-2025-04-01.001
myapp:staging-2025-04-01.005リリースを日付ごとに数える用途で使います。
4) マルチタグ #
運用推奨パターンは immutable + alias です。
docker tag myapp:abc1234 myapp:abc1234 # 不変 (永遠にそのまま)
docker tag myapp:abc1234 myapp:prod-current # 可変 (現在の運用を指す)ECR repo 自体は IMMUTABLE (一度 push したタグを上書きできない) にしておき、alias が必要なら別のツール (deployment system) が管理します。
イメージスキャン #
ECR は push したイメージの脆弱性を自動でスキャンしてくれます。scanOnPush=true オプションです (上で設定)。
2種類 #
| 種類 | 何 | コスト |
|---|---|---|
| Basic Scanning | open source CVE DB (CoreOS Clair) ベースの単発スキャン | 無料 |
| Enhanced Scanning | Inspector 統合。OS レイヤー + 言語ライブラリ (npm、pip など) まで。継続モニタリング (イメージ push 後にも新しい CVE 発見時にアラート) | repo あたり時間 / イメージあたり |
運用ワークロードは Enhanced を検討します。Basic も最初の出発には十分です。
結果を見る #
aws ecr describe-image-scan-findings \
--repository-name myapp \
--image-id imageTag=v1コンソールでは repo → イメージ → “Vulnerabilities” タブで CRITICAL / HIGH / MEDIUM / LOW の数がひと目で見えます。
ビルド段階で遮断する #
CRITICAL があればデプロイを止めます — CI ジョブで次を置きます。
CRITICAL=$(aws ecr describe-image-scan-findings \
--repository-name myapp --image-id imageTag=$SHA \
--query 'imageScanFindings.findingSeverityCounts.CRITICAL' \
--output text)
if [ "$CRITICAL" != "None" ] && [ "$CRITICAL" -gt 0 ]; then
echo "🚨 CRITICAL CVE 発見。デプロイ中断。"
exit 1
fiこのゲートは 第24章 CI/CD パイプライン でビルド段階にそのまま挟み込みます。
ライフサイクルポリシー — 自動整理 #
イメージが積もると ECR コストが来ます。ライフサイクルポリシー で自動整理します。
{
"rules": [
{
"rulePriority": 1,
"description": "untagged イメージを7日後に削除",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "最新30個だけ維持 (それ以外は削除)",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 30
},
"action": { "type": "expire" }
}
]
}aws ecr put-lifecycle-policy \
--repository-name myapp \
--lifecycle-policy-text file://lifecycle.jsonよくあるパターンは次のとおりです。
- untagged を 7 ~ 14日後に削除 (失敗したビルドの残骸)
- タグ prefix
pr-のものを 30日後に削除 (PR プレビューイメージ) - タグ prefix
release-は永久保存
運用ワークロードは1年分のイメージが累積すると GB 単位のコストがかかります。ライフサイクルを最初に固めておくことが運用衛生の核心です。
マルチアーキテクチャイメージ #
Apple Silicon Mac (arm64) でビルドしたイメージをそのまま運用 (通常は amd64) に push するとブートしません。2つの道があります。
1) buildx で多プラットフォーム push #
docker buildx create --use
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v1 \
--push .ECR の1つのタグ (v1) の中に2つのアーキテクチャが一緒に入る manifest list です。pull 側が自分のアーキテクチャに合うものを自動選択します。
2) Fargate ARM で統一 #
第15章 Fargate で task definition の runtimePlatform.cpuArchitecture: ARM64 にしておくと、ARM 専用イメージだけ push すればよくなります。単価が約 20% 安いボーナスがあります。
{
"runtimePlatform": {
"cpuArchitecture": "ARM64",
"operatingSystemFamily": "LINUX"
}
}小 / 中トラフィックの新規プロジェクトは最初から ARM をおすすめします。
VPC Endpoint — NAT なしで pull #
private subnet の ECS Task が ECR から pull すると、基本は NAT Gateway 経由なので GB あたりで課金されます。
ECR は VPC Endpoint をサポートして NAT を迂回します。
# api 呼び出し用
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx \
--service-name com.amazonaws.ap-northeast-2.ecr.api \
--vpc-endpoint-type Interface \
--subnet-ids subnet-aaa subnet-bbb
# イメージ layer ダウンロード用
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx \
--service-name com.amazonaws.ap-northeast-2.ecr.dkr \
--vpc-endpoint-type Interface \
--subnet-ids subnet-aaa subnet-bbb
# イメージ layer が S3 に生きているので S3 endpoint も一緒に
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx \
--service-name com.amazonaws.ap-northeast-2.s3 \
--vpc-endpoint-type Gateway \
--route-table-ids rtb-xxx3つ (api、dkr、s3) で1セットです。NAT Gateway コストを大きく減らしてくれます — 運用トラフィックが大きい環境ではほぼ必須です。VPC と endpoint の深さは 第28章 VPC 深掘り でさらに扱います。
クロスアカウントアクセス #
prod アカウントの ECR repo を dev アカウントから pull したいなら Repository Policy で許可します。
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowDevAccountPull",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::222222222222:root"
},
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
]
}
]
}aws ecr set-repository-policy \
--repository-name myapp \
--policy-text file://repo-policy.json原則は次のとおりです。運用イメージは運用アカウントの ECR に一度だけ置き、他のアカウントは pull します。同じイメージを環境ごとのアカウントに重複ビルドしません。マルチアカウントガバナンスは 第29章 セキュリティガバナンス で扱います。
コスト #
| 項目 | 価格 (ソウルリージョン) |
|---|---|
| Storage | GB / 月 $0.10 |
| Data Transfer Out (インターネット) | GB $0.126 (1GB 無料) |
| Data Transfer Out (同じリージョン) | 無料 |
| Enhanced Scanning | イメージあたり + repo あたり時間 |
同じリージョンの中の ECS が pull すれば無料です。インターネットに出る (CI / 外部ツール) pull だけがコストです。ライフサイクルポリシーで storage だけ抑えればコストはほぼ 0 に近いです。
よく出会う落とし穴 #
1) denied: ... is not authorized to perform: ecr:...
#
権限漏れです。両方を確認します。
- ユーザー / ロールのポリシーに ECR action が入っているか
- Repository Policy が遮断していないか (通常は空 — 空なら IAM ポリシーだけで十分)
2) manifest unknown または repository ... not found
#
99% はリージョン / アカウント ID の打ち間違いです。URI の ap-northeast-2 の位置、123456789012 の位置をもう一度確認します。
3) IMMUTABLE repo に同じタグを push
#
同じタグを2回 push しようとすると拒否されます。意図された動作で運用推奨です。CI ジョブで commit SHA でタグを付ける形で回避します。
4) マルチアーキテクチャの抜け #
Mac (ARM) でビルド → push → x86_64 Fargate で exec format error が出ます。buildx で multi-arch するか、task definition を ARM で統一します。
5) NAT Gateway コストの爆発 #
ECR pull が NAT を通ると GB あたりで課金されます。VPC Endpoint の3つ (api / dkr / s3) を追加します。
6) イメージの累積 #
ライフサイクルポリシーなしで1年運用すると数千個のイメージが GB 単位のコストを作ります。最初に repo を作るときにライフサイクルも一緒に置きます。
練習問題 #
- 自分のアプリのイメージにどのタグ戦略を使うか §「タグ戦略」の4つのパターンから1つを選び、運用で
latestを使わない理由を1行で書いておきましょう。第24章 CI/CD パイプライン で CI が commit SHA でタグを付けるとき、この決定が基準になります。 - private subnet の ECS Task が ECR から pull するとき、NAT Gateway を通る経路と VPC Endpoint(api / dkr / s3)を通る経路のコスト差を §「VPC Endpoint」と §「コスト」を根拠に1段落で説明してみましょう(第15章 ECS と Fargate の NAT コストの落とし穴とまとめてみます)。
- ライフサイクルポリシーで untagged イメージを7日で削除 + 最新30個を維持するルールを適用すると、1年間毎日1回ずつデプロイするとき repo に残るイメージ数がおおよそいくつになるかを §「ライフサイクルポリシー」を根拠に推定してみましょう。
一行まとめ: ECR は AWS の中のコンテナイメージレジストリで、ECS / Lambda / EKS と IAM で連携し、運用では Private repo を使います。認証は 12時間のトークンを受け取る
aws ecr get-login-passwordで、運用推奨タグは Git SHA + IMMUTABLE。push 時にイメージスキャンで CRITICAL を CI で遮断し、ライフサイクルポリシーでイメージを自動整理します。マルチアーキテクチャは buildx または Fargate ARM で解決し、VPC Endpoint(api · dkr · s3)で NAT コストを回避します。
次の章 #
ECS と ECR はコンテナが常に立ち上がっているモデルです。次の 第17章 Lambda 基礎 では反対側 — リクエストが来たときだけ関数が目覚めるサーバーレス — を扱います。Lambda の動作方式、runtime / handler / イベントモデル、コールドスタート、同時実行、ロギングまで AWS サーバーレスの最初のボタンを整理します。