Skip to content

Commit 68b7e9f

Browse files
committed
Merge branch 'master' into cpierre/rebase
2 parents 3d6b841 + 5b8bf25 commit 68b7e9f

File tree

8 files changed

+79
-33
lines changed

8 files changed

+79
-33
lines changed

Dockerfile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# syntax=docker/dockerfile:1
2+
# check=skip=SecretsUsedInArgOrEnv
3+
14
# We start from my nginx fork which includes the proxy-connect module from tEngine
25
# Source is available at https://github.com/rpardini/nginx-proxy-connect-stable-alpine
36
# This is already multi-arch!
@@ -9,7 +12,7 @@ ARG BASE_IMAGE_SUFFIX="${IMAGE_SUFFIX}"
912
FROM ${BASE_IMAGE}${BASE_IMAGE_SUFFIX}
1013

1114
# Link image to original repository on GitHub
12-
LABEL org.opencontainers.image.source https://github.com/rpardini/docker-registry-proxy
15+
LABEL org.opencontainers.image.source=https://github.com/rpardini/docker-registry-proxy
1316

1417
# apk packages that will be present in the final image both debug and release
1518
RUN apk add --no-cache --update bash ca-certificates-bundle coreutils openssl
@@ -70,7 +73,7 @@ EXPOSE 8082
7073

7174
## Default envs.
7275
# A space delimited list of registries we should proxy and cache; this is in addition to the central DockerHub.
73-
ENV REGISTRIES="k8s.gcr.io gcr.io quay.io"
76+
ENV REGISTRIES="registry.k8s.io gcr.io quay.io ghcr.io"
7477
# A space delimited list of registry:user:password to inject authentication for
7578
ENV AUTH_REGISTRIES="some.authenticated.registry:oneuser:onepassword another.registry:user:password"
7679
# Should we verify upstream's certificates? Default to true.
@@ -146,5 +149,8 @@ ENV PROXY_CONNECT_READ_TIMEOUT="60s"
146149
ENV PROXY_CONNECT_CONNECT_TIMEOUT="60s"
147150
ENV PROXY_CONNECT_SEND_TIMEOUT="60s"
148151

152+
# Allow disabling IPV6 resolution, default to false
153+
ENV DISABLE_IPV6="false"
154+
149155
# Did you want a shell? Sorry, the entrypoint never returns, because it runs nginx itself. Use 'docker exec' if you need to mess around internally.
150156
ENTRYPOINT ["/entrypoint.sh"]

