Cambiar tema

Prueba de velocidad de mirrors Docker: 3 métodos + script de cambio automático

Easton editorial illustration: large image-pull speedometer with one winning range

¿Te ha pasado alguna vez? El pipeline de CI/CD se queda atascado en el 99 % de un docker pull, el log repite “connection timeout” y “TLS handshake timeout”, y el despliegue lleva diez minutos parado.

La semana pasada me pasó en un proyecto. No era una caída a las tres de la madrugada, pero tras siete reintentos, cambiar el mirror a mano y reiniciar el daemon de Docker, casi media hora hasta resolverlo. Lo peor: no sabes qué mirror funciona. El acelerador de Alibaba Cloud limita mucho fuera de sus propios servidores, el mirror de la USTC dejó de ofrecer servicio en junio del año pasado, y esos mirrors “de alta velocidad” de terceros a veces ni siquiera pasan una prueba básica de conectividad.

De ahí la pregunta: ¿cómo medir la velocidad rápido y encontrar el mirror más rápido en tu red actual?

En este artículo no te daré una lista de direcciones para probar una a una (hay demasiados de esos). Hablaré de la lógica técnica de la medición, las ventajas e inconvenientes de tres métodos, y dos scripts listos para usar (Shell y Python). Al final comparto datos reales de mirrors en China medidos en mayo de 2026, para que sepas cuáles funcionan de verdad hoy.


Comparación de métodos: ping, HTTP HEAD y pull real

Hay tres enfoques habituales: ping, HTTP HEAD y pull real de imagen. Cada uno tiene pros y contras; la tabla resume las diferencias.

MétodoPrincipioVentajasDesventajasCaso de uso
PingTiempo de respuesta ICMPSimple y rápidoNo refleja la velocidad de descarga; muchos servidores bloquean pingFiltrado inicial
HTTP HEADEndpoint /v2/ de la Registry APIAPI estándar; verifica soporte V2Solo conectividad, no velocidad de descargaValidar disponibilidad
Pull realdocker pull de una imagen realRefleja la velocidad real con precisiónLento; consume ancho de bandaVerificación final

¿Por qué ping no basta?

Mucha gente prueba ping primero: un comando y ves la latencia. Pero ping mide ICMP, algo distinto de descargar una imagen.

Ejemplo: un mirror puede tener ICMP desactivado (común en la nube por seguridad), ping da timeout y HTTP funciona bien. Al revés: un nodo CDN con 20 ms de ping puede ir lento por rutas, TLS o límites de ancho de banda.

HTTP HEAD: la práctica estándar

La Registry API v2 define un endpoint de salud: /v2/. Un HEAD o GET que devuelva 200 OK indica soporte V2 y disponibilidad.

La lógica central:

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

Si ves HTTP/2 200, el mirror responde. El tiempo hasta recibir la cabecera aproxima la latencia de red: no es velocidad de descarga, pero sirve para conectividad y respuesta.

Pull real: la verificación más fiable

Lo más fiable es docker pull de una imagen real. Uso Alpine (~5 MB): pequeña, rápida, poco ancho de banda.

time docker pull alpine:latest

Mira el tiempo real: de la petición al fin del pull. Con tamaño de imagen / tiempo obtienes la velocidad media, la que notarás en despliegues.

Inconveniente: lento. Un mirror tarda segundos o decenas de segundos; diez mirrors, varios minutos. Además, el caché difiere entre mirrors y puede sesgar la comparación.


Mi recomendación: HTTP HEAD para filtrar mirrors con buena conectividad (descartar los lentos o caídos), luego pull real para validar los 3–5 más rápidos. Eficiente y fiable.


Implementación en Shell: medición y cambio automático con un clic

Si eres de operaciones o sueles tocar servidores, un script Shell es lo más directo. Este script mide en paralelo, ordena resultados y actualiza daemon.json.

Lógica central: medición concurrente + ordenación

Define una lista de mirrors, prueba /v2/ con curl, ordena y escribe los más rápidos en /etc/docker/daemon.json.

Función de medición:

#!/bin/bash

# Lista de mirrors (verificados en mayo de 2026)
MIRRORS=(
    "https://docker.xuanyuan.me"
    "https://docker.1ms.run"
    "https://docker.m.daocloud.io"
    "https://atomhub.openatom.cn"
)

