docker『Image Not Found』の原因と対処法

docker『Image Not Found』の原因と対処法

指定したコンテナイメージが見つからず、pull/run/build/compose 時に失敗する状態。典型原因は「リポジトリ名/タグの誤り」「レジストリの可視性・認可不足」「デフォルトレジストリの誤解(docker.io/library)」「マニフェスト未公開(タグは表示されても実体が無い)」「ネットワーク/DNS/プロキシ」「ビルドの FROM 参照ミス」など。まずイベントとエラーメッセージの文面を読み、名前の正規化→認証→存在確認→ネットワークの順で切り分ける。

症状と発生条件(まず把握)

・docker run / pull / compose up / build(FROM)で「not found」「manifest unknown」「repository does not exist」などが表示される。

・docker images に目当てのイメージが存在しない、またはローカルにはあるがタグが違う。

・プライベートレジストリ/組織レジストリで公開設定やトークン権限が足りない。

・docker.io(Docker Hub)で名前の省略が原因(library/NAME 扱い)になっている。

・arm64/amd64 のプラットフォーム差で「タグはあるが対象アーキのマニフェストが無い(実質 not found)」。

クイック診断(存在・タグ・接続を最短で確かめる)

# ローカルにあるか
docker images | grep -E '(^|/)<repo>/<name>|(^| )<name>'

# そのタグが存在するか(ローカル)
docker images <image> --format 'ID={{.ID}}  TAG={{.Tag}}  SIZE={{.Size}}'

# リモートから直接 pull(メッセージのHTTPコードを見る)
docker pull <registry>/<org>/<name>:<tag>

# 省略時の解決先(docker.io/library/...)を確認
docker pull <name>:<tag>

# そのタグの multi-arch マニフェスト確認(要 buildx)
docker buildx imagetools inspect <image>:<tag>

# ネットワーク/DNS疎通
getent hosts <registry> || nslookup <registry>

イメージ名・タグを正規化(最頻出の取り違え)

# NG: 名前の省略・latest 依存
docker run myapp:latest

# OK: レジストリ/組織/名前/タグを明示
docker run ghcr.io/myorg/myapp:v1.2.3

# Docker Hub の公式は library ネームスペース
# 「nginx:1.25」は実体として「docker.io/library/nginx:1.25」
docker pull docker.io/library/nginx:1.25

・CI/CDでは latest ではなくバージョンタグやダイジェスト(@sha256:…)で固定する。

プライベートレジストリの認証(login/トークン権限不足)

# ログインして認証情報を保存
docker login ghcr.io     # GitHub: read:packages 権限のPATを使用
docker login registry.gitlab.com
docker login <your-registry.example.com>

# pull 再試行
docker pull <registry>/<org>/<name>:<tag>

・404/denied/unauthorized は「存在しない」の他に「見えていない」場合も多い。可視性(public/private)やトークン権限(read/pull)を確認。

マニフェストが無い/アーキ差(manifest unknown, not found)

# タグ自体はあるが、arm64 にはマニフェストが無い例
docker buildx imagetools inspect <image>:<tag>

# 暫定:--platform で既存アーキを明示して試す
docker pull --platform=linux/amd64 <image>:<tag>

# 根治:multi-arch で配布(ビルド側)
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 \
  -t <registry>/<org>/<name>:<tag> --push .

FROM 行のベースイメージが見つからない(ビルド時)

# Dockerfile
FROM myorg/base:2025-11-01  # ← そのタグが消えていないか?

# 事前検証:ビルド前にpull
docker pull myorg/base:2025-11-01

# 参照元を固定(ダイジェスト)
FROM myorg/base@sha256:<digest>

・社内レジストリでタグのガベージや上書きが走ると、過去のビルドが再現不能になる。ダイジェスト固定を推奨。

Compose での参照ミス(context, image, build の整合)

# docker-compose.yml
services:
  api:
    image: ghcr.io/myorg/api:v1.2.3   # ← リモートを引く
  web:
    build:
      context: ./web                   # ← ローカルビルド
      dockerfile: Dockerfile
    image: ghcr.io/myorg/web:v2.0.0    # build と image を併用するなら tag の整合を取る

