docker pull nginx の一行に隠された秘密 — ドメインを省略するとどこへ行くのか? 🐳

“なぜnginxとだけ打ったのにイメージがダウンロードされるのですか?”

— 初心者が最初に疑問に思うこの一行の質問に、

Dockerレジストリの核心的な哲学がすべて詰まっている。

>

🎯 この記事で扱うこと

  • Dockerイメージ参照(reference)の完全なフォーマットと省略規則
  • nginx → docker.io/library/nginx:latest へと展開される3段階のメカニズム
  • 純正Docker Engineでデフォルトレジストリを変更できるか (ネタバレ: できない)
  • registry-mirrors、Podmanのunqualified-search-registriesによる回避の実践方法
  • 短い名前(short name)が引き起こすセキュリティ上の脅威 — タイポスクワッティング

📌 なぜこのテーマが重要なのか

一日に何十回も打つ docker pull nginx。あまりにも自然すぎて、一度も疑ったことがないだろう。しかし、この一行は実は3回の自動補正を経た結果だ。この補正規則を知らないと、次のような状況でたちまち行き詰まる。

  • 社内プライベートレジストリにイメージの出所を一元化する必要があるとき
  • 中国・中東などDocker Hubへのアクセスが制限された環境でデプロイする必要があるとき
  • Docker Hubのプルレート制限 (匿名ユーザーは1時間あたり100回) を回避する必要があるとき
  • タイポスクワッティング攻撃 (類似名の悪性イメージ) を防御する必要があるとき

つまり、このメカニズムは単なる「便利機能」ではなく、運用・セキュリティ・コストが絡む重要な設計ポイントなのだ。

🔍 イメージ参照の完全なフォーマット

Dockerイメージ参照は次の構造に従う。

[REGISTRY[:PORT]/]NAMESPACE/REPOSITORY[:TAG|@DIGEST]
構成要素 説明 省略時のデフォルト値
REGISTRY イメージが保存されているレジストリドメイン docker.io
NAMESPACE 組織・ユーザー・特殊ネームスペース library (docker.io限定)
REPOSITORY イメージリポジトリ名 (省略不可)
TAG バージョン・変種識別子 latest

したがって、docker pull nginx の一行をDockerデーモンが内部的に処理する際には、以下のように3段階の自動補正が順次行われる。

nginx
  ↓ (1) 레지스트리 생략 → docker.io 붙임
docker.io/nginx
  ↓ (2) 네임스페이스 생략 → library 붙임
docker.io/library/nginx
  ↓ (3) 태그 생략 → latest 붙임
docker.io/library/nginx:latest

実際に docker pull nginx を実行してみると、最後の行に docker.io/library/nginx:latest が表示されるのがわかる。Dockerが「実はこのように解釈しました」と親切に教えてくれているわけだ。

library ネームスペースの正体

ここで一つ誤解がある。library というネームスペースは、docker.ioレジストリ専用の特殊規則であり、汎用的な規約ではない。つまり、Quay.ioやGCRのような他のレジストリではこの規則は適用されない。

# docker.ioでのみlibraryの自動補正が行われる
docker pull nginx                       # ✅ docker.io/library/nginx:latest
docker pull quay.io/nginx                # ❌ quay.io/library/nginx には変更されない
docker pull quay.io/bitnami/nginx        # ✅ ネームスペースは必ず明示する必要がある

そのため、docker.io以外のレジストリからイメージを取得する際には、必ずネームスペースを含むフルパス(FQIN, Fully-Qualified Image Name)を使用する必要がある。

🔧 デフォルトレジストリを変更できるか?

結論から申し上げると、以下の通りだ。

ランタイムデフォルトレジストリ変更備考

ランタイムデフォルトレジストリ 変更 備考
Docker Engine (純正) ❌ 不可能 docker.ioにハードコーディング
Docker Engine + registry-mirrors 🔶 回避のみ可能 docker.ioに対するプルスルーミラー
Podman / CRI-O / Buildah ✅ 可能 unqualified-search-registries
RHEL系パッチDocker ✅ 可能 ADD_REGISTRY, BLOCK_REGISTRY オプション (レガシー)

1) 純正Docker Engine — デフォルトレジストリは変更できない

