🐳

プライベートサブネットからDockerイメージを安全に取得する方法:ECR Pull Through Cache活用ガイド

に公開

はじめに

Amazon ECR(Elastic Container Registry)のPull Through Cache機能は、外部のコンテナレジストリからイメージを自動的にキャッシュし、ECR経由で配信する機能です。この機能により、Docker Hubなどの外部レジストリのレート制限を回避しながら、イメージの取得を高速化できます。

本記事では、AWS環境でコンテナを運用しているエンジニアの方向けに、Pull Through Cache機能の詳細な設定方法と実践的な活用方法を解説します。

Pull Through Cache機能とは

概要

Pull Through Cache(プルスルーキャッシュ)は、ECRが外部レジストリのプロキシとして機能し、初回アクセス時に自動的にイメージをキャッシュする仕組みです。2回目以降のアクセスでは、ECRにキャッシュされたイメージが返されるため、外部レジストリへのアクセスが不要になります。

主なメリット

🚀 レート制限の回避
Docker Hubの匿名ユーザーは6時間あたり100回、認証済みユーザーでも200回という制限があります。Pull Through Cacheを使用することで、この制限を効果的に回避できます。

⚡ パフォーマンスの向上
AWS内部ネットワークからECRへのアクセスは高速であり、外部レジストリと比較して大幅な速度向上が期待できます。特にECSからのイメージ取得時に効果を発揮します。

💰 コスト最適化
外部レジストリからの転送料金を削減でき、複数回同じイメージを取得する場合は特に効果的です。

対応している外部レジストリ

本記事執筆時点、以下のレジストリに対応しています:

  • Docker Hub (docker.io)
  • GitHub Container Registry (ghcr.io)
  • Microsoft Azure Container Registry
  • GitLab Container Registry
  • Quay.io
  • Kubernetes Registry (registry.k8s.io)

設定方法

前提条件

設定を開始する前に、以下の準備が必要です:

  • AWS CLIまたはAWSマネジメントコンソールへのアクセス権限
  • ECRの管理権限を持つIAMロール/ユーザー
  • 外部レジストリの認証情報(必要な場合)

ステップ1: Pull Through Cacheルールの作成

AWS CLIを使用した設定例を示します。Docker Hub用のルールを作成する場合:

# Docker Hub用のPull Through Cacheルールを作成
aws ecr create-pull-through-cache-rule \
    --ecr-repository-prefix "docker-hub" \
    --upstream-registry-url "registry-1.docker.io" \
    --region ap-northeast-1

GitHub Container Registry用の設定:

# GitHub Container Registry用のルール作成
aws ecr create-pull-through-cache-rule \
    --ecr-repository-prefix "ghcr" \
    --upstream-registry-url "ghcr.io" \
    --region ap-northeast-1

ステップ2: 認証情報の設定(オプション)

プライベートリポジトリや認証が必要なレジストリの場合、AWS Secrets Managerに認証情報を保存します:

# Docker Hub認証情報をSecrets Managerに保存
aws secretsmanager create-secret \
    --name ecr-pullthroughcache/docker-hub \
    --description "Docker Hub credentials for ECR Pull Through Cache" \
    --secret-string '{"username":"your-dockerhub-username","password":"your-dockerhub-token"}' \
    --region ap-northeast-1

認証情報をPull Through Cacheルールに関連付け:

# ルール作成(認証情報なし)
aws ecr create-pull-through-cache-rule \
    --ecr-repository-prefix "docker-hub" \
    --upstream-registry-url "registry-1.docker.io" \
    --region ap-northeast-1

# 認証情報の関連付けはマネジメントコンソールから行う必要があります

ステップ3: IAMポリシーの設定

ECSタスクやEC2インスタンスがPull Through Cacheを使用するために必要なIAMポリシー:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ecr:CreateRepository"
            ],
            "Resource": "*"
        }
    ]
}

使用方法

基本的な使用方法

Pull Through Cacheを経由してイメージを取得するには、ECRのURIフォーマットを使用します:

# ECRへのログイン
aws ecr get-login-password --region ap-northeast-1 | \
    docker login --username AWS --password-stdin \
    123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

# Docker Hubのnginxイメージを取得(Pull Through Cache経由)
docker pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/docker-hub/library/nginx:latest

初回実行時は外部レジストリからイメージが取得され、ECRに自動的にキャッシュされます。

ECSでの使用例

ECSタスク定義でPull Through Cacheを使用する設定:

{
    "family": "my-task",
    "networkMode": "awsvpc",
    "requiresCompatibilities": ["FARGATE"],
    "cpu": "256",
    "memory": "512",
    "taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
    "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
    "containerDefinitions": [
        {
            "name": "nginx",
            "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/docker-hub/library/nginx:latest",
            "essential": true,
            "portMappings": [
                {
                    "containerPort": 80,
                    "protocol": "tcp"
                }
            ]
        }
    ]
}

