ErrImagePull は「イメージの取得(pull)に今失敗した」、ImagePullBackOff は「失敗したので、次に取りに行くまで待っている」状態です。 原因は同じで、kubectl describe pod の Events にある Failed to pull image の行に書かれています。

kubectl describe pod <Pod名> -n <名前空間>     # Events の "Failed to pull image ..." を読む
kubectl get events -n <名前空間> --field-selector involvedObject.name=<Pod名>

原因を変えた Pod を1つずつ作り、イベントの文面を並べました。Failed to pull image の後ろの、最後の「:」より後ろが原因です。

原因 イベントの文面(最後の部分) STATUS
タグが無い localhost:5000/myapp:1.1: not found ImagePullBackOff
リポジトリ名の誤り localhost:5000/myap:1.0: not found ImagePullBackOff
認証が要るのに Secret が無い pull access denied, repository does not exist or may require authorization: authorization failed: no basic auth credentials ImagePullBackOff
パスワードが違う unexpected status from HEAD request to http://localhost:5001/v2/team/api/manifests/2.3.1: 401 Unauthorized ImagePullBackOff
imagePullSecrets の名前の誤り Unable to retrieve some image pull secrets (regcrd); attempting to pull the image may not succeed. ImagePullBackOff
ノードの CPU 用のイメージが無い no match for platform in manifest: not found ImagePullBackOff
レジストリの名前が引けない dial tcp: lookup registry-1.docker.io: no such host ImagePullBackOff
レジストリが動いていない dial tcp 127.0.0.1:5009: connect: connection refused ImagePullBackOff
イメージ名に大文字 invalid reference format: repository name (MyApp) must be lowercase InvalidImageName
imagePullPolicy: Never でノードに無い Container image "..." is not present with pull policy of Never ErrImageNeverPull

