From d04604484ff1fa6df24b017dd8b9e33f4d863e1d Mon Sep 17 00:00:00 2001 From: snowdream Date: Tue, 1 Apr 2025 15:45:14 +0800 Subject: [PATCH 1/7] feat: help html --- src/help.html | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/index.js | 11 ++++ 2 files changed, 151 insertions(+) create mode 100644 src/help.html diff --git a/src/help.html b/src/help.html new file mode 100644 index 000000000..9ea568c58 --- /dev/null +++ b/src/help.html @@ -0,0 +1,140 @@ + + + + + + 镜像使用说明 + + + + +
+

镜像使用说明

+ + GitHub + +
+
+
+

为了加速 Docker 镜像拉取,你可以使用以下命令设置 registry mirror:

+
sudo tee /etc/docker/daemon.json <<EOF
+{
+    "registry-mirrors": ["https://{{host}}"]
+}
+EOF
+# 配置完后需要重启 Docker 服务
+sudo systemctl restart docker
+
+

使用该代理从不同的镜像仓库拉取镜像,请参考以下命令:

+

+# docker pull nginx:latest
+docker pull docker.{{host}}/library/nginx:latest  # 拉取 Docker 官方镜像
+
+# docker pull quay.io/coreos/etcd:latest
+docker pull quay.{{host}}/coreos/etcd:latest  # 拉取 Quay 镜像
+
+# docker pull gcr.io/google-containers/busybox:latest
+docker pull gcr.{{host}}/google-containers/busybox:latest  # 拉取 GCR 镜像
+
+# docker pull k8s.gcr.io/pause:latest
+docker pull k8s-gcr.{{host}}/pause:latest  # 拉取 k8s.gcr.io 镜像
+
+# docker pull registry.k8s.io/pause:latest
+docker pull k8s.{{host}}/pause:latest  # 拉取 registry.k8s.io 镜像
+
+# docker pull ghcr.io/github/super-linter:latest
+docker pull ghcr.{{host}}/github/super-linter:latest  # 拉取 GitHub 容器镜像
+
+# docker pull docker.cloudsmith.io/public/repo/image:latest
+docker pull cloudsmith.{{host}}/public/repo/image:latest  # 拉取 Cloudsmith 镜像
+
+

为了避免 Worker 用量耗尽,你可以手动 pull 镜像然后 re-tag 之后 push 至本地镜像仓库。