README.md

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1-
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/rpardini/docker-registry-proxy/master-latest?label=%3Alatest%20from%20master)
1+
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/rpardini/docker-registry-proxy/master-latest.yaml?branch=master&label=%3Alatest%20from%20master)
22
![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/rpardini/docker-registry-proxy?label=last%20tagged%20release)
3-
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/rpardini/docker-registry-proxy/tags?label=last%20tagged%20release)
3+
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/rpardini/docker-registry-proxy/tags.yaml?branch=master&label=last%20tagged%20release)
44
![Docker Image Size (latest semver)](https://img.shields.io/docker/image-size/rpardini/docker-registry-proxy?sort=semver)
55
![Docker Pulls](https://img.shields.io/docker/pulls/rpardini/docker-registry-proxy)
66
## TL,DR
77

88
A caching proxy for Docker; allows centralised management of (multiple) registries and their authentication; caches images from *any* registry.
99
Caches the potentially huge blob/layer requests (for bandwidth/time savings), and optionally caches manifest requests ("pulls") to avoid rate-limiting.
1010

11+
### `0.6.5`: Updated late February 2025 for the "2nd Docker Apocalypse"
12+
13+
Docker, Inc has announced a [2nd apocalypse](https://www.docker.com/blog/revisiting-docker-hub-policies-prioritizing-developer-experience/) for 1st of March'25 (it has [already been pushed back to April](https://www.theregister.com/2025/02/22/docker_hub_pull_limits/)).
14+
This has caused a new surge of interest in this project; in response I've updated all dependencies to the latest versions,
15+
added a [Test matrix](https://github.com/rpardini/docker-registry-proxy/actions/workflows/test.yaml), merged some pull requests (including `DISABLE_IPV6=true`, which was a long-standing request), and updated the documentation.
16+
17+
Many thanks to all the contributors over the years; I've no intention of abandoning this project -- please keep sending and updating your PRs.
18+
1119
### NEW: avoiding DockerHub Pull Rate Limits with Caching
1220

1321
Starting November 2nd, 2020, DockerHub will
@@ -18,7 +26,7 @@ also known as the _Docker Apocalypse_.
1826
The main symptom is `Error response from daemon: toomanyrequests: Too Many Requests. Please see https://docs.docker.com/docker-hub/download-rate-limit/` during pulls.
1927
Many unknowing Kubernetes clusters will hit the limit, and struggle to configure `imagePullSecrets` and `imagePullPolicy`.
2028

21-
Since version `0.6.0`, this proxy can be configured with the env var `ENABLE_MANIFEST_CACHE=true` which provides
29+
This proxy can be configured with the env var `ENABLE_MANIFEST_CACHE=true` which provides
2230
configurable caching of the manifest requests that DockerHub throttles. You can then fine-tune other parameters to your needs.
2331
Together with the possibility to centrally inject authentication (since 0.3x), this is probably one of the best ways to bring relief to your distressed cluster, while at the same time saving lots of bandwidth and time.
2432

@@ -63,8 +71,7 @@ for this to work it requires inserting a root CA certificate into system trusted
6371
## master/:latest is unstable/beta
6472

6573
- `:latest` and `:latest-debug` Docker tag is unstable, built from master, and amd64-only
66-
- Production/stable is `0.6.2`, see [0.6.2 tag on Github](https://github.com/rpardini/docker-registry-proxy/tree/0.6.2) - this image is multi-arch amd64/arm64
67-
- The previous version is `0.5.0`, without any manifest caching, see [0.5.0 tag on Github](https://github.com/rpardini/docker-registry-proxy/tree/0.5.0) - this image is multi-arch amd64/arm64
74+
- Production/stable is `0.6.5`, see [0.6.5 tag on Github](https://github.com/rpardini/docker-registry-proxy/tree/0.6.5) - this image is multi-arch amd64/arm64
6875

6976
## Also hosted on GitHub Container Registry (ghcr.io)
7077

@@ -86,22 +93,20 @@ for this to work it requires inserting a root CA certificate into system trusted
8693
- Env `AUTH_REGISTRIES`: space separated list of `hostname:username:password` authentication info.
8794
- `hostname`s listed here should be listed in the REGISTRIES environment as well, so they can be intercepted.
8895
- Env `AUTH_REGISTRIES_DELIMITER` to change the separator between authentication info. By default, a space: "` `". If you use keys that contain spaces (as with Google Cloud Registry), you should update this variable, e.g. setting it to `AUTH_REGISTRIES_DELIMITER=";;;"`. In that case, `AUTH_REGISTRIES` could contain something like `registry1.com:user1:pass1;;;registry2.com:user2:pass2`.
89-
- Env `AUTH_REGISTRY_DELIMITER` to change the separator between authentication info *parts*. By default, a colon: "`:`". If you use keys that contain single colons, you should update this variable, e.g. setting it to `AUTH_REGISTRIES_DELIMITER=":::"`. In that case, `AUTH_REGISTRIES` could contain something like `registry1.com:::user1:::pass1 registry2.com:::user2:::pass2`.
90-
- Env `PROXY_REQUEST_BUFFERING`: If push is allowed, buffering requests can cause issues on slow upstreams.
91-
If you have trouble pushing, set this to `false` first, then fix remainig timeouts.
92-
Default is `true` to not change default behavior.
93-
ENV PROXY_REQUEST_BUFFERING="true"
96+
- Env `AUTH_REGISTRY_DELIMITER` to change the separator between authentication info *parts*. By default, a colon: "`:`". If you use keys that contain single colons, you should update this variable, e.g. setting it to `AUTH_REGISTRY_DELIMITER=":::"`. In that case, `AUTH_REGISTRIES` could contain something like `registry1.com:::user1:::pass1 registry2.com:::user2:::pass2`.
97+
- Env `PROXY_REQUEST_BUFFERING`: If push is allowed, buffering requests can cause issues on slow upstreams. If you have trouble pushing, set this to `false` first, then fix remaining timeouts. Default is `true` to not change default behavior.
9498
- Timeouts ENVS - all of them can pe specified to control different timeouts, and if not set, the defaults will be the ones from `Dockerfile`. The directives will be added into `http` block.:
9599
- SEND_TIMEOUT : see [send_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#send_timeout)
96100
- CLIENT_BODY_TIMEOUT : see [client_body_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout)
97101
- CLIENT_HEADER_TIMEOUT : see [client_header_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout)
98-
- KEEPALIVE_TIMEOUT : see [keepalive_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout
102+
- KEEPALIVE_TIMEOUT : see [keepalive_timeout](http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout)
99103
- PROXY_READ_TIMEOUT : see [proxy_read_timeout](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout)
100104
- PROXY_CONNECT_TIMEOUT : see [proxy_connect_timeout](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_connect_timeout)
101105
- PROXY_SEND_TIMEOUT : see [proxy_send_timeout](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_send_timeout)
102106
- PROXY_CONNECT_READ_TIMEOUT : see [proxy_connect_read_timeout](https://github.com/chobits/ngx_http_proxy_connect_module#proxy_connect_read_timeout)
103107
- PROXY_CONNECT_CONNECT_TIMEOUT : see [proxy_connect_connect_timeout](https://github.com/chobits/ngx_http_proxy_connect_module#proxy_connect_connect_timeout)
104-
- PROXY_CONNECT_SEND_TIMEOUT : see [proxy_connect_send_timeout](https://github.com/chobits/ngx_http_proxy_connect_module#proxy_connect_send_timeout))
108+
- PROXY_CONNECT_SEND_TIMEOUT : see [proxy_connect_send_timeout](https://github.com/chobits/ngx_http_proxy_connect_module#proxy_connect_send_timeout)
109+
- Env `DISABLE_IPV6`: If set to `true`, prevents nginx from getting IPv6 addresses from the resolver, without needing a [custom resolver config](#custom_nginx_resolvers_configuration)
105110

106111

107112
### Simple (no auth, all cache)
@@ -110,7 +115,7 @@ docker run --rm --name docker_registry_proxy -it \
110115
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
111116
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
112117
-v $(pwd)/docker_mirror_certs:/ca \
113-
rpardini/docker-registry-proxy:0.6.2
118+
rpardini/docker-registry-proxy:0.6.5
114119
```
115120

116121
### DockerHub auth
@@ -124,9 +129,9 @@ docker run --rm --name docker_registry_proxy -it \
124129
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
125130
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
126131
-v $(pwd)/docker_mirror_certs:/ca \
127-
-e REGISTRIES="k8s.gcr.io gcr.io quay.io your.own.registry another.public.registry" \
132+
-e REGISTRIES="registry.k8s.io gcr.io quay.io your.own.registry another.public.registry" \
128133
-e AUTH_REGISTRIES="auth.docker.io:dockerhub_username:dockerhub_password your.own.registry:username:password" \
129-
rpardini/docker-registry-proxy:0.6.2
134+
rpardini/docker-registry-proxy:0.6.5
130135
```
131136

132137
### Simple registries auth (HTTP Basic auth)
@@ -154,7 +159,7 @@ docker run --rm --name docker_registry_proxy -it \
154159
-v $(pwd)/docker_mirror_certs:/ca \
155160
-e REGISTRIES="reg.example.com git.example.com" \
156161
-e AUTH_REGISTRIES="git.example.com:USER:PASSWORD" \
157-
rpardini/docker-registry-proxy:0.6.2
162+
rpardini/docker-registry-proxy:0.6.5
158163
```
159164

160165
### Google Container Registry (GCR) auth
@@ -173,11 +178,36 @@ docker run --rm --name docker_registry_proxy -it \
173178
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
174179
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
175180
-v $(pwd)/docker_mirror_certs:/ca \
176-
-e REGISTRIES="k8s.gcr.io gcr.io quay.io your.own.registry another.public.registry" \
181+
-e REGISTRIES="registry.k8s.io gcr.io quay.io your.own.registry another.public.registry" \
177182
-e AUTH_REGISTRIES_DELIMITER=";;;" \
178183
-e AUTH_REGISTRY_DELIMITER=":::" \
179184
-e AUTH_REGISTRIES="gcr.io:::_json_key:::$(cat servicekey.json);;;auth.docker.io:::dockerhub_username:::dockerhub_password" \
180-
rpardini/docker-registry-proxy:0.6.2
185+
rpardini/docker-registry-proxy:0.6.5
186+
```
187+
188+
### Google Artifact Registry (GAR) auth
189+
190+
For Google Artifact Registry (GAR), username should be `_json_key` and the password should be the contents of the service account JSON.
191+
Check out [GAR docs](https://cloud.google.com/artifact-registry/docs/docker/authentication#json-key).
192+
193+
The service account key is in JSON format, it contains spaces ("` `") and colons ("`:`").
194+
195+
To be able to use GAR you should set `AUTH_REGISTRIES_DELIMITER` to something different than space (e.g. `AUTH_REGISTRIES_DELIMITER=";;;"`) and `AUTH_REGISTRY_DELIMITER` to something different than a single colon (e.g. `AUTH_REGISTRY_DELIMITER=":::"`).
196+
197+
GAR repositories have different domain names depending on the region in which they are hosted. Separate `REGISTRIES` and `AUTH_REGISTRIES` entries must be defined for each region's domain name. `us-east1-docker.pkg.dev` and `us-central1-docker.pkg.dev` are used in the example below.
198+
199+
Example with GAR using credentials from a service account from a key file `servicekey.json`:
200+
201+
```bash
202+
docker run --rm --name docker_registry_proxy -it \
203+
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
204+
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
205+
-v $(pwd)/docker_mirror_certs:/ca \
206+
-e REGISTRIES="us-east1-docker.pkg.dev us-central1-docker.pkg.dev" \
207+
-e AUTH_REGISTRIES_DELIMITER=";;;" \
208+
-e AUTH_REGISTRY_DELIMITER=":::" \
209+
-e AUTH_REGISTRIES="us-east1-docker.pkg.dev:::_json_key:::$(cat servicekey.json);;;us-central1-docker.pkg.dev:::_json_key:::$(cat servicekey.json);;;auth.docker.io:::dockerhub_username:::dockerhub_password" \
210+
rpardini/docker-registry-proxy:0.6.5
181211
```
182212

183213
### Kind Cluster
@@ -194,7 +224,7 @@ docker run --rm --name docker_registry_proxy -it \
194224
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
195225
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
196226
-v $(pwd)/docker_mirror_certs:/ca \
197-
rpardini/docker-registry-proxy:0.6.2
227+
rpardini/docker-registry-proxy:0.6.5
198228
```
199229

200230
Now deploy your Kind cluster and then automatically configure the nodes with the following script :
@@ -223,7 +253,7 @@ wait $pids # Wait for all configurations to end
223253
docker run -d --name registry-proxy --restart=always \
224254
-v /tmp/registry-proxy/mirror_cache:/docker_mirror_cache \
225255
-v /tmp/registry-proxy/certs:/ca \
226-
rpardini/docker-registry-proxy:0.6.4
256+
rpardini/docker-registry-proxy:0.6.5
227257

228258
export PROXY_HOST=registry-proxy
229259
export PROXY_PORT=3128
@@ -310,7 +340,7 @@ systemctl restart docker.service
310340

311341
Clear `dockerd` of everything not currently running: `docker system prune -a -f` *beware*
312342

313-
Then do, for example, `docker pull k8s.gcr.io/kube-proxy-amd64:v1.10.4` and watch the logs on the caching proxy, it should list a lot of MISSes.
343+
Then do, for example, `docker pull registry.k8s.io/kube-proxy-amd64:v1.10.4` and watch the logs on the caching proxy, it should list a lot of MISSes.
314344

315345
Then, clean again, and pull again. You should see HITs! Success.
316346

@@ -329,7 +359,7 @@ docker run --rm --name docker_registry_proxy -it
329359
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
330360
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
331361
-v $(pwd)/docker_mirror_certs:/ca \
332-
rpardini/docker-registry-proxy:0.6.2-debug
362+
rpardini/docker-registry-proxy:0.6.5-debug
333363
```
334364

335365
- `DEBUG=true` enables the mitmweb proxy between Docker clients and the caching layer, accessible on port 8081
@@ -348,7 +378,7 @@ docker run --rm --name docker_registry_proxy -it
348378
### Why not use Docker's own registry, which has a mirror feature?
349379

350380
Yes, Docker offers [Registry as a pull through cache](https://docs.docker.com/registry/recipes/mirror/), *unfortunately*
351-
it only covers the DockerHub case. It won't cache images from `quay.io`, `k8s.gcr.io`, `gcr.io`, or any such, including any private registries.
381+
it only covers the DockerHub case. It won't cache images from `quay.io`, `registry.k8s.io`, `gcr.io`, or any such, including any private registries.
352382

353383
That means that your shiny new Kubernetes cluster is now a bandwidth hog, since every image will be pulled from the
354384
Internet on every Node it runs on, with no reuse.

docs/compose/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: '3.7'
22

33
services:
44
docker_registry_proxy:
5-
image: rpardini/docker-registry-proxy:0.6.1 # Check and make sure this is the last released version
5+
image: rpardini/docker-registry-proxy:0.6.5 # Check and make sure this is the last released version
66
env_file: # This contains REGISTRIES and AUTH_REGISTRIES
77
- ./secrets.env
88
environment:

docs/compose/secrets.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# DockerHub authentication
2-
REGISTRIES="k8s.gcr.io gcr.io quay.io" # There is no need to specify auth.docker.io, it's built-in
2+
REGISTRIES="registry.k8s.io gcr.io quay.io" # There is no need to specify auth.docker.io, it's built-in
33
AUTH_REGISTRIES="auth.docker.io:your_dockerhub_username:your_dockerhub_password"

docs/kops/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ docker run --rm --name docker_registry_proxy -it \
99
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
1010
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
1111
-v $(pwd)/docker_mirror_certs:/ca \
12-
rpardini/docker-registry-proxy:0.6.0
12+
rpardini/docker-registry-proxy:0.6.5
1313
```
1414

1515
or you can run it from another cluster, maybe a management/observability one with provided yaml, in this case, you will need to change the following lines:

docs/kops/docker-registry-proxy.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ spec:
1919
serviceAccountName: default
2020
containers:
2121
- name: docker-registry-proxy
22-
image: ghcr.io/rpardini/docker-registry-proxy:0.6.1
22+
image: ghcr.io/rpardini/docker-registry-proxy:0.6.5
2323
imagePullPolicy: IfNotPresent
2424
env:
2525
- name: ENABLE_MANIFEST_CACHE
2626
value: "true"
2727
- name: REGISTRIES
28-
value: "k8s.gcr.io gcr.io quay.io us.gcr.io"
28+
value: "registry.k8s.io gcr.io quay.io us.gcr.io"
2929
ports:
3030
- name: http
3131
containerPort: 3128

entrypoint.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ confpath=/etc/nginx/resolvers.conf
3333
if [ ! -e $confpath ] || [ "$conf" != "$(cat $confpath)" ]
3434
then
3535
echo "Using auto-determined resolver '$conf' via '$confpath'"
36+
if [[ "a${DISABLE_IPV6}" == "atrue" ]]; then
37+
echo "Disabling IPv6 in '$confpath'"
38+
conf="${conf%;*} ipv6=off;"
39+
fi
3640
echo "$conf" > $confpath
3741
else
3842
echo "Not using resolver config, keep existing '$confpath' -- mounted by user?"
@@ -395,6 +399,10 @@ fi
395399
# Set worker processes if provided
396400
sed -i "s/worker_processes auto;/worker_processes ${WORKER_PROCESSES};/g" /etc/nginx/nginx.conf
397401

402+
echo -e "\nFinal resolver configuration: ---"
403+
cat "${confpath}"
404+
echo -e "---\n"
405+
398406
echo "Testing nginx config..."
399407
${NGINX_BIN} -t
400408

nginx.conf

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ events {
1111
}
1212

1313
http {
14-
proxy_buffer_size 128k;
1514
proxy_busy_buffers_size 256k;
16-
proxy_buffers 4 256k;
1715
map_hash_bucket_size 128;
1816
include /etc/nginx/mime.types;
1917
default_type application/octet-stream;
@@ -24,6 +22,10 @@ http {
2422
# Include nginx timeout configs
2523
include /etc/nginx/nginx.timeouts.config.conf;
2624

25+
# Support Google Artifact Registry big headers
26+
proxy_buffer_size 128k;
27+
proxy_buffers 4 256k;
28+
2729
# Use a debug-oriented logging format.
2830
log_format debugging escape=json
2931
'{'
@@ -183,7 +185,7 @@ Environment="HTTPS_PROXY=$scheme://$http_host/"
183185
EOD
184186

185187
# Get the CA certificate from the proxy and make it a trusted root.
186-
curl $scheme://$http_host/ca.crt > /usr/share/ca-certificates/docker_registry_proxy.crt
188+
curl -sS $scheme://$http_host/ca.crt > /usr/share/ca-certificates/docker_registry_proxy.crt
187189
if fgrep -q "docker_registry_proxy.crt" /etc/ca-certificates.conf ; then
188190
echo "certificate refreshed"
189191
else

0 commit comments

Comments
 (0)