イメージURIの構成要素

Pull Through Cache使用時のイメージURIは以下の形式になります:
{アカウントID}.dkr.ecr.{リージョン}.amazonaws.com/{プレフィックス}/{イメージパス}

例:

  • Docker Hub: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/docker-hub/library/nginx:latest
  • GitHub: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/ghcr/owner/repo:tag

キャッシュの動作仕様

  • キャッシュ有効期限:24時間(デフォルト)
  • 自動更新:なし(手動でプルする必要あり)
  • タグの更新:latest タグも24時間キャッシュされる

動作確認とテスト

Pull Through Cacheの動作確認

設定が正しく動作しているか確認する方法を紹介します。

📝 ルールの確認

# 設定済みのPull Through Cacheルールを確認
aws ecr describe-pull-through-cache-rules --region ap-northeast-1

🧪 イメージ取得のテスト

# テスト用の軽量イメージを使用
docker pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/docker-hub/library/alpine:latest

# イメージが正常に取得できたか確認
docker images | grep alpine

🔍 キャッシュの確認

# ECRリポジトリの確認(自動作成されたリポジトリ)
aws ecr describe-repositories \
    --repository-names docker-hub/library/alpine \
    --region ap-northeast-1

# キャッシュされたイメージの詳細確認
aws ecr describe-images \
    --repository-name docker-hub/library/alpine \
    --region ap-northeast-1

パフォーマンステスト

キャッシュの効果を測定するスクリプト例:

#!/usr/bin/env python3
import time
import subprocess
import statistics

def pull_image(image_uri):
    """イメージをプルして所要時間を測定"""
    start_time = time.time()
    
    # 既存のイメージを削除
    subprocess.run(["docker", "rmi", image_uri], 
                   capture_output=True, text=True)
    
    # イメージをプル
    result = subprocess.run(["docker", "pull", image_uri], 
                          capture_output=True, text=True)
    
    end_time = time.time()
    return end_time - start_time

def test_performance():
    ecr_uri = "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com"
    image = f"{ecr_uri}/docker-hub/library/redis:7-alpine"
    
    print("Pull Through Cacheパフォーマンステスト")
    print("=" * 50)
    
    times = []
    for i in range(3):
        elapsed = pull_image(image)
        times.append(elapsed)
        print(f"試行 {i+1}: {elapsed:.2f}秒")
    
    print(f"\n平均時間: {statistics.mean(times):.2f}秒")
    print(f"最小時間: {min(times):.2f}秒")
    print(f"最大時間: {max(times):.2f}秒")

if __name__ == "__main__":
    test_performance()

プライベート環境での活用シーン

ECS Fargateのベストプラクティスとしてのプライベートサブネット配置

AWS Well-Architected Frameworkでは、ECS Fargateタスクをプライベートサブネットに配置することを推奨しています。これはセキュリティの観点から最も重要なベストプラクティスの1つです。しかし、プライベートサブネットからはインターネットへの直接アクセスができないため、Docker Hubなどの外部レジストリからイメージを取得する際に課題が生じます。

ECR Pull Through CacheとVPCエンドポイントを組み合わせることで、セキュリティを犠牲にすることなくこの課題を解決できます。

なぜプライベートサブネットが推奨されるのか

🛡️ セキュリティ上の利点

  1. 攻撃対象領域の最小化

    • パブリックIPアドレスを持たないため、インターネットから直接アクセスできない
    • DDoS攻撃やポートスキャンなどの脅威から保護
  2. 多層防御の実現

    • ALB/NLBを通じてのみアクセス可能(リバースプロキシパターン)
    • セキュリティグループとNACLによる二重のネットワーク制御
  3. コンプライアンス要件の充足

    • PCI DSS、HIPAA、金融規制などの要件に対応
    • データ漏洩リスクの最小化

典型的なアーキテクチャパターン

このアーキテクチャでは:

  • ユーザートラフィックはALB経由でのみアクセス
  • コンテナイメージはVPCエンドポイント経由で取得
  • アウトバウンド通信はNATゲートウェイ経由(必要な場合のみ)

VPCエンドポイントの設定

プライベートサブネットのECS FargateからECRにアクセスするために必要なVPCエンドポイント:

# 1. ECR API エンドポイント(必須)
aws ec2 create-vpc-endpoint \
    --vpc-id vpc-xxxxxxxxx \
    --service-name com.amazonaws.ap-northeast-1.ecr.api \
    --subnet-ids subnet-private-1a subnet-private-1c \
    --security-group-ids sg-vpc-endpoints \
    --vpc-endpoint-type Interface \
    --private-dns-enabled true