確認環境:k3s v1.36.5+k3s1(Kubernetes 1.36.5・containerd 2.3.4)を Ubuntu 24.04 の上に1ノードで立て、ローカルに置いたレジストリ(CNCF Distribution 3.1.2。認証なしと、htpasswd の Basic 認証ありの2つ)に、crane 0.22.1 でイメージを置いて確かめました。イベントの文面を出す箇所は Kubernetes v1.36.5 のソース(kubelet の image_manager.go など)で確かめています。Docker Hub のレート制限と Amazon ECR は、各社の公式ドキュメントで確かめています(確認日 2026年10月13日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ImagePullBackOffの直し方|ErrImagePullとの違いと原因表」

ErrImagePull と ImagePullBackOff の違い

取得に失敗した瞬間が ErrImagePull、次の取得を待っている間が ImagePullBackOff です。 STATUS は2つを行き来します。待ち時間は 10秒から倍になり、上限は 5分です(kubelet のソースの imageBackOffPeriod = 10s、MaxImageBackOff = 300s)。

flowchart LR
    A["Pulling image"] -->|失敗| B["ErrImagePull<br/>(Failed to pull image ...)"]
    B --> C["ImagePullBackOff<br/>(Back-off pulling image ...)"]
    C -->|"待ち時間(10秒→20秒→…最大5分)"| A
    A -->|成功| D["Pulled → Created → Started"]

タグが無いイメージを指定した Pod の Events です。1回の失敗で Failed が3行出ます。

Events:
  Type     Reason     Age                    From      Message
  ----     ------     ----                   ----      -------
  Normal   Pulling    69s (x4 over 2m45s)    kubelet   spec.containers{app}: Pulling image "localhost:5000/myapp:1.1"
  Warning  Failed     69s (x4 over 2m44s)    kubelet   spec.containers{app}: Failed to pull image "localhost:5000/myapp:1.1": rpc error: code = NotFound desc = failed to pull and unpack image "localhost:5000/myapp:1.1": failed to resolve reference "localhost:5000/myapp:1.1": localhost:5000/myapp:1.1: not found
  Warning  Failed     69s (x4 over 2m44s)    kubelet   spec.containers{app}: Error: ErrImagePull
  Normal   BackOff    3s (x9 over 2m16s)     kubelet   spec.containers{app}: Back-off pulling image "localhost:5000/myapp:1.1"
  Warning  Failed     3s (x9 over 2m16s)     kubelet   spec.containers{app}: Error: ImagePullBackOff
イベント 出す場所(kubelet のソース) 読み方
Pulling image "..." image_manager.go 取得を始めた
Failed to pull image "...": <原因> image_manager.go 原因はここ。containerd などのランタイムのエラー文がそのまま入る
Error: ErrImagePull kuberuntime 状態の名前だけ。原因は書かれない
Back-off pulling image "..." image_manager.go 待ち時間に入った
Error: ImagePullBackOff kuberuntime 状態の名前だけ

イベントが流れて見えないときは、Pod の status にも直前の原因が残っています。

kubectl get pod wrong-tag -n pull -o jsonpath='{.status.containerStatuses[0].state}'
{"waiting":{"message":"Back-off pulling image \"localhost:5000/myapp:1.1\": ErrImagePull: rpc error: code = NotFound desc = failed to pull and unpack image \"localhost:5000/myapp:1.1\": failed to resolve reference \"localhost:5000/myapp:1.1\": localhost:5000/myapp:1.1: not found","reason":"ImagePullBackOff"}}

待ち時間は Pod とイメージの組み合わせごとに数えています(ソースの backOffKey が「Pod の UID + イメージ名」)。直したあとは Pod を作り直すと、待たずに取りに行きます。 Deployment なら、イメージ名を直して apply すれば新しい Pod ができます。

原因別の直し方

原因 文面の手がかり 直し方
タグ・名前の誤り not found、manifest unknown レジストリにあるタグを一覧で確かめる
認証が無い no basic auth credentials、pull access denied、401 Unauthorized(Secret なし) imagePullSecrets を付ける
認証情報が違う 401 Unauthorized、403 Forbidden、denied Secret を作り直す。トークンの期限を確かめる
Secret が見つからない Unable to retrieve some image pull secrets Secret の名前と名前空間を合わせる
アーキテクチャ no match for platform in manifest ノードの CPU 用のイメージを作る(マルチアーキテクチャ)
ネットワーク no such host、connection refused、i/o timeout DNS・プロキシ・ファイアウォール・レジストリの稼働
レート制限 429 Too Many Requests、toomanyrequests 認証して取る・ミラーを置く
イメージ名の書式 InvalidImageName、invalid reference format 小文字にする。: と @ の位置を直す
pull しない設定 ErrImageNeverPull imagePullPolicy を IfNotPresent にするか、ノードに先に入れる

タグ・名前の誤り(not found)

not found は「レジストリにはつながったが、その名前・タグが無い」です。 タグとリポジトリ名のどちらが違っても、文面は同じ not found でした。

Failed to pull image "localhost:5000/myap:1.0": rpc error: code = NotFound desc = failed to pull and unpack image "localhost:5000/myap:1.0": failed to resolve reference "localhost:5000/myap:1.0": localhost:5000/myap:1.0: not found

レジストリにあるタグは、手元の PC から一覧で確かめます。

crane ls registry.example.com/team/api                     # タグの一覧(go-containerregistry の crane)
docker manifest inspect registry.example.com/team/api:2.3.1   # そのタグがあるか
skopeo list-tags docker://registry.example.com/team/api
aws ecr describe-images --repository-name team/api --query 'imageDetails[].imageTags'   # ECR
見落としやすい誤り 例
Docker Hub の公式イメージ以外で、ユーザー名を書いていない myapp:1.0 は docker.io/library/myapp:1.0 と解釈される
CI がタグを付ける前にデプロイした git のコミットハッシュのタグがまだ push されていない
latest が無い タグを省くと latest になる。latest を push していないことがある
レジストリのホスト名の誤り 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com のリージョン違い

プライベートレジストリ(認証)

認証が要るレジストリに Secret なしで取りに行くと、no basic auth credentials になります。 手元の Basic 認証付きレジストリで、Secret の付け方を変えた結果です。

Pod の設定 結果 イベントの文面(最後の部分)
imagePullSecrets なし ImagePullBackOff pull access denied, repository does not exist or may require authorization: authorization failed: no basic auth credentials
パスワードが違う Secret ImagePullBackOff unexpected status from HEAD request to http://localhost:5001/v2/team/api/manifests/2.3.1: 401 Unauthorized
Secret の名前の誤り(regcrd) ImagePullBackOff FailedToRetrieveImagePullSecret:Unable to retrieve some image pull secrets (regcrd); attempting to pull the image may not succeed. のあと no basic auth credentials
正しい Secret Running Successfully pulled image "localhost:5001/team/api:2.3.1" in 270ms (270ms including waiting). Image size: 2146319 bytes.

Docker Hub のプライベートリポジトリでは、認証が無いと「リポジトリが無い」とも読める pull access denied, repository does not exist or may require authorization になります。 名前の誤りと認証の不足を、この文面だけでは見分けられません。

imagePullSecrets の作り方

kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=deploy \
  --docker-password='パスワードやアクセストークン' \
  -n myapp

作られる Secret の中身です(type: kubernetes.io/dockerconfigjson)。手元で作ったものをデコードすると、次の JSON でした。

kubectl get secret regcred -n myapp -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
{"auths":{"localhost:5001":{"username":"deploy","password":"s3cret-pass","auth":"ZGVwbG95OnMzY3JldC1wYXNz"}}}

--docker-server は、イメージ名のホスト部分と同じ書き方にします。 Docker Hub なら https://index.docker.io/v1/、ECR なら 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com です。docker login 済みの ~/.docker/config.json から作ることもできます。

kubectl create secret generic regcred \
  --from-file=.dockerconfigjson=$HOME/.docker/config.json \
  --type=kubernetes.io/dockerconfigjson -n myapp

docker login が資格情報ストア(credsStore)を使っていると、config.json に auth が入っていないので、この方法では認証できません。

Pod・Deployment に付ける

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: myapp
spec:
  replicas: 2
  selector:
    matchLabels: {app: api}
  template:
    metadata:
      labels: {app: api}
    spec:
      imagePullSecrets:
      - name: regcred              # 同じ名前空間の Secret
      containers:
      - name: api
        image: registry.example.com/team/api:2.3.1

Secret は Pod と同じ名前空間に必要です。 名前空間ごとに毎回書くのを避けるなら、ServiceAccount に付けます。手元で default の ServiceAccount に付けると、imagePullSecrets を書いていない Pod にも [{"name":"regcred"}] が自動で入り、取得できました。

kubectl patch serviceaccount default -n myapp -p '{"imagePullSecrets": [{"name": "regcred"}]}'

ノードにある資格情報に注意

kubelet は、ノードの config.json も読みます。 手元で、ノードの root の ~/.docker/config.json にレジストリのログイン情報があると、imagePullSecrets の無い Pod でも取得できてしまいました。kubelet のソース(pkg/credentialprovider/config.go)では、--root-dir(既定は /var/lib/kubelet)、kubelet の作業ディレクトリ、$HOME/.docker、/.docker の config.json を探します。「あるノードでは動くのに、別のノードでは ImagePullBackOff」のときは、ノードごとの資格情報の違いを疑います。

Kubernetes 1.35 から:ノードにあるイメージでも資格情報を確かめる

KubeletEnsureSecretPulledImages が 1.35 でベータになり、既定で有効です。 「別の Pod が Secret を使って取得し、ノードに残っているイメージ」を、Secret を持たない Pod は使えなくなりました。手元で確かめた結果です。

順番 Pod imagePullPolicy 結果
1 Secret ありで取得 IfNotPresent Running(レジストリから取得)
2 Secret なし(同じイメージ) IfNotPresent ErrImagePull。no basic auth credentials

以前は、ノードにイメージがあれば IfNotPresent で使えました。公式ドキュメントでは、kubelet の設定の imagePullCredentialsVerificationPolicy で確かめ方を選べると説明されています。

値 ノードにあるイメージの扱い
NeverVerify 確かめない(以前と同じ)
NeverVerifyPreloadedImages(既定) kubelet の外で入れたイメージは確かめない。kubelet が取得したものは確かめる
NeverVerifyAllowListedImages kubelet の外で入れ、許可リストにあるものだけ確かめない
AlwaysVerify すべて確かめる

1.35 以上へ上げたあとに、「同じノードで前は動いていた Pod が ErrImagePull になる」場合は、その Pod に imagePullSecrets が付いているかを確かめます。

Amazon ECR の認証

使い方 認証のしかた 起きやすいエラー
EKS のノードから同じアカウントの ECR ノードの IAM ロールに AmazonEC2ContainerRegistryPullOnly などの権限 権限が無いと 403 Forbidden・not authorized
別アカウントの ECR ECR のリポジトリポリシーで、取得する側のアカウント・ロールを許可 403 Forbidden
EKS 以外のクラスターから ECR aws ecr get-login-password のトークンで Secret を作る 12時間で期限切れになり no basic auth credentials・403
kubectl create secret docker-registry ecr-cred \
  --docker-server=123456789012.dkr.ecr.ap-northeast-1.amazonaws.com \
  --docker-username=AWS \
  --docker-password="$(aws ecr get-login-password --region ap-northeast-1)" \
  -n myapp

AWS のドキュメントでは、GetAuthorizationToken で得たトークンの有効期限は既定で12時間で、トークンは取得したリージョンでしか使えないと説明されています。EKS 以外で長く使うなら、トークンを定期的に作り直す仕組みか、kubelet の資格情報プロバイダー(ecr-credential-provider)を使います。ECR のリポジトリの作り方は、関連記事「Amazon ECR の使い方 リポジトリ作成とライフサイクルポリシー」で扱っています。

アーキテクチャの違い(no match for platform)

ノードの CPU(amd64・arm64)用のイメージがレジストリに無いと、no match for platform in manifest になります。 手元で、arm64 用だけを入れたイメージ一覧(マニフェストリスト)を amd64 のノードで取得した結果です。

Failed to pull image "localhost:5000/armonly:1.0": rpc error: code = NotFound desc = failed to pull and unpack image "localhost:5000/armonly:1.0": no match for platform in manifest: not found
crane manifest localhost:5000/armonly:1.0     # どの CPU 用が入っているか
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","size":546,"digest":"sha256:b4796200...","platform":{"architecture":"arm64","os":"linux"}}]}
状況 起きること
マニフェストリストにノードの CPU が無い 取得で no match for platform in manifest(ImagePullBackOff)
マニフェストリストではなく、1つの CPU 用のイメージだけ 取得はでき、起動で exec format error(CrashLoopBackOff)

Apple シリコンの Mac でビルドしたイメージを amd64 のノードで動かすと起きやすいです。両方の CPU 用に作るには docker buildx build --platform linux/amd64,linux/arm64 --push を使います。ノードの CPU は kubectl get nodes -L kubernetes.io/arch で見られます。

レート制限(Docker Hub)

Docker Hub は、認証なしの取得を IPv4 アドレス(IPv6 は /64)ごとに 6時間で100回、無料の個人アカウントでの認証ありを 6時間で200回に制限しています。 Pro・Team・Business は制限なしです(Docker の公式ドキュメント)。超えると、マニフェストの取得に 429 が返り、本文は次のとおりです。

You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits

NAT ゲートウェイの後ろにあるノードは、全部が同じ IP で数えられます。

対策 内容
認証して取る Docker Hub のアカウントで imagePullSecrets を付ける
自分のレジストリに写す ECR・Artifact Registry・Harbor にコピーし、そこから取る
プルスルーキャッシュ ECR のプルスルーキャッシュなど、取得のたびに上流へ行かない仕組み
imagePullPolicy: IfNotPresent タグ固定のイメージを毎回取りに行かない

残りの回数は、公式ドキュメントにある手順で、レスポンスヘッダーの ratelimit-limit・ratelimit-remaining から確かめられます。

ネットワーク(名前が引けない・つながらない)

文面 意味 確かめ方
dial tcp: lookup registry-1.docker.io: no such host ノードで名前が引けない ノードの DNS 設定
dial tcp 127.0.0.1:5009: connect: connection refused そのポートで待ち受けていない レジストリの稼働・ポート
i/o timeout 届いていない ファイアウォール・プロキシ・閉じたネットワークの出口
x509: certificate signed by unknown authority 証明書を信頼できない ノードのランタイムに CA を入れる

イメージを取りに行くのは Pod ではなく、ノードの containerd などのランタイムです。 Pod の中から curl で確かめても、ノードの結果とは違うことがあります。プロキシが要る環境では、ランタイムの設定(containerd の環境変数など)にプロキシを書きます。

イメージ名の書式(InvalidImageName)

Warning  InspectFailed  Failed to apply default image tag "localhost:5000/MyApp:1.0": couldn't parse image name "localhost:5000/MyApp:1.0": invalid reference format: repository name (MyApp) must be lowercase
Warning  Failed         Error: InvalidImageName

リポジトリ名は小文字だけです。ほかに、スペースや末尾の :、タグとダイジェストの順番の誤り(正しくは name:tag@sha256:...)でも起きます。

imagePullPolicy の早見表

imagePullPolicy ノードにある ノードに無い
Always 毎回レジストリにダイジェストを問い合わせる 取得する
IfNotPresent そのまま使う(1.35 以降は資格情報を確かめることがある) 取得する
Never そのまま使う ErrImageNeverPull
省略・タグが latest か無し Always になる ―
省略・ほかのタグ IfNotPresent になる ―

よくある質問

Q. 同じイメージで、あるノードの Pod だけ ImagePullBackOff になります。 A. ノードごとの違いを見ます。ノードの CPU(kubectl get nodes -L kubernetes.io/arch)、ノードの config.json、ノードの DNS・ファイアウォール、そのノードにだけイメージが残っていたか、の順に確かめます。

Q. ImagePullBackOff が直ったのに、なかなか起動しません。 A. 待ち時間(最大5分)の途中です。Pod を作り直すと、すぐ取りに行きます。

Q. kubectl create secret docker-registry の --docker-email は要りますか? A. 省略できます。Secret には username・password・auth が入ります。

Q. Secret のパスワードを変えたら、動いている Pod は止まりますか? A. 動いているコンテナは止まりません。Secret はイメージを取得するときにだけ使われます。次に Pod を作り直したときに、新しい値で取得します。

まとめ

  • ErrImagePull は失敗した瞬間、ImagePullBackOff は次の取得を待っている状態。原因は Failed to pull image の行の最後の部分
  • not found は名前・タグ、no basic auth credentials・401 は認証、no match for platform は CPU の違い
  • imagePullSecrets は Pod と同じ名前空間に作る。ServiceAccount に付けると書き忘れを防げる
  • 1.35 以降は、ノードに残っているイメージでも、Secret を持たない Pod は使えないことがある
  • ECR のトークンは12時間で切れる。Docker Hub は認証なしで6時間に100回まで
  • 直したら Pod を作り直すと待ち時間を飛ばせる

起動したあとに再起動を繰り返す場合は、関連記事「CrashLoopBackOffの直し方|原因別の切り分け表」で扱っています。イメージを小さく安全に作る方法は「Dockerfileの書き方|軽く・速く・安全なイメージを作るベストプラクティス」、イメージの脆弱性の調べ方は「Trivyの使い方|脆弱性スキャン・SBOM出力とGitHub Actions設定」で扱っています。

参考・出典

確認日はいずれも 2026年10月13日です。

  • Kubernetes「Images」:https://kubernetes.io/docs/concepts/containers/images/
  • Kubernetes「Pull an Image from a Private Registry」:https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
  • Kubernetes「Configure Service Accounts for Pods(Add ImagePullSecrets to a service account)」:https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
  • Kubernetes「Kubelet Configuration (v1beta1)」:https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/
  • Kubernetes のソース v1.36.5(pkg/kubelet/images・pkg/credentialprovider・pkg/features):https://github.com/kubernetes/kubernetes/tree/v1.36.5
  • Docker Docs「Docker Hub pull usage and limits」:https://docs.docker.com/docker-hub/usage/pulls/
  • Amazon ECR ユーザーガイド「Troubleshooting errors with Docker commands when using Amazon ECR」:https://docs.aws.amazon.com/AmazonECR/latest/userguide/common-errors-docker.html
  • Amazon ECR ユーザーガイド「Private registry authentication」:https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html
  • Amazon EKS ユーザーガイド「Amazon EKS node IAM role」:https://docs.aws.amazon.com/eks/latest/userguide/create-node-role.html
  • Google Cloud「イメージの pull に関するトラブルシューティング」:https://cloud.google.com/kubernetes-engine/docs/troubleshooting/image-pulls?hl=ja
  • CNCF Distribution(registry):https://distribution.github.io/distribution/
  • go-containerregistry(crane):https://github.com/google/go-containerregistry

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ImagePullBackOffの直し方|ErrImagePullとの違いと原因表」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?