Docker Hub の Rate Limit 対策としてArtifact Registry のリモートリポジトリを使う

docker
Google Cloud
GKE

2025-09-20

#はじめに

最近、業務でEKSのクラスタを構築して、その際、ECRのPull through cacheを利用してDocker HubのRate Limit対策を行いました。
GKEで同様のことをしたいと思い、調べたところ、Artifact Registryのリモートリポジトリを利用することで同様のことができることがわかりました。
今回は、Artifact Registryのリモートリポジトリを利用したDocker HubのRate Limit対策について解説します。

#背景

Docker Hubの6時間あたりのプルレート制限は、認証されていないユーザーの場合、IPv4 アドレスまたは IPv6 /64 サブネットごとに 100という記述が有ります。

Pulls
Learn about pull usage and limits for Docker Hub.
Pulls favicon docs.docker.com
Pulls

EKSなど商用向けのクラスタを構築する際、Rate limitに引っかかった場合のリスクが大きいため、対策が必要です。
また、静的なNodeのk8sクラスタであれば、イメージをPullするタイミングは構築時とクラスタの更新タイミングなど限定的ですが、EKSのAutoModeなどを利用している場合、ノードのスケールアウトやスケールインのタイミングでPullが発生するため、Rate limitに引っかかるリスクが高くなります。
そのため、EKSであればECRのPull through cache、GKEであればArtifact Registryのリモートリポジトリを利用することが、ほぼ必須の対策だと考えています。

#Artifact Registryのリモートリポジトリとは

リモート リポジトリは、アップストリーム ソースのプロキシとして機能するため、依存関係をきめ細かく制御できます。パッケージのバージョンを初めてリクエストするときに、Artifact Registry はパッケージをダウンロードして、リモート リポジトリにキャッシュ保存します。次に同じパッケージ バージョンをリクエストすると、Artifact Registry はキャッシュに保存されたコピーを提供します。

リモート リポジトリの概要  |  Artifact Registry documentation  |  Google Cloud
リモート リポジトリの概要  |  Artifact Registry documentation  |  Google Cloud favicon cloud.google.com
リモート リポジトリの概要  |  Artifact Registry documentation  |  Google Cloud

リポジトリにイメージが存在しない状態でpullするとDocker Hubからイメージをダウンロードしてキャッシュするという挙動になります。その後は、キャッシュがPullされるので、Docker Hubへのアクセスは減ります。
この挙動はECRのpull through cacheと同じですね。シンプルな仕組みですが、強力です。

#Terraformでの設定例

下記のドキュメントを参考にしました。

リモート リポジトリを作成する  |  Artifact Registry documentation  |  Google Cloud
リモート リポジトリを作成する  |  Artifact Registry documentation  |  Google Cloud favicon cloud.google.com
リモート リポジトリを作成する  |  Artifact Registry documentation  |  Google Cloud

#GCPプロジェクトの設定

もともとあるGCPプロジェクトのAPIを有効にしました。

  • Secret Manager API
  • Access Context Manager API
terraform {
  required_version = ">= 1.1.6"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "7.3.0"
    }
    random = {
      version = "~> 3.0"
    }
  }
}

variable "name" {
  description = "The NAME of the Google Cloud project"
}

variable "billing_account" {
  description = "Billing account STRING."
}

variable "folder_id" {
  description = "Folder NR."
}

variable "region" {
  default     = "asia-northeast1"
  description = "Region of resources"
}

variable "env" {
  description = "The Environment of the Google Cloud project"
}


resource "random_id" "id" {
  byte_length = 4
  prefix      = "${var.name}-${var.env}-"
}

resource "google_project" "project" {
  name                = "${var.name}-${var.env}"
  project_id          = random_id.id.hex
  billing_account     = var.billing_account
  folder_id           = var.folder_id
  auto_create_network = false
}

module "project-services" {
  source  = "terraform-google-modules/project-factory/google//modules/project_services"
  version = "18.1.0"

  project_id = google_project.project.project_id

  activate_apis = [
    "artifactregistry.googleapis.com",
    "iamcredentials.googleapis.com",
+   "secretmanager.googleapis.com",
+   "accesscontextmanager.googleapis.com",
  ]
  enable_apis = true
}


# project creation output
output "project" {
  value = google_project.project.project_id
}

#Docker HubでPATを発行する

Docker HubにログインしてメニューからSettings, Personal access tokensの順にクリック。
権限をREAD OnlyにしてPATを作成します。
後続の手順で利用します。

#Artifact Registryのリモートリポジトリの設定

先の手順で取得したPATを環境変数に設定します。

export TF_VAR_docker_hub_pat="dckr_pat_xxx"

リモートリポジトリと接続するためのシークレットを設定しました。

locals {
  docker_hub_username = "<docker hub username>"
}
data "google_project" "project" {}
variable "region" {
  default     = "asia-northeast1"
  description = "Region of resources"
}
variable "docker_hub_pat" {
  description = "Docker Hub Personal Access Token"
  type        = string
  sensitive   = true
}

resource "google_artifact_registry_repository" "docker_remote_repo" {
  location      = var.region
  repository_id = "docker-hub-proxy" # 任意のリポジトリIDを指定
  description   = "Docker Hub remote repository"
  format        = "DOCKER"

  # モードをREMOTE_REPOSITORYに設定
  mode = "REMOTE_REPOSITORY"

  # リモートリポジトリの設定
  remote_repository_config {
    description = "Docker Hub mirror"
    docker_repository {
      # 公開リポジトリとしてDocker Hubを指定
      public_repository = "DOCKER_HUB"
    }
    upstream_credentials {
      username_password_credentials {
        username                = local.docker_hub_username
        password_secret_version = google_secret_manager_secret_version.docker_hub_remote_secret_version.id
      }
    }
  }
}

resource "google_secret_manager_secret" "docker_hub_remote_secret" {
  secret_id = "docker-hub-remote-secret"
  replication {
    auto {}
  }
}

resource "google_secret_manager_secret_version" "docker_hub_remote_secret_version" {
  secret      = google_secret_manager_secret.docker_hub_remote_secret.id
  secret_data = var.docker_hub_pat
}

resource "google_secret_manager_secret_iam_member" "docker_hub_secret_access" {
  secret_id = google_secret_manager_secret.docker_hub_remote_secret.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-artifactregistry.iam.gserviceaccount.com"
}

#動作確認

ためしにNginxをデプロイしてみましょう。動作確認のみなのでPodを直接起動する。project-nameはプロジェクト名のプレースホルダです。

kubectl run nginx-pod --image=asia-northeast1-docker.pkg.dev/<project-name>/docker-hub-proxy/nginx

動きました。

kubectl get po
NAME        READY   STATUS    RESTARTS   AGE
nginx-pod   1/1     Running   0          6m37s

#まとめ

今回は、Artifact Registryのリモートリポジトリを利用したDocker HubのRate Limit対策について解説しました。
あまり複雑ではなくすぐに利用できると思うので、GKEを利用する際には必ず設定することをおすすめします。