OK this is now resolved.
I’m not sure what has changed recently but here’s what I discovered:
Docker’s rate limiting when using IPv6 is per subnet, not per address.
I ran the following commands from here:
TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
curl --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest 2>&1
The response was:
HTTP/1.1 200 OK
content-length: 527
content-type: application/vnd.docker.distribution.manifest.v2+json
docker-content-digest: sha256:c2d41d2ba6d8b7b4a3ffec621578eb4d9a0909df29dfa2f6fd8a2e5fd0836aed
docker-distribution-api-version: registry/2.0
etag: "sha256:c2d41d2ba6d8b7b4a3ffec621578eb4d9a0909df29dfa2f6fd8a2e5fd0836aed"
date: Wed, 13 Nov 2024 13:00:20 GMT
strict-transport-security: max-age=31536000
ratelimit-limit: 100;w=21600
ratelimit-remaining: 0;w=21600
docker-ratelimit-source: 2a03:b0c0:1:e0::
See the docker-ratelimit-source
- something must have changed recently and Docker now lumps together entire IPv6 subnets when rate limiting. I’ve never had reason to check rate limits before so can’t confirm what this was previously.
The solution was to run sudo docker login
- I had previously run docker login
without sudo, so the Docker commands in the update script running as root were not authenticated. I then can use my own account rate limit rather than the shared IP-linked limit.