# Probar tiempo de respuesta de un mirror (milisegundos)
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"  # Marcar fallos con valor muy alto
    fi
}

Detalle: date +%s%N da nanosegundos; al dividir entre 1000000 obtienes milisegundos. Mirrors con código distinto de 200 se marcan como 999999 ms y quedan al final al ordenar.

Medición concurrente: xargs multihilo

Probar diez mirrors uno a uno es lento. Uso xargs -P:

# Medir todos los mirrors en paralelo
results=$(printf "%s\n" "${MIRRORS[@]}" | \
    xargs -P 4 -I {} bash -c 'test_mirror "$@"' _ {})

# Ordenar por tiempo de respuesta (ascendente)
sorted=$(echo "$results" | sort -t '|' -k1 -n)

# Mostrar resultados ordenados
echo "Resultados (menor tiempo = mejor):"
echo "$sorted" | while IFS='|' read time url; do
    if [[ "$time" != "999999" ]]; then
        echo "  ${time}ms  $url"
    else
        echo "  [fallo]  $url"
    fi
done

xargs -P 4 lanza 4 hilos. Ajusta según el servidor: 2–4 en pruebas, 8–10 en producción si hace falta.

Actualizar daemon.json automáticamente

Último paso: escribir los 3 mirrors más rápidos.

# Extraer los 3 mirrors más rápidos
top3=$(echo "$sorted" | grep -v "999999" | head -n 3 | cut -d '|' -f 2)

# Construir array JSON
mirrors_json=$(echo "$top3" | sed 's/.*/"&"/' | tr '\n' ',' | sed 's/,$//')

# ⚠️ Advertencia: sobrescribir pierde la configuración existente
# Si daemon.json ya tiene otros campos (data-root, log-driver), combínalos a mano
cat > /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": [$mirrors_json]
}
EOF

echo "daemon.json actualizado, mirrors más rápidos:"
echo "$top3"

# Reiniciar Docker (requiere root)
if [[ $EUID -eq 0 ]]; then
    systemctl restart docker
    echo "Servicio Docker reiniciado; configuración aplicada"
else
    echo "Se necesita root para reiniciar Docker. Ejecuta: sudo systemctl restart docker"
fi

Uso

Guarda el script como docker-mirror-test.sh y dale permiso de ejecución:

chmod +x docker-mirror-test.sh
sudo ./docker-mirror-test.sh  # root para modificar daemon.json

Salida típica:

Resultados (menor tiempo = mejor):
  45ms   https://docker.xuanyuan.me
  68ms   https://docker.1ms.run
  120ms  https://docker.m.daocloud.io
  [fallo] https://atomhub.openatom.cn

daemon.json actualizado, mirrors más rápidos:
https://docker.xuanyuan.me
https://docker.1ms.run
https://docker.m.daocloud.io

Ojo: si ya tienes otras opciones en Docker (data-root, log-driver), sobrescribir daemon.json las borra. Es más seguro leer la config existente y añadir registry-mirrors. La versión Python hace eso; te la recomiendo si tienes config previa.


Implementación en Python: cronometraje preciso y manejo de errores

Si Shell no es lo tuyo, o quieres tiempos más precisos y mejor manejo de errores, Python con requests controla timeouts y excepciones, y funciona en macOS, Windows y Linux.

Función central de medición

import requests
import time
import json
from pathlib import Path

# Lista de mirrors (verificados en mayo de 2026)
MIRRORS = [
    "https://docker.xuanyuan.me",
    "https://docker.1ms.run",
    "https://docker.m.daocloud.io",
    "https://atomhub.openatom.cn",
]

def test_mirror(url, timeout=5):
    """Probar tiempo de respuesta de un mirror (milisegundos)"""
    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  # convertir a ms
        if r.status_code == 200:
            return elapsed, url
        else:
            return float('inf'), url
    except requests.exceptions.RequestException:
        return float('inf'), url

Uso allow_redirects=True porque algunos mirrors redirigen a CDN; hay que medir la respuesta final. El User-Agent evita bloqueos por bots en ciertos CDN.

Medición concurrente: ThreadPoolExecutor

concurrent.futures ofrece un pool más flexible que xargs:

from concurrent.futures import ThreadPoolExecutor, as_completed

def test_all_mirrors(mirrors, max_workers=4):
    """Probar todos los mirrors en paralelo"""
    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 devuelve resultados al terminar cada tarea, sin bloquear. Puedes subir max_workers a 8 o más según CPU y red.