+
+
+ + + + \ No newline at end of file diff --git a/src/index.js b/src/index.js index a97a73819..3a859d18d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,5 @@ +import DOCS from './help.html' + addEventListener("fetch", (event) => { event.passThroughOnException(); event.respondWith(handleRequest(event.request)); @@ -42,6 +44,15 @@ async function handleRequest(request) { status: 404, } ); + } + // return docs + if (url.pathname === "/") { + return new Response(DOCS, { + status: 200, + headers: { + "content-type": "text/html" + } + }); } const isDockerHub = upstream == dockerHub; const authorization = request.headers.get("Authorization"); From f581502e109692ecb3ab99f935038e85b7e69513 Mon Sep 17 00:00:00 2001 From: snowdream Date: Tue, 1 Apr 2025 15:45:15 +0800 Subject: [PATCH 2/7] feat: Enable Workers Logs --- wrangler.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wrangler.toml b/wrangler.toml index bbf4845d2..1705112e3 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -1,6 +1,10 @@ name = "cloudflare-docker-proxy" compatibility_date = "2023-12-01" +[observability] +enabled = true +head_sampling_rate = 1 # optional. default = 1. + [dev] ip = "0.0.0.0" port = 8787 From cfa4776751518a483ee9b2db1f5859ddc6c04123 Mon Sep 17 00:00:00 2001 From: snowdream Date: Tue, 1 Apr 2025 15:45:15 +0800 Subject: [PATCH 3/7] feat: support search --- src/index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 3a859d18d..4d8550f61 100644 --- a/src/index.js +++ b/src/index.js @@ -5,11 +5,12 @@ addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request)); }); -const dockerHub = "https://registry-1.docker.io"; +const registry_dockerHub = "https://registry-1.docker.io"; +const index_dockerHub = "https://index.docker.io"; const routes = { // production - ["docker." + CUSTOM_DOMAIN]: dockerHub, + ["docker." + CUSTOM_DOMAIN]: registry_dockerHub, ["quay." + CUSTOM_DOMAIN]: "https://quay.io", ["gcr." + CUSTOM_DOMAIN]: "https://gcr.io", ["k8s-gcr." + CUSTOM_DOMAIN]: "https://k8s.gcr.io", @@ -19,7 +20,7 @@ const routes = { ["ecr." + CUSTOM_DOMAIN]: "https://public.ecr.aws", // staging - ["docker-staging." + CUSTOM_DOMAIN]: dockerHub, + ["docker-staging." + CUSTOM_DOMAIN]: registry_dockerHub, }; function routeByHosts(host) { @@ -54,7 +55,7 @@ async function handleRequest(request) { } }); } - const isDockerHub = upstream == dockerHub; + const isDockerHub = upstream == registry_dockerHub; const authorization = request.headers.get("Authorization"); if (url.pathname == "/v2/") { const newUrl = new URL(upstream + "/v2/"); From 591a8f42611313638a285a69d42ff57f9975909b Mon Sep 17 00:00:00 2001 From: snowdream Date: Tue, 1 Apr 2025 15:45:15 +0800 Subject: [PATCH 4/7] feat: add CUSTOM_DOMAIN for dev --- wrangler.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/wrangler.toml b/wrangler.toml index 1705112e3..694ba7ecf 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -14,6 +14,7 @@ local_protocol = "http" CUSTOM_DOMAIN = "libcuda.so" [env.dev.vars] +CUSTOM_DOMAIN = "router.com" MODE = "debug" TARGET_UPSTREAM = "https://registry-1.docker.io" CUSTOM_DOMAIN = "exmaple.com" From e2542d0014158b25ece9b8c5894bb91b29ef09f2 Mon Sep 17 00:00:00 2001 From: snowdream Date: Tue, 1 Apr 2025 15:45:16 +0800 Subject: [PATCH 5/7] feat: support search in dockerhub --- src/index.js | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index 4d8550f61..f094367a8 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import DOCS from './help.html' +import DOCS from "./help.html"; addEventListener("fetch", (event) => { event.passThroughOnException(); @@ -45,18 +45,41 @@ async function handleRequest(request) { status: 404, } ); - } + } // return docs if (url.pathname === "/") { return new Response(DOCS, { status: 200, headers: { - "content-type": "text/html" - } + "content-type": "text/html", + }, }); } const isDockerHub = upstream == registry_dockerHub; const authorization = request.headers.get("Authorization"); + + if (url.pathname == "/v1/search" && isDockerHub) { + const newUrl = new URL(index_dockerHub + "/v1/search"); + newUrl.search = url.search; + + const headers = new Headers(); + if (authorization) { + headers.set("Authorization", authorization); + } + + // check if need to authenticate + const resp = await fetch(newUrl.toString(), { + method: "GET", + headers: headers, + redirect: "follow", + }); + + if (resp.status === 401) { + return responseUnauthorized(url); + } + return resp; + } + if (url.pathname == "/v2/") { const newUrl = new URL(upstream + "/v2/"); const headers = new Headers(); @@ -166,7 +189,7 @@ async function fetchToken(wwwAuthenticate, scope, authorization) { } function responseUnauthorized(url) { - const headers = new(Headers); + const headers = new Headers(); if (MODE == "debug") { headers.set( "Www-Authenticate", From 6464d0ac0651d1ee8e95ee5767a9646bda1c8421 Mon Sep 17 00:00:00 2001 From: snowdream Date: Tue, 1 Apr 2025 15:45:16 +0800 Subject: [PATCH 6/7] feat: support search in quay --- src/index.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index f094367a8..2ea0b0b23 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,8 @@ addEventListener("fetch", (event) => { const registry_dockerHub = "https://registry-1.docker.io"; const index_dockerHub = "https://index.docker.io"; +const registry_quay = "https://quay.io"; +const index_quay = "https://quay.io"; const routes = { // production @@ -56,10 +58,20 @@ async function handleRequest(request) { }); } const isDockerHub = upstream == registry_dockerHub; + const isQuay = upstream == registry_quay; const authorization = request.headers.get("Authorization"); - if (url.pathname == "/v1/search" && isDockerHub) { - const newUrl = new URL(index_dockerHub + "/v1/search"); + if (url.pathname == "/v1/search") { + let newUrl = url + + if(isDockerHub){ + newUrl = new URL(index_dockerHub + "/v1/search"); + }else if(isQuay){ + newUrl = new URL(index_quay + "/v1/search"); + }else{ + newUrl = url + } + newUrl.search = url.search; const headers = new Headers(); From 4ca664358e04665cc30f0444d5d329ced6da922a Mon Sep 17 00:00:00 2001 From: snowdream Date: Tue, 1 Apr 2025 15:45:16 +0800 Subject: [PATCH 7/7] feat: Docker API /v1/_ping --- src/index.js | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index 2ea0b0b23..e03bec47d 100644 --- a/src/index.js +++ b/src/index.js @@ -61,18 +61,32 @@ async function handleRequest(request) { const isQuay = upstream == registry_quay; const authorization = request.headers.get("Authorization"); - if (url.pathname == "/v1/search") { + if (url.pathname.startsWith("/v1/")) { let newUrl = url - if(isDockerHub){ - newUrl = new URL(index_dockerHub + "/v1/search"); - }else if(isQuay){ - newUrl = new URL(index_quay + "/v1/search"); - }else{ - newUrl = url + // Docker API /v1/_ping + // https://docs.docker.com/reference/api/engine/version/v1.47/#tag/System/operation/SystemPing + if (url.pathname == "/v1/_ping") { + return new Response(null, { + status: 200, + headers: { + "content-type": "text/plain", + }, + }); } - newUrl.search = url.search; + // Docker API /v1/search + if (url.pathname == "/v1/search") { + if(isDockerHub){ + newUrl = new URL(index_dockerHub + "/v1/search"); + }else if(isQuay){ + newUrl = new URL(index_quay + "/v1/search"); + }else{ + newUrl = url + } + + newUrl.search = url.search; + } const headers = new Headers(); if (authorization) { @@ -136,10 +150,12 @@ async function handleRequest(request) { } return await fetchToken(wwwAuthenticate, scope, authorization); } + console.log(JSON.stringify(url, null, 2)) // redirect for DockerHub library images // Example: /v2/busybox/manifests/latest => /v2/library/busybox/manifests/latest if (isDockerHub) { const pathParts = url.pathname.split("/"); + console.log(JSON.stringify(url, null, 2)) if (pathParts.length == 5) { pathParts.splice(2, 0, "library"); const redirectUrl = new URL(url);