1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クラスター作りすぎでDockerのレートリミットに悩まされてる人、必見! mirror.gcr.ioで「ImagePullBackOff」にオサラバしよう! [Cluster APIにも対応]

Last updated at Posted at 2025-06-18

はじめに

Kubernetesクラスタを運用する際、特にCI/CDパイプラインやプロトタイピング中に、Docker Hubのレートリミットに遭遇することがあります。この制限は、イメージのプル失敗(ImagePullBackOff)などを引き起こし、非常にうっとうしいです。

これを回避するために、mirror.gcr.io をDocker Hubイメージのプルスルーキャッシュとして利用できます。

本稿では、特にCluster API を用いた管理クラスタワークロードクラスタの構成で、全てのクラスターでmirror.gcr.ioをレジストリミラーとして設定し、Docker Hubのレートリミットを回避する方法を解説していきます。

なぜmirror.gcr.ioを使うのか?

mirror.gcr.ioはDocker Hubイメージをキャッシュしてくれているので、クラスタからは直接Docker HubではなくGoogleのミラーからイメージを取得するようにすると、Docker Hubのレートリミットに悩まされなくなります!

前提条件

  • Docker のインストール
  • kind(Kubernetes IN Docker)のインストール
  • kubectl のインストール
  • clusterctl のインストール
  • yq のインストール(YAML処理用)

ステップ1: レジストリミラー設定ファイルの準備

kindで直接起動したクラスター(管理クラスター)のcontainerdがDocker Hubのミラーとしてmirror.gcr.ioを利用できるよう、ディレクトリ構造と設定ファイルを作成します。

mkdir -p certs.d/docker.io
cat > certs.d/docker.io/hosts.toml <<EOF
server = "https://registry-1.docker.io"

[host."https://mirror.gcr.io"]
  capabilities = ["pull"]

[host."https://registry-1.docker.io"]
  capabilities = ["pull", "resolve"]
EOF

このファイルは、containerdにDocker Hubイメージの取得時に、

  1. registry-1.docker.ioからマニフェストを取得 (resolve)
  2. mirror.gcr.ioからpull

というステップを踏むような設定になっています。

このファイルはkindを実行するホストマシン(macOS)に作成しておきます。

resolveもひとつのAPIコールになるため、Docker Hubのレートリミットの消費につながります。「一切Docker Hubとやりとりしたくない」という場合は次のようにmirror.gcr.ioにresolveも任せることもできます。

server = "https://registry-1.docker.io"

[host."https://mirror.gcr.io"]
  capabilities = ["pull", "resolve"]

注意点として、latestタグなど頻繁に更新されるイメージが、mirror.gcr.ioでは古いままといったことが起りうるので注意してください。

ステップ2: kindクラスタのミラー設定

以下の内容で kind-cluster.yaml ファイルを作成します。これにより、kind内部のcontainerdがミラーを利用し、デバッグログも有効化されます。

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  ipFamily: dual
nodes:
  - role: control-plane
    image: kindest/node:v1.33.1
    extraMounts:
      # Cluster API Docker Provider(CAPD)がホストのDockerを操作できるようにDockerソケットをマウント
      - hostPath: /var/run/docker.sock
        containerPath: /var/run/docker.sock
      # ミラー設定をcontainerdの設定ディレクトリにマウント
      - hostPath: ./certs.d
        containerPath: /etc/containerd/certs.d
# containerdにdocker.ioとregistry.k8s.ioのイメージ取得時にmirror.gcr.ioを優先させる
containerdConfigPatches:
  - |-
    [plugins."io.containerd.grpc.v1.cri".registry]
      config_path = "/etc/containerd/certs.d"
    # mirror.gcr.ioの利用状況を確認するためデバッグモードを有効化
    # ログ確認例: `docker exec -it <cluster名>-control-plane bash -c 'journalctl -u containerd -f & crictl pull nginx'`
    [debug]
      level = "debug"