Actualizar daemon.json (conservando la config existente)

Esta versión lee daemon.json actual y actualiza registry-mirrors sin borrar el resto:

def update_daemon_json(fastest_mirrors, daemon_path="/etc/docker/daemon.json"):
    """Actualizar daemon.json conservando la configuración existente"""
    path = Path(daemon_path)

    # Leer configuración existente
    if path.exists():
        config = json.loads(path.read_text())
    else:
        config = {}

    # Actualizar registry-mirrors
    config["registry-mirrors"] = fastest_mirrors[:3]

    # Escribir configuración
    path.write_text(json.dumps(config, indent=2))
    print(f"Actualizado {daemon_path}, mirrors más rápidos:")
    for m in fastest_mirrors[:3]:
        print(f"  {m}")

def main():
    print("Midiendo velocidad de mirrors...")
    results = test_all_mirrors(MIRRORS)

    print("\nResultados (menor tiempo = mejor):")
    for elapsed, url in results:
        if elapsed != float('inf'):
            print(f"  {elapsed:.0f}ms  {url}")
        else:
            print(f"  [fallo]  {url}")

    # Extraer mirrors válidos
    valid_mirrors = [url for elapsed, url in results if elapsed != float('inf')]

    if valid_mirrors:
        update_daemon_json(valid_mirrors)
        print("\nReinicia Docker para aplicar: sudo systemctl restart docker")
    else:
        print("\nTodos los mirrors fallaron; revisa red o la lista de mirrors")

if __name__ == "__main__":
    main()

Uso

Guarda como docker-mirror-test.py y ejecuta:

python3 docker-mirror-test.py

Ejemplo de salida:

Midiendo velocidad de mirrors...

Resultados (menor tiempo = mejor):
  42ms   https://docker.xuanyuan.me
  71ms   https://docker.1ms.run
  118ms  https://docker.m.daocloud.io
  [fallo] https://atomhub.openatom.cn

Actualizado /etc/docker/daemon.json, mirrors más rápidos:
  https://docker.xuanyuan.me
  https://docker.1ms.run
  https://docker.m.daocloud.io

Reinicia Docker para aplicar: sudo systemctl restart docker

La versión Python es un poco más lenta (~10–20 ms de overhead), pero más precisa y robusta. Si tu daemon.json ya tiene varios campos, Python es más seguro y no pisa el resto.


Datos reales de mirrors en China (mayo 2026)

El estado de los mirrors cambia rápido: lo que funcionaba el año pasado puede estar caído; lo rápido el mes pasado puede estar limitado hoy. Resumo mediciones de mayo de 2026.

Mirrors disponibles (mediciones)

MirrorDirecciónVelocidad mediaEstabilidadNotas
Xuanyuanhttps://docker.xuanyuan.me12.3 MB/s99.2%Multiplataforma; operación conforme en China
1mshttps://docker.1ms.run11.8 MB/s99.5%SLA de nivel financiero; preferido en empresas
DaoCloudhttps://docker.m.daocloud.io9.5 MB/s97.6%Servicio consolidado; opción de respaldo
AtomHubhttps://atomhub.openatom.cn8.2 MB/s100%Proyecto oficial de la OpenAtom Foundation

Datos de un informe de la comunidad Tencent Cloud (2026-03), verificados con HTTP HEAD; encajan en general. Xuanyuan y 1ms son los más rápidos y estables; conviene probarlos primero.

Mirrors ya no válidos (2024–2026)

Estos funcionaron antes pero hoy están caídos o muy limitados:

MirrorDirecciónEstadoNotas
USTChttps://docker.mirrors.ustc.edu.cn❌ DetenidoDejó servicio externo en junio de 2024
NetEasehttp://hub-mirror.c.163.com❌ DetenidoSin sincronización; imágenes obsoletas
Acelerador oficial Alibaba Cloudhttps://registry.cn-hangzhou.aliyuncs.com⚠️ Muy limitadoFuerte throttling fuera de ECS Alibaba; no recomendado

El acelerador de Alibaba es una trampa habitual: en un servidor Tencent Cloud, pulls con timeout frecuentes; Alibaba limita tráfico ajeno a su nube. En ECS Alibaba va bien; entre nubes distintas, no cuentes con ello.

NAS y desarrolladores en China