# 展開後の定義で最終形を確認
docker compose config

・build と image を併用したとき、push/pull 先のタグ名を合わせないと次回 up で「Image Not Found」化する。

ネットワーク/DNS/プロキシ/Firewall による擬似“not found”

 DNS解決と443到達確認
nslookup ghcr.io || getent hosts ghcr.io
nc -vz ghcr.io 443

# 企業プロキシ配下:クライアント側の環境を統一
export HTTP_PROXY=http://proxy:8080
export HTTPS_PROXY=http://proxy:8080
export NO_PROXY=localhost,127.0.0.1,.cluster.local,ghcr.io
docker pull ghcr.io/myorg/myapp:v1

・到達不可やミドルボックスのブロックが「not found」風メッセージを返すことがある。まず疎通を確かめる。

レジストリ固有の命名/可視化ルール(GHCR/ECR/GCR 例)

# GHCR(GitHub)
docker pull ghcr.io/<owner>/<repo>/<image>:<tag>  # owner/repo 階層に注意

# ECR(AWS)
aws ecr get-login-password | docker login --username AWS --password-stdin <aws_account>.dkr.ecr.<region>.amazonaws.com
docker pull <aws_account>.dkr.ecr.<region>.amazonaws.com/<name>:<tag>

# GCR/Artifact Registry(GCP)
gcloud auth configure-docker
docker pull <region>-docker.pkg.dev/<project>/<repo>/<image>:<tag>

・組織/プロジェクト/リポジトリの3階層以上の命名を誤ると not found。

ローカルキャッシュの誤解と掃除(見えているが引けない)

# 参照しているのはローカルかリモートかを意識する
docker images | grep <name>

# キャッシュをいったん掃除して再pull
docker image rm <image>:<tag> || true
docker pull <image>:<tag>

・ローカルに同名別タグが残っていて誤動作するケースを除外する。

タグではなくダイジェストで固定(再現性/404回避)

# ダイジェスト取得(Docker)
docker pull <image>:<tag>
docker inspect <image>:<tag> --format '{{index .RepoDigests 0}}'
# 固定して使用
docker run <image>@sha256:xxxxxxxx

・タグの削除や書換えに強く、CIの安定度が上がる。

最小再現テンプレ(名前・認証・存在の三段階を検証)

# 1) 完全修飾名で pull(レジストリ含む)
docker pull docker.io/library/busybox:1.36

# 2) プライベートの場合は login → pull
docker login ghcr.io && docker pull ghcr.io/myorg/myapp:v1.2.3

# 3) マニフェスト有無を確認
docker buildx imagetools inspect ghcr.io/myorg/myapp:v1.2.3

NG→OK 早見表(クイック修正)

# NG: 名前を省略(誤解) → OK: 完全修飾
docker run myapp
docker run ghcr.io/myorg/myapp:v1.2.3

# NG: latest 依存 → OK: バージョン or ダイジェスト固定
docker run myapp:latest
docker run myapp@sha256:<digest>

# NG: 未ログインのプライベート → OK: docker login
docker login <registry> && docker pull <registry>/<org>/<name>:<tag>

# NG: arm64 ノードに amd64 のみ → OK: multi-arch or --platform
docker pull --platform=linux/arm64 <image>:<tag>

# NG: Compose で build/image バラバラ → OK: compose config で整合確認
docker compose config

チェックリスト(上から順に潰す)

1) <registry>/<org>/<name>:<tag> を完全修飾で指定したか
2) docker login 済みか(トークン権限:pull/read)
3) docker buildx imagetools inspect で該当アーキのマニフェストが存在するか
4) ネットワーク/DNS/プロキシでレジストリに到達できるか
5) Dockerfile の FROM タグが有効か(ダイジェスト固定を検討)
6) Compose の image/build/context が整合しているか(docker compose config)
7) ダイジェスト固定で再現性を確保したか
8) それでも不可なら、レジストリUI/APIでタグの実在と可視性を確認したか