これもホストマシンに作成しておきます。

各項目の詳細解説:

  • extraMounts:
    • CAPDがDockerを操作するためのソケットマウント。
    • ミラー設定(certs.d)をノード内のcontainerd設定ディレクトリにマウント。
  • containerdConfigPatches:
    • containerdにカスタムレジストリ設定パスを指定。
    • デバッグログを有効化し、イメージプルやミラー利用がはっきりと解るようにする。

ステップ3: 管理クラスタの作成

kind create cluster --name management --config kind-cluster.yaml

このコマンドで、カスタムレジストリ設定とデバッグログが有効な管理クラスタが作成されます。ミラーが利用されているかは、以下のコマンドで確認できます:

docker exec -it management-control-plane bash -c 'crictl pull hello-world && journalctl -u containerd' | grep fetch | grep mirror.gcr.io

mirror.gcr.ioからイメージが取得されているログが表示されれば成功です。

ステップ4: 管理クラスタへのCluster APIインストール

export CLUSTER_TOPOLOGY=true
clusterctl init --infrastructure docker

これで管理クラスタにCluster APIコンポーネントがインストールされます。

ステップ5: ワークロードクラスタテンプレートへのミラーパッチ適用

Cluster APIでワークロードクラスタを作成する際、ノードにもミラー設定が反映されるよう、クラスタテンプレートに事前コマンドを注入します。

以下の内容で patch.yaml を作成します:

- name: containerd-customization
  description: "containerdのミラー・デバッグ・再起動設定"
  definitions:
    - selector:
        apiVersion: controlplane.cluster.x-k8s.io/v1beta1
        kind: KubeadmControlPlaneTemplate
        matchResources:
          controlPlane: true
      jsonPatches:
        - op: add
          path: /spec/template/spec/kubeadmConfigSpec/preKubeadmCommands
          value:
            - |
              set -e

              # 1. ミラー用hosts.toml作成
              mkdir -p /etc/containerd/certs.d/docker.io
              cat <<EOF > /etc/containerd/certs.d/docker.io/hosts.toml
              server = "https://registry-1.docker.io"

              [host."https://mirror.gcr.io"]
                capabilities = ["pull"]

              [host."https://registry-1.docker.io"]
                capabilities = ["pull", "resolve"]
              EOF

              # 2. デバッグ設定を冪等に追加
              grep -qF '[debug]' /etc/containerd/config.toml || cat <<'TOML' >> /etc/containerd/config.toml
              [debug]
                level = "debug"
              TOML

              # 3. registry config_pathを冪等に追加
              grep -qF '[plugins."io.containerd.grpc.v1.cri".registry]' /etc/containerd/config.toml || cat <<'TOML' >> /etc/containerd/config.toml

              [plugins."io.containerd.grpc.v1.cri".registry]
                config_path = "/etc/containerd/certs.d"
              TOML

              # 4. containerdを再起動して反映
              systemctl restart containerd
    - selector:
        apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
        kind: KubeadmConfigTemplate
        matchResources:
          machineDeploymentClass:
            names: ["default-worker"]
      jsonPatches:
        - op: add
          path: /spec/template/spec/preKubeadmCommands
          value:
            - |
              set -e

              # 1. ミラー用hosts.toml作成
              mkdir -p /etc/containerd/certs.d/docker.io
              cat <<EOF > /etc/containerd/certs.d/docker.io/hosts.toml
              server = "https://registry-1.docker.io"

              [host."https://mirror.gcr.io"]
                capabilities = ["pull"]

              [host."https://registry-1.docker.io"]
                capabilities = ["pull", "resolve"]
              EOF

              # 2. デバッグ設定を冪等に追加
              grep -qF '[debug]' /etc/containerd/config.toml || cat <<'TOML' >> /etc/containerd/config.toml
              [debug]
                level = "debug"
              TOML

              # 3. registry config_pathを冪等に追加
              grep -qF '[plugins."io.containerd.grpc.v1.cri".registry]' /etc/containerd/config.toml || cat <<'TOML' >> /etc/containerd/config.toml

              [plugins."io.containerd.grpc.v1.cri".registry]
                config_path = "/etc/containerd/certs.d"
              TOML

              # 4. containerdを再起動して反映
              systemctl restart containerd

