- 技術 💻
ImagePullBackOffの直し方|ErrImagePullとの違いと原因表
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期連続の黒字決算。