# 2. ECR Docker エンドポイント(必須)
aws ec2 create-vpc-endpoint \
    --vpc-id vpc-xxxxxxxxx \
    --service-name com.amazonaws.ap-northeast-1.ecr.dkr \
    --subnet-ids subnet-private-1a subnet-private-1c \
    --security-group-ids sg-vpc-endpoints \
    --vpc-endpoint-type Interface \
    --private-dns-enabled true

# 3. S3 エンドポイント(必須:イメージレイヤー取得用)
aws ec2 create-vpc-endpoint \
    --vpc-id vpc-xxxxxxxxx \
    --service-name com.amazonaws.ap-northeast-1.s3 \
    --route-table-ids rtb-private-1a rtb-private-1c \
    --vpc-endpoint-type Gateway

# 4. CloudWatch Logs エンドポイント(推奨:ログ送信用)
aws ec2 create-vpc-endpoint \
    --vpc-id vpc-xxxxxxxxx \
    --service-name com.amazonaws.ap-northeast-1.logs \
    --subnet-ids subnet-private-1a subnet-private-1c \
    --security-group-ids sg-vpc-endpoints \
    --vpc-endpoint-type Interface \
    --private-dns-enabled true

# 5. Secrets Manager エンドポイント(オプション:シークレット管理用)
aws ec2 create-vpc-endpoint \
    --vpc-id vpc-xxxxxxxxx \
    --service-name com.amazonaws.ap-northeast-1.secretsmanager \
    --subnet-ids subnet-private-1a subnet-private-1c \
    --security-group-ids sg-vpc-endpoints \
    --vpc-endpoint-type Interface \
    --private-dns-enabled true

コスト比較:NATゲートウェイ vs VPCエンドポイント

プライベートサブネットでの運用時のコスト比較:

💸 NATゲートウェイを使用した場合

  • NATゲートウェイ料金: $0.045/時間 × 2AZ = 約$65/月
  • データ処理料金: $0.045/GB
  • Docker Hubレート制限の影響あり

💰 VPCエンドポイント + Pull Through Cacheの場合

  • VPCエンドポイント: $0.01/時間 × 2エンドポイント = 約$15/月
  • S3エンドポイント: 無料
  • データ処理料金: $0.01/GB(エンドポイント経由)
  • Docker Hubレート制限を回避
  • 月間約$50のコスト削減

トラブルシューティングチェックリスト

プライベートサブネットでイメージ取得に失敗する場合の確認項目:

# 1. VPCエンドポイントの作成確認
aws ec2 describe-vpc-endpoints \
    --filters "Name=vpc-id,Values=vpc-xxxxxxxxx" \
    --query 'VpcEndpoints[*].[ServiceName,State]' \
    --output table

# 2. セキュリティグループのルール確認
aws ec2 describe-security-groups \
    --group-ids sg-vpc-endpoints \
    --query 'SecurityGroups[0].IpPermissions'

# 3. ECSタスクのネットワーク設定確認
aws ecs describe-tasks \
    --cluster my-cluster \
    --tasks $(aws ecs list-tasks --cluster my-cluster --query 'taskArns[0]' --output text) \
    --query 'tasks[0].attachments[0].details'

# 4. DNS解決テスト(デバッグ用EC2インスタンスから)
nslookup ecr.api.ap-northeast-1.amazonaws.com
nslookup dkr.ecr.ap-northeast-1.amazonaws.com

# 5. ECR認証トークンの取得テスト
aws ecr get-login-password --region ap-northeast-1

プライベート環境構築のポイント

この構成により、セキュリティベストプラクティスを遵守しながら、Docker Hubレート制限の回避とコスト最適化を同時に実現できます。

トラブルシューティング

技術的な問題と解決方法

❌ プライベートサブネットからイメージ取得できない場合

VPCエンドポイントのDNS設定を確認してください:

# VPCエンドポイントのDNS設定確認
aws ec2 describe-vpc-endpoints \
    --vpc-endpoint-ids vpce-xxxxx \
    --query 'VpcEndpoints[0].DnsOptions'

# PrivateDnsEnabledがtrueであることを確認

❌ 認証エラーが発生する場合

ECRへの認証が正しく行われていない可能性があります:

# ECR認証トークンの有効期限確認(12時間)
aws ecr get-authorization-token --region ap-northeast-1 \
    --query 'authorizationData[0].expiresAt' --output text

# 再認証
aws ecr get-login-password --region ap-northeast-1 | \
    docker login --username AWS --password-stdin \
    $(aws sts get-caller-identity --query Account --output text).dkr.ecr.ap-northeast-1.amazonaws.com