各項目の詳細解説:

  • namedescription: パッチの目的を示すメタデータ。
  • definitions: ノード種別ごとのパッチ定義リスト。
  • selectorは特定のCluster APIテンプレート種別(コントロールプレーンまたはワーカーノード)をターゲット。
  • jsonPatches: ノードの起動プロセスにコマンドを注入するJSONパッチ操作。
  • preKubeadmCommands内のシェルスクリプトは:
    1. ミラー設定作成: containerd用のhosts.tomlを作成。
    2. デバッグログ有効化: containerd設定にdebugセクションを追加。
    3. registry config_path設定: containerdにミラー設定パスを認識させる。
    4. containerd再起動: 設定反映のためサービス再起動。
  • このパッチはコントロールプレーン・ワーカーノード両方に適用され、全ノードでミラーが利用されます。

なんだか込み入ってますが、kindで行った設定をCluster API版として焼き直したものです。

ステップ6: ワークロードクラスタマニフェストの生成と適用

このステップでは、ワークロードクラスタのマニフェストを生成し、containerdカスタマイズパッチを適用してから管理クラスタに適用します。

clusterctl generate cluster workload \
  --flavor development \
  --kubernetes-version v1.33.1 \
  --control-plane-machine-count=1 \
  --worker-machine-count=1 \
  | yq \
  | tee workload.original.yaml \
  | yq 'select(.kind == "ClusterClass").spec.patches += load("patch.yaml")' \
  | tee workload.patched.yaml \
  | kubectl apply -f -

各コマンドの意味と流れは以下の通りです:

  • クラスタマニフェスト生成: clusterctl generate cluster workload ... で新しいワークロードクラスタのYAMLマニフェストを生成します(トポロジー、マシンテンプレート、設定など)。
  • yqでYAML整形: 最初のyqでYAMLをパースし、後続処理しやすくします。
  • オリジナル保存: tee workload.original.yamlで未パッチのマニフェストを保存。
  • ClusterClassへパッチ適用: 2つ目のyqClusterClassspec.patchespatch.yamlの内容を追加。これによりクラスタ作成時にpreKubeadmCommands(ミラー設定)がノード起動時に注入されます。
  • パッチ済みマニフェスト保存: tee workload.patched.yamlでパッチ済みマニフェストを保存。
  • クラスタへ適用: kubectl apply -f -でパッチ済みマニフェストを管理クラスタに適用し、ワークロードクラスタが作成されます。

workload.original.yamlとworkload.patched.yamlは、パッチ適用の前後をご確認いただきやすくするために保存しています。

ステップ7: ワークロードクラスタでミラー利用を確認

ワークロードクラスタのノードがミラーを利用しているか確認するには、以下を実行します:

for container in $(kubectl --context=kind-management get machines -o custom-columns=NAME:.metadata.name --no-headers); do
  echo
  echo === $container ===
  docker exec -it $container bash -c 'crictl pull hello-world && journalctl -u containerd' | grep fetch | grep mirror.gcr.io
done

各ノードでmirror.gcr.ioからイメージが取得されているログが表示されれば成功です。

ステップ8: (オプション) CNIプラグインのインストール

例:Calicoをインストールする場合

kubectl --context=kind-workload apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml

まとめ

以上のようにすると、管理クラスタ・ワークロードクラスタの両方でmirror.gcr.ioをDocker Hubイメージのプルスルーキャッシュとして利用できます。これによりDocker Hubのレートリミットを回避し、Kubernetesワークロードのイメージプルが安定します。是非試してみてください! 最後までお読みいただき、ありがとうございました!

参考リンク

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?