En Synology o Zspace, cambiar la config de Docker no es tan simple como en un servidor; algunos sistemas bloquean editar daemon.json.

En ese caso recomiendo AtomHub (OpenAtom Foundation): proyecto de beneficio público, sin throttling ni cobro, estabilidad 100 %. Más lento que Xuanyuan o 1ms, pero usable. No depende de un cloud concreto; experiencia coherente entre plataformas.


Nota de vigencia: el estado de los mirrors cambia rápido; estos datos son de mayo de 2026. Usa los scripts anteriores de forma periódica o un cron semanal para actualizar la config.


Buenas prácticas para daemon.json

Tras medir, toca configurar el daemon. Una buena config permite conmutación: si falla el primer mirror, Docker prueba el siguiente.

Configuración recomendada

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

Con 2–3 mirrors basta. Docker prueba en orden y usa el primero que responda; el resto no se usa. Demasiados mirrors añaden coste de resolución y pueden incluir fuentes muertas.

Mecanismo de conmutación de Docker

Así funciona registry-mirrors:

  1. Ejecutas docker pull ubuntu:latest
  2. Docker intenta primero docker.xuanyuan.me
  3. Si timeout o error, pasa a docker.1ms.run
  4. Si todos fallan, vuelve a Docker Hub oficial

Ventaja: un mirror caído no para el despliegue. Inconveniente: si el primero responde lento pero no falla, Docker no salta al más rápido.

Por eso tiene sentido medir de vez en cuando: el más rápido primero, el segundo en segunda posición.

Verificar que la config aplica

Tras cambiar, reinicia Docker:

sudo systemctl restart docker

Comprueba los mirrors:

docker info | grep -A 5 "Registry Mirrors"

Salida esperada:

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

Si lo ves, la config está activa y los pulls usarán esos mirrors con prioridad.

Rutas en macOS y Windows

Con Docker Desktop la ruta es distinta:

  • macOS: Docker Desktop → Settings → Docker Engine → editar JSON
  • Windows: Settings → Docker Engine, igual

El contenido JSON es el mismo; solo cambia la UI. Tras editar, “Apply & Restart”.


daemon.json admite más campos: data-root, log-driver, storage-driver, etc. Combínalos con registry-mirrors en un solo JSON; no sobrescribas todo. Python ya lo hace; en Shell debes fusionar a mano.


Resumen

En esencia, tres ideas:

  1. Métodos de medición: HTTP HEAD para filtrar mirrors con buena conectividad; pull real para validar los más rápidos. No uses ping: mide ICMP, no velocidad de descarga.

  2. Scripts automáticos: Shell para despliegue rápido en ops; Python para precisión y multiplataforma. Ambos pueden actualizar daemon.json sin configurar a mano.

  3. Elección de mirror: en mayo de 2026, Xuanyuan y 1ms son los más rápidos y estables; AtomHub encaja en NAS y escenarios de beneficio público. Deja de usar USTC, NetEase y el acelerador Alibaba limitado fuera de su nube.


Qué hacer ahora:

  • Descarga el script (Shell o Python) y mide mirrors en tu red
  • Programa un cron o systemd timer semanal para rem medir y actualizar: los mirrors cambian rápido
  • Si gestionas CI/CD del equipo, integra la medición antes del despliegue para evitar alertas nocturnas por pull fallido

Si te ha servido, compártelo con el equipo o la comunidad. El tema de mirrors es habitual y mucha gente sigue cambiando a mano; les ahorrarás tiempo.

FAQ

¿Le ping suffit-il pour choisir un miroir Docker ?
No. Le ping mesure l'ICMP y peut être bloqué o ne pas refléter el débit del registre. Utilisez-el seulement comme préfiltre, puis vérifiez l'endpoint /v2/ y terminez por un vrai docker pull.
¿Qué méthode donne le benchmark le plus fiable ?
Un pull réel d'una petite image mesure el mieux l'expérience complète, notamment DNS, TLS, métadonnées y téléchargement. Supprimez l'effet del cache y répétez el test para comparer los miroirs équitablement.
¿Cómo automatiser le choix du meilleur miroir ?
Filtrez d'abord los endpoints joignables con una requête HTTP, mesurez plusieurs fois leur latence, puis effectuez un pull en los meilleurs candidats. Ne modifiez daemon.json qu'après validation y conservez una configuration de secours.

11 min de lectura · Publicado el: 27 may 2026 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog