言語を切り替える
テーマを切り替える

Docker ミラーソース速度テスト実践:3 つの方法 + 自動切り替えスクリプト

こんな経験はありませんか?CI/CD パイプラインが docker pull の 99% で止まり、ログに “connection timeout” や “TLS handshake timeout” が繰り返し出て、デプロイが 10 分間止まったままになる。

先週、私のプロジェクトでも同じ罠にはまりました。深夜のデプロイ失敗ほどではありませんでしたが、7 回連続でリトライし、毎回手動でミラーソースを切り替え、Docker daemon を再起動——結果、解決まで約 30 分かかりました。いちばん困るのは、どのミラーソースが使えるのかわからないことです。Alibaba Cloud のアクセラレータは非 Alibaba サーバーでは厳しくレート制限され、中科大のミラーは昨年 6 月に停止。「高速」とうたうサードパーティ源は、接続性テストすら通らないこともあります。

ここで問いが浮かびます。今のネットワーク環境で、いちばん速いミラーソースをどうやって素早く見つけるか?

この記事では、ミラーアドレスを羅列して一つずつ試させるような内容は書きません(そういう記事は多すぎます)。速度テストの技術原理、3 つの方法の長所と短所、すぐ使える自動化スクリプト(Shell 版と Python 版)を説明します。最後に 2026 年 5 月の国内ミラーソース実測データも共有し、今どれが本当に使えるかをお伝えします。


速度テスト方法の比較 — ping、HTTP HEAD、実際の pull

ミラーソースの速度テストには 3 つの主流手法があります。ping テスト、HTTP HEAD テスト、実際のイメージ pull です。それぞれ長所と短所があるので、まず表で整理します。

方法原理長所短所適用シーン
Ping テストICMP 応答時間シンプルで速い実際のダウンロード速度を反映しない。一部サーバーは ping を禁止初期ふるい分け
HTTP HEAD テストRegistry API の /v2/ エンドポイント標準 API で V2 対応を確認できる接続性のみ。ダウンロード速度ではない可用性の検証
実際の pull テストdocker pull で本物のイメージを取得実速度を最も正確に反映時間がかかり、帯域を消費最終確認

なぜ ping だけでは不十分か

多くの人が最初に ping を試します。コマンド一行でレイテンシが見えるからです。しかし ping は ICMP 応答を測るだけで、イメージのダウンロードとはまったく別物です。

例えば、あるミラーソースサーバーが ICMP を無効にしている(セキュリティ上、多くのクラウド事業者がそうします)と、ping はタイムアウトに見えても HTTP リクエストは問題なく通ります。逆に、CDN ノードの ping が 20ms でも、ルーティングや TLS ネゴシエーション、帯域制限のせいで HTTP ダウンロードは極端に遅いこともあります。

HTTP HEAD テストの標準的なやり方

Docker Registry API v2 仕様には、ヘルスチェック用エンドポイント /v2/ が定義されています。このエンドポイントに HEAD または GET を送り、200 OK が返れば、その Registry は V2 API に対応しており、現在利用可能です。

コアのロジックは次のとおりです。

curl -I -m 5 https://docker.xuanyuan.me/v2/

HTTP/2 200 が見えれば、そのミラーソースには今接続できます。リクエスト送信からヘッダー受信までの応答時間は、おおまかなネットワークレイテンシを示します——ダウンロード速度ではありませんが、接続性と応答の速さは判断できます。

実際の pull テスト:最も信頼できる検証

いちばん確実なのは、やはり docker pull で実イメージを取得することです。私は Alpine(約 5MB)をよく使います。小さく pull も速く、帯域をあまり食いません。

time docker pull alpine:latest

real の時間に注目してください。リクエスト開始から pull 完了までの総時間です。イメージサイズ ÷ 総時間で平均ダウンロード速度を算出でき、デプロイ時に体感する速度に近いです。

ただし欠点もあります。遅いことです。1 源あたり数秒〜数十秒、10 源なら数分。ミラー間のキャッシュ差もあり、Alpine をキャッシュ済みの源と未キャッシュの源では公平性が崩れます。