アップストリームのDockerは、デフォルトレジストリを別の場所に変更するオプション自体を提供していない。Docker Hubが常に最終的な検索先となる。これは意図された設計であり、名前の衝突と攻撃対象領域を減らすための保守的な選択だ。

2) registry-mirrors — 変更ではなく「前に挿入する」方式

代わりにDockerは、Docker Hubに対するプルスルーキャッシュミラー(pull-through mirror)を登録できる。/etc/docker/daemon.json を次のように修正すればよい。

{
  "registry-mirrors": [
    "https://mirror.gcr.io",
    "https://registry.mycompany.internal"
  ]
}

そしてデーモンを再起動する。

sudo systemctl restart docker

この設定の動作原理はこうだ。

  1. docker pull nginx リクエストが来ると、
  2. Dockerデーモンはまず登録されたミラーを順番に確認し、
  3. ミラーにイメージがあればそこから取得し、
  4. なければ最終的にdocker.ioへ行く。

つまり、デフォルト値が「代替」されるのではなく、「前に挿入される」のだ。Docker Hubが最終的なバックエンドであるという事実は変わらない。これが、韓国・中国のようにDocker Hubへのアクセスが遅い、または不安定な地域でよく使われるパターンだ。

3) Podman — 本当にデフォルトレジストリを変更できる

一方、Podman・Buildah・CRI-O系は /etc/containers/registries.conf で完全に自由に構成できる。

# /etc/containers/registries.conf

# 短い名前(例: nginx)を検索するレジストリのリスト — 順番に探索
unqualified-search-registries = [
  "registry.mycompany.internal",
  "quay.io",
  "docker.io"
]

# short-name 解釈モード
# "enforcing" の場合、曖昧なときにユーザーに選択を強制する
short-name-mode = "enforcing"

# docker.ioにミラーをアタッチする
[[registry]]
prefix = "docker.io"
location = "docker.io"

  [[registry.mirror]]
  location = "mirror.mycompany.internal:5000"

このように設定した後 podman pull nginx を実行すると、registry.mycompany.internal から順に検索していく。Dockerよりもはるかに柔軟なのだ。この違いが、RHEL・OpenShiftエコシステムがDockerの代わりにPodmanをデフォルト採用した理由の一つでもある。

⚠️ 短い名前が引き起こすセキュリティ上の脅威 — タイポスクワッティング

デフォルトレジストリを変更できるのは便利だが、逆に落とし穴でもある。unqualified-search-registries に複数のレジストリを登録しておくと、どのレジストリからイメージが来たのか曖昧になる。

例えば、探索順序が ["registry1.com", "registry2.com"] のとき、攻撃者が registry1nginx という名前の悪性イメージを先にアップロードすると、正規の nginxregistry2 にあったとしても、registry1 の悪性イメージが先にダウンロードされてしまう。これが短い名前スクワッティング(short-name squatting)攻撃だ。

防御原則3つ

  1. FQINを使おう: プロダクションでは常に docker.io/library/nginx:1.27.3 のようにレジストリ・ネームスペース・タグをすべて明示
  2. ダイジェスト固定: より厳密には nginx@sha256:72297... のようなハッシュ固定。同一イメージを保証
  3. Short-name-mode = “enforcing” (Podman限定): 曖昧な短い名前はユーザーに確認を強制するよう設定

✅ まとめ

docker pull nginx というごく普通の一行は、実はレジストリ → ネームスペース → タグの3回の自動補正を経て docker.io/library/nginx:latest へと展開される結果物だ。この規則はDocker Hubという特定のレジストリの慣習であり、コンテナ世界共通の文法ではない。

核心を一行で要約すると以下の通りだ。

  • 純正Docker Engineではデフォルトレジストリを変更できないregistry-mirrors で前にキャッシュを挿入できるだけだ。
  • Podman系では unqualified-search-registries で完全に自由に構成できる。
  • 利便性の代償は曖昧さだ — プロダクションでは必ずFQINまたはダイジェスト固定を習慣化しよう。

次のステップに関心があるなら、Docker Hubのプルレート制限回避戦略Harbor・ECRのようなプライベートレジストリ構築Sigstoreベースのイメージ署名検証(cosign)CI/CDパイプラインのダイジェストピンニング自動化の順で学習を進めていくと良いだろう。



Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です