❌ リポジトリが自動作成されない場合

IAM権限が不足している可能性があります。以下の権限を確認:

# 現在のユーザー/ロールの権限確認
aws iam simulate-principal-policy \
    --policy-source-arn $(aws sts get-caller-identity --query Arn --output text) \
    --action-names ecr:CreateRepository \
    --resource-arns "arn:aws:ecr:ap-northeast-1:*:repository/docker-hub/*"

❌ キャッシュが更新されない場合

Pull Through Cacheは24時間のTTLがデフォルトです。強制的に最新のイメージを取得する場合:

# キャッシュされたイメージを削除
aws ecr batch-delete-image \
    --repository-name docker-hub/library/nginx \
    --image-ids imageTag=latest \
    --region ap-northeast-1

# 再度プルして最新版を取得
docker pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/docker-hub/library/nginx:latest

導入前の確認事項

既存のDockerfileの変更について

FROM文はECRのURIに変更が必要です:

  • 変更前:FROM nginx:latest
  • 変更後:FROM 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/docker-hub/library/nginx:latest

CI/CDパイプラインでの利用

CodeBuildやGitHub Actionsでも同様に利用可能です。ECRへの認証を追加するだけで、既存のパイプラインに組み込めます。

他AWSアカウントとの共有

Pull Through Cacheで取得したイメージは、通常のECRリポジトリと同様にクロスアカウントアクセスポリシーを設定できます。

プライベートレジストリの利用

認証が必要な外部レジストリも、Secrets Managerに認証情報を保存することで利用可能です。ただし、認証情報とルールの関連付けは現在マネジメントコンソールからのみ設定できます。

料金について

Pull Through Cache機能自体に追加料金はありません。通常のECRストレージ料金($0.10/GB/月)のみが発生します。

ベストプラクティス

🔒 セキュリティの考慮事項

最小権限の原則を適用し、必要なリポジトリパスのみにアクセスを制限します。以下は特定のプレフィックスのみを許可するポリシー例:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:BatchGetImage",
                "ecr:GetDownloadUrlForLayer"
            ],
            "Resource": [
                "arn:aws:ecr:ap-northeast-1:*:repository/docker-hub/library/*",
                "arn:aws:ecr:ap-northeast-1:*:repository/docker-hub/mycompany/*"
            ]
        }
    ]
}

イメージスキャンの有効化により、脆弱性を自動検出:

# リポジトリのスキャン設定(リポジトリが作成された後)
aws ecr put-image-scanning-configuration \
    --repository-name docker-hub/library/nginx \
    --image-scanning-configuration scanOnPush=true \
    --region ap-northeast-1

💰 コスト最適化

ライフサイクルポリシーを設定して、古いキャッシュを自動削除:

{
    "rules": [
        {
            "rulePriority": 1,
            "description": "30日以上古いイメージを削除",
            "selection": {
                "tagStatus": "any",
                "countType": "sinceImagePushed",
                "countUnit": "days",
                "countNumber": 30
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}

適用コマンド:

aws ecr put-lifecycle-policy \
    --repository-name docker-hub/library/nginx \
    --lifecycle-policy-text file://lifecycle-policy.json \
    --region ap-northeast-1

マネジメントコンソールでの設定

AWSマネジメントコンソールからも設定可能です:

  1. ECRコンソールを開く
  2. 左メニューの「プライベートレジストリ」→「Pull through cache」を選択
  3. 「ルールを作成」をクリック
  4. 必要事項を入力して作成

詳細は公式ドキュメントを参照してください。

制限事項と注意点

  • イメージサイズ制限: 最大10GBまで
  • リポジトリ数制限: アカウントあたり10,000リポジトリ
  • 同時プル数: リージョンごとに制限あり
  • 対応アーキテクチャ: マルチアーキテクチャイメージは各アーキテクチャごとにカウント

まとめ

Amazon ECRのPull Through Cache機能は、外部レジストリのレート制限問題を解決し、コンテナイメージの取得を高速化する強力な機能です。本記事で紹介した設定方法とベストプラクティスを活用することで、AWS環境でのコンテナ運用をより効率的に行えます。

特に大規模なECSやEKSクラスターを運用している場合、Pull Through Cacheの導入により、安定性の向上とコスト削減の両方を実現できます。セキュリティとコスト最適化の観点から、適切なIAMポリシーとライフサイクルポリシーの設定を忘れずに行いましょう。

今後もAWSは対応レジストリの拡充や機能強化を進めていくと予想されるため、定期的に最新情報をチェックすることをお勧めします。

参考リンク

株式会社ソニックムーブ

Discussion