J’ai un mirror Docker Hub registry:2 sur srv-a, bindé strict 127.0.0.1:5000 (cf. lkd/34). Parfait pour srv-a, mais srv-b et srv-c restent soumis au rate limit Docker Hub.
Partager ce cache entre les trois sans exposer le mirror sur Internet (auth, TLS, rate limiter à monter) ? Mesh WireGuard + double bind du compose. 30 min, zéro complexité durable.
Étape 1 : étendre le WG existant en mesh
srv-a héberge déjà un WG (10.8.0.1/24) pour mon PC. J’ajoute srv-b et srv-c comme peers : keypair sur chaque, ajout dans wg0.conf serveur, côté client Endpoint = cloud.example.com:51820, AllowedIPs = 10.8.0.0/24, PersistentKeepalive = 25.
Astuce : ajouter des peers sans couper les clients connectés. wg-quick down/up déconnecte tout. À la place :
sudo wg syncconf wg0 <(wg-quick strip wg0)
strip filtre les directives non natives (PostUp, Address…), syncconf applique le diff aux peers. Les sessions WG existantes restent up : mon SSH via le tunnel ne saute pas.
Étape 2 : double bind du mirror dans docker-compose
Le ports du mirror passe à :
ports:
- "127.0.0.1:5000:5000" # daemon srv-a local
- "10.8.0.1:5000:5000" # mesh WG srv-b/srv-c
docker compose up -d recrée le container avec les deux binds. Le mirror reste invisible depuis Internet : aucun port 5000 sur l’IP publique, juste loopback + wg0.
Étape 3 : daemon Docker des autres serveurs
Sur srv-b et srv-c, /etc/docker/daemon.json : "registry-mirrors": ["http://10.8.0.1:5000"], puis systemctl restart docker.
Attention : la doc Docker veut https:// sauf host dans insecure-registries. Empiriquement http:// passe sur RFC1918 (10.0.0.0/8) sans config ; sinon ajouter "insecure-registries": ["10.8.0.1:5000"].
Test
$ docker pull alpine:latest # srv-b : 1.869s (cache miss)
$ docker pull alpine:latest # srv-c : 0.516s (cache hit srv-a)
Les logs montrent remoteaddr=10.8.0.11 (srv-c) servi depuis le cache rempli par srv-b juste avant.
Lessons learned
wg syncconf wg0 <(wg-quick strip wg0): ajouter/retirer des peers sans couper les sessions. Peu documenté.- Mesh = peers + AllowedIPs corrects partout. Hub-and-spoke (srv-a ↔ chaque) suffit ; pour srv-b ↔ srv-c direct, peers directs sur chaque.
- Double bind
ports: loopback + interface privée cohabitent, sans reverse proxy. registry-mirrorsacceptehttp://sur RFC1918 sansinsecure-registries.- SPOF mais pas catastrophe : srv-a down = plus de pull de nouvelles images, mais le cache local sert les existantes.
- 1 mirror partagé via mesh plutôt que 3 caches : pulls ×3 économisés, single source of truth. WG ~0.7ms.