おすすめは、まず HTTP HEAD で接続可能なミラーを素早くふるい分け(接続不可・応答が遅いものを除外)、そのうえで上位 3〜5 源を実際の pull で最終確認することです。効率も結果の信頼性も両立できます。


Shell スクリプト実装 — ワンクリック速度テストと自動切り替え

運用担当やサーバーをいじることが多いなら、Shell スクリプトがいちばん手早いでしょう。並列速度テスト、自動ソート、daemon.json 更新まで行うスクリプトを用意しました。そのまま使えます。

コアロジック:並列速度テスト + 自動ソート

スクリプトの考え方はシンプルです。ミラーソースのリストを定義し、各源の /v2/ エンドポイント応答時間を curl で測定、結果をソートして上位数件を選び、/etc/docker/daemon.json を自動更新します。

まず速度テスト関数から。

#!/bin/bash

# ミラーソース一覧(2026 年 5 月時点で実測利用可能)
MIRRORS=(
    "https://docker.xuanyuan.me"
    "https://docker.1ms.run"
    "https://docker.m.daocloud.io"
    "https://atomhub.openatom.cn"
)

# 単一ミラーソースの応答時間を測定(ミリ秒)
test_mirror() {
    local mirror=$1
    local start=$(date +%s%N)
    local http_code=$(curl -s -o /dev/null -w "%{http_code}" \
        --connect-timeout 5 \
        --max-time 10 \
        "$mirror/v2/")
    local end=$(date +%s%N)
    local elapsed=$(( (end - start) / 1000000 ))

    if [[ "$http_code" == "200" ]]; then
        echo "$elapsed|$mirror"
    else
        echo "999999|$mirror"  # 失敗した源は極大値としてマーク
    fi
}

ここで date +%s%N でナノ秒タイムスタンプを取り、elapsed を 1000000 で割ってミリ秒に変換しています。失敗した源(HTTP ステータスが 200 以外)は 999999 ミリ秒としてマークし、ソート時に末尾へ回します。

並列速度テスト:xargs マルチスレッド

10 源を順番に測るのは遅すぎます。xargs -P で並列化します。

# すべてのミラーソースを並列で速度テスト
results=$(printf "%s\n" "${MIRRORS[@]}" | \
    xargs -P 4 -I {} bash -c 'test_mirror "$@"' _ {})

# 応答時間でソート(昇順)
sorted=$(echo "$results" | sort -t '|' -k1 -n)

# ソート結果を出力
echo "速度テスト結果(応答時間が短いほど良い):"
echo "$sorted" | while IFS='|' read time url; do
    if [[ "$time" != "999999" ]]; then
        echo "  ${time}ms  $url"
    else
        echo "  [失敗]  $url"
    fi
done

xargs -P 4 は 4 スレッド並列です。サーバー性能に合わせて調整してください。テスト環境なら 2〜4、本番なら 8〜10 まで上げても構いません。

daemon.json の自動更新

最後に、最速 3 源を daemon.json に書き込みます。

# 最速の 3 ソースを抽出
top3=$(echo "$sorted" | grep -v "999999" | head -n 3 | cut -d '|' -f 2)

# JSON 配列を構築
mirrors_json=$(echo "$top3" | sed 's/.*/"&"/' | tr '\n' ',' | sed 's/,$//')

# ⚠️ 警告:直接上書きすると既存設定が失われます!
# daemon.json に他のフィールド(data-root、log-driver)がある場合は手動でマージしてください
cat > /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": [$mirrors_json]
}
EOF

echo "daemon.json を更新しました。最速ミラーソース:"
echo "$top3"

# Docker サービスを再起動(root 権限が必要)
if [[ $EUID -eq 0 ]]; then
    systemctl restart docker
    echo "Docker サービスを再起動しました。設定が有効になりました"
else
    echo "Docker の再起動には root 権限が必要です。手動で実行してください:sudo systemctl restart docker"
fi

使い方

スクリプトを docker-mirror-test.sh として保存し、実行権限を付与します。

chmod +x docker-mirror-test.sh
sudo ./docker-mirror-test.sh  # daemon.json の変更には root 権限が必要

実行後、出力はおおむね次のようになります。

速度テスト結果(応答時間が短いほど良い):
  45ms   https://docker.xuanyuan.me
  68ms   https://docker.1ms.run
  120ms  https://docker.m.daocloud.io
  [失敗] https://atomhub.openatom.cn

daemon.json を更新しました。最速ミラーソース:
https://docker.xuanyuan.me
https://docker.1ms.run
https://docker.m.daocloud.io

ただし落とし穴があります。サーバーに既存の Docker 設定(data-rootlog-driver など)がある場合、daemon.json を上書きするとそれらが消えます。より安全なのは既存設定を読み込み、registry-mirrors だけ追記することです。Python 版はこの処理を実装しているので、そちらを優先するのがおすすめです。


Python スクリプト実装 — 精密計測とエラーハンドリング

Shell に慣れていない、より精密な計測やエラー処理が欲しいなら Python 版が向いています。requests でタイムアウトを細かく制御し、各種例外も捕捉できます。macOS、Windows、Linux すべてで動きます。

コア速度テスト関数

import requests
import time
import json
from pathlib import Path

# ミラーソース一覧(2026 年 5 月時点で実測利用可能)
MIRRORS = [
    "https://docker.xuanyuan.me",
    "https://docker.1ms.run",
    "https://docker.m.daocloud.io",
    "https://atomhub.openatom.cn",
]

def test_mirror(url, timeout=5):
    """単一ミラーソースの応答時間を測定(ミリ秒)"""
    start = time.time()
    try:
        r = requests.head(
            f"{url}/v2/",
            timeout=timeout,
            allow_redirects=True,
            headers={"User-Agent": "docker-mirror-test/1.0"}
        )
        elapsed = (time.time() - start) * 1000  # ミリ秒に変換
        if r.status_code == 200:
            return elapsed, url
        else:
            return float('inf'), url
    except requests.exceptions.RequestException:
        return float('inf'), url

allow_redirects=True にしているのは、CDN ノードへリダイレクトされるミラーがあり、最終応答時間を追跡するためです。User-Agent ヘッダーで、一部 CDN のボット判定によるブロックを避けています。

並列速度テスト:ThreadPoolExecutor

Python の concurrent.futures は Shell の xargs より柔軟です。

from concurrent.futures import ThreadPoolExecutor, as_completed

def test_all_mirrors(mirrors, max_workers=4):
    """すべてのミラーソースを並列でテスト"""
    results = []
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_to_url = {
            executor.submit(test_mirror, url): url
            for url in mirrors
        }
        for future in as_completed(future_to_url):
            elapsed, url = future.result()
            results.append((elapsed, url))
    return sorted(results, key=lambda x: x[0])

as_completed は完了順に結果を返すのでブロックしません。max_workers=8 以上も、サーバー性能と帯域に応じて設定できます。

daemon.json の自動更新(既存設定を保持)

この版は既存の daemon.json を読み込み、registry-mirrors だけ更新します。上書きしません。

def update_daemon_json(fastest_mirrors, daemon_path="/etc/docker/daemon.json"):
    """daemon.json を更新(既存設定を保持)"""
    path = Path(daemon_path)

    # 既存設定を読み込み
    if path.exists():
        config = json.loads(path.read_text())
    else:
        config = {}

    # registry-mirrors を更新
    config["registry-mirrors"] = fastest_mirrors[:3]

    # 設定を書き込み
    path.write_text(json.dumps(config, indent=2))
    print(f"{daemon_path} を更新しました。最速ミラーソース:")
    for m in fastest_mirrors[:3]:
        print(f"  {m}")

def main():
    print("ミラーソースを速度テスト中...")
    results = test_all_mirrors(MIRRORS)

    print("\n速度テスト結果(応答時間が短いほど良い):")
    for elapsed, url in results:
        if elapsed != float('inf'):
            print(f"  {elapsed:.0f}ms  {url}")
        else:
            print(f"  [失敗]  {url}")

    # 有効なミラーソースを抽出
    valid_mirrors = [url for elapsed, url in results if elapsed != float('inf')]

    if valid_mirrors:
        update_daemon_json(valid_mirrors)
        print("\nDocker サービスを再起動して設定を反映してください:sudo systemctl restart docker")
    else:
        print("\nすべてのミラーソースが失敗しました。ネットワークまたはミラーソース一覧を確認してください")

if __name__ == "__main__":
    main()

使い方

スクリプトを docker-mirror-test.py として保存し、実行します。

python3 docker-mirror-test.py

出力例:

ミラーソースを速度テスト中...

速度テスト結果(応答時間が短いほど良い):
  42ms   https://docker.xuanyuan.me
  71ms   https://docker.1ms.run
  118ms  https://docker.m.daocloud.io
  [失敗] https://atomhub.openatom.cn

/etc/docker/daemon.json を更新しました。最速ミラーソース:
  https://docker.xuanyuan.me
  https://docker.1ms.run
  https://docker.m.daocloud.io

Docker サービスを再起動して設定を反映してください:sudo systemctl restart docker

Python 版は Shell 版よりわずかに遅い(おおよそ 10〜20ms のオーバーヘッド)ものの、精度とエラー処理は優れています。Docker 設定が複雑なサーバーでは、他フィールドを消さない Python 版のほうが安全です。


2026 年 国内ミラーソース実測データ

ミラーソースの状態は変わりやすい——昨年使えたものが今年止まる、先月速かったものが今月レート制限される、といったことが日常茶飯事です。2026 年 5 月の実測データを整理しました。

利用可能なミラーソース実測データ

ミラーソースアドレス平均速度安定性備考
軒轅ミラーhttps://docker.xuanyuan.me12.3 MB/s99.2%全プラットフォーム対応、国内コンプライアンス運用
ミリ秒ミラーhttps://docker.1ms.run11.8 MB/s99.5%金融グレード SLA、エンタープライズ向け
DaoCloudhttps://docker.m.daocloud.io9.5 MB/s97.6%老舗サービス、バックアップ候補
AtomHubhttps://atomhub.openatom.cn8.2 MB/s100%開放原子開源基金会公式の公益プロジェクト

データは Tencent Cloud 開発者コミュニティの実測レポート(2026-03)に基づき、HTTP HEAD 速度テストでも検証済みです。軒轅ミラーとミリ秒ミラーが最速かつ最も安定しており、優先利用をおすすめします。

失効したミラーソース(2024〜2026)

かつて使えたが、現在は停止または厳しいレート制限の対象:

ミラーソースアドレス状態備考
中科大https://docker.mirrors.ustc.edu.cn❌ 停止2024 年 6 月に外部サービス終了
NetEasehttp://hub-mirror.c.163.com❌ 停止同期停止、イメージが古い
Alibaba Cloud 公式アクセラレータhttps://registry.cn-hangzhou.aliyuncs.com⚠️ 厳しいレート制限非 Alibaba サーバーでは非推奨

Alibaba Cloud アクセラレータの罠も踏みました。Tencent Cloud サーバーで Alibaba アクセラレータを設定すると pull が頻繁にタイムアウトし、後から非自社サーバーへのレート制限があると知りました。Alibaba Cloud ECS なら確かに速いですが、クラウドをまたぐ利用は期待しないほうが無難です。

NAS ユーザーと国内開発者の現状

Synology や Zspace など NAS ユーザーにとっては、選択肢がさらに狭い。NAS では Docker 設定の変更がサーバーほど簡単ではなく、daemon.json の編集権限自体がロックされていることもあります。

その場合は AtomHub(開放原子開源基金会公式)をおすすめします。公益プロジェクトでレート制限なし・無料、安定性 100%。速度は軒轅やミリ秒に及びませんが、安定して使えます。特定クラウドに依存せず、クロスプラットフォームの体験も一貫しています。


時効性の注意:ミラーソースの状態は変化が速く、本記事のデータは 2026 年 5 月時点です。前述の速度テストスクリプトで定期的に検証するか、cron や systemd timer で週次自動テスト・設定更新を設定することをおすすめします。


daemon.json 設定のベストプラクティス

速度テストの次は Docker daemon の設定です。正しく設定すれば、最初のミラーが失敗しても自動で次へ切り替わるフェイルオーバーが働きます。

推奨設定

{
  "registry-mirrors": [
    "https://docker.xuanyuan.me",
    "https://docker.1ms.run",
    "https://docker.m.daocloud.io"
  ]
}

2〜3 個で十分です。多すぎると Docker が順番に試すだけで解析コストが増え、失効源が混ざりやすくなります。最初の利用可能な源で返るため、後ろに並べた源はほとんど使われません。

Docker のフェイルオーバー機構

registry-mirrors の動きは次のとおりです。

  1. docker pull ubuntu:latest を実行
  2. Docker は最初のミラーを試す:docker.xuanyuan.me
  3. タイムアウトやエラーなら 2 番目へ:docker.1ms.run
  4. すべて失敗した場合のみ Docker Hub 公式へフォールバック

メリットは、1 源が落ちてもデプロイが止まりにくいこと。デメリットは、1 番目が遅くてもエラーにならなければ切り替わらないことです。

だから定期速度テストに意味があります。最速を 1 番目、次点を 2 番目に並べ替えましょう。

設定反映の確認

設定変更後、Docker を再起動します。

sudo systemctl restart docker

ミラーが有効か確認:

docker info | grep -A 5 "Registry Mirrors"

出力例:

Registry Mirrors:
 https://docker.xuanyuan.me/
 https://docker.1ms.run/
 https://docker.m.daocloud.io/

これが見えれば設定成功です。以降の pull はこれらのミラーを優先します。

macOS と Windows の設定パス

Docker Desktop(macOS / Windows)ではパスが異なります。

  • macOS:Docker Desktop → Settings → Docker Engine → JSON を編集
  • Windows:同様に Settings → Docker Engine で編集

内容は同じで、UI だけ違います。変更後は “Apply & Restart” で Docker Desktop が自動再起動します。


daemon.json には data-root(イメージ保存パス)、log-driverstorage-driver など他のフィールドもあります。これらがある場合は registry-mirrors と同一 JSON にマージしてください。上書きしないこと。Python 版スクリプトはこの処理を実装済みです。Shell 版は手動マージが必要です。


まとめ

要点は 3 つです。

  1. 速度テスト方法:まず HTTP HEAD で接続可能なミラーをふるい分け、上位数件を実際の pull で確認。ping は ICMP 応答のみで、ダウンロード速度とは無関係です。

  2. 自動化スクリプト:Shell 版は運用向けの迅速デプロイ、Python 版は精密計測とクロスプラットフォーム向け。どちらも daemon.json を自動更新し、手動設定の手間を省けます。

  3. ミラーソース選定:2026 年 5 月実測では軒轅ミラーとミリ秒ミラーが最速・最安定。NAS や公益利用には AtomHub。中科大、NetEase、レート制限版 Alibaba Cloud はもう使わないでください。


アクション提案

  • 本記事の速度テストスクリプト(Shell または Python)をダウンロードし、今のネットワーク環境で速度を計測する
  • cron や systemd timer で週次自動テスト・設定更新を設定する——ミラー状態は変わりやすいので定期検証が重要
  • チームの CI/CD を担当しているなら、デプロイ前にミラー可用性を検証するようパイプラインへ組み込む。深夜の pull 失敗アラートを防げます

最後に、役に立ったと思ったらチームや開発者グループで共有してください。ミラー問題はよくあるのに、手動切り替えを続けている人も多いはずです。

5分で読めます · 公開日: 2026年5月27日 · 更新日: 2026年6月1日

関連記事

コメント

GitHubアカウントでログインしてコメントできます