前几天写了个使用registry的pullthrough功能,解决了无法拉取dockerhub的问题, 但是最近又碰到了其他问题, 那就是在拉取镜像的时候, yaml文件中的镜像不一定都是dockerhub中的, 而且, 用registry还有单独解决https的问题, 如果只解决dockerhub还好, 但是镜像仓库多了就很麻烦, 因此想到了cloudflare的worker, 果然能完美解决这个问题!!!
参考
ciiiii/cloudflare-docker-proxy: A docker registry proxy run on cloudflare worker. (github.com)
使用方法-无敌简单版
直接进入参考的github网页, 在仓库中直接点击这个按钮即可
然后会跳出来github的认证, 再填写上cloudflare的token即可
使用方法-手动版
因为需要创建token, 然后不太熟悉cloudflare的token, 但是如果给个全局token, 又感觉太危险, 索性手撸了, 不用他那个自动化了, 他那个自动化, 就是把worker自动部署一下, 本质上来说就是自动了而已
托管网站
准备1个自己的域名, 在cloudflare的网站这里点击添加站点, 根据提示, 到域名的服务商那里将dns服务器改成提示中的
说明: 域名服务商,就是你在哪里申请的域名, 哪里就是你的域名服务商, 一般你申请了域名之后, 会有1个管理后台的, 管理后台中, 就有域名的dns服务器, 你改成提示中的cloudflare的就好, 一般需要数小时才能识别到, 等cloudflare识别了之后, 这里的站点下面, 就会出现活跃2个字, 就可以进行下一步了
创建worker
登录到cloudflare的界面, 然后点击Workers页面, 如下, 不熟悉英文的人, 可以选择右上角, 选择中文就是了
创建1个worker, 名字的话, 就写cloudflare-docker-proxy就可以了, 因为这个名字被worker中的代码里面引用了, 因此就直接写这个名字吧
编辑代码
注意修改其中的routes中的域名地址为自己的, 也就是下面的yyy.com替换为自己的域名, 建议直接全局替换即可, 记住这里的域名分别是
1 2 3 4 5 6 7
| docker.yyy.xyz对应dockerHub也就是docker.io quay.yyy.xyz对应https://quay.io gcr.yyy.xyz对应https://gcr.io k8s-gcr.yyy.xyz对应https://k8s.gcr.io registry-k8s.yyy.xyz对应https://registry.k8s.io ghcr.yyy.xyz对应https://ghcr.io docker-cloudsmith.yyy.xyz对应https://docker.cloudsmith.io
|
worker的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
| addEventListener("fetch", (event) => { event.passThroughOnException(); event.respondWith(handleRequest(event.request)); });
const MODE = "production"; const TARGET_UPSTREAM = "";
const dockerHub = "https://registry-1.docker.io";
const routes = { "docker.yyy.xyz": dockerHub, "quay.yyy.xyz": "https://quay.io", "gcr.yyy.xyz": "https://gcr.io", "k8s-gcr.yyy.xyz": "https://k8s.gcr.io", "registry-k8s.yyy.xyz": "https://registry.k8s.io", "ghcr.yyy.xyz": "https://ghcr.io", "docker-cloudsmith.yyy.xyz": "https://docker.cloudsmith.io",
};
function routeByHosts(host) { if (host in routes) { return routes[host]; } if (MODE == "debug") { return TARGET_UPSTREAM; } return ""; }
async function handleRequest(request) { const url = new URL(request.url); const upstream = routeByHosts(url.hostname); if (upstream === "") { return new Response( JSON.stringify({ routes: routes, }), { status: 404, } ); } const isDockerHub = upstream == dockerHub; const authorization = request.headers.get("Authorization"); if (url.pathname == "/v2/") { const newUrl = new URL(upstream + "/v2/"); const headers = new Headers(); if (authorization) { headers.set("Authorization", authorization); } const resp = await fetch(newUrl.toString(), { method: "GET", headers: headers, redirect: "follow", }); if (resp.status === 401) { if (MODE == "debug") { headers.set( "Www-Authenticate", `Bearer realm="http://${url.host}/v2/auth",service="cloudflare-docker-proxy"` ); } else { headers.set( "Www-Authenticate", `Bearer realm="https://${url.hostname}/v2/auth",service="cloudflare-docker-proxy"` ); } return new Response(JSON.stringify({ message: "UNAUTHORIZED" }), { status: 401, headers: headers, }); } else { return resp; } } if (url.pathname == "/v2/auth") { const newUrl = new URL(upstream + "/v2/"); const resp = await fetch(newUrl.toString(), { method: "GET", redirect: "follow", }); if (resp.status !== 401) { return resp; } const authenticateStr = resp.headers.get("WWW-Authenticate"); if (authenticateStr === null) { return resp; } const wwwAuthenticate = parseAuthenticate(authenticateStr); let scope = url.searchParams.get("scope"); if (scope && isDockerHub) { let scopeParts = scope.split(":"); if (scopeParts.length == 3 && !scopeParts[1].includes("/")) { scopeParts[1] = "library/" + scopeParts[1]; scope = scopeParts.join(":"); } } return await fetchToken(wwwAuthenticate, scope, authorization); } if (isDockerHub) { const pathParts = url.pathname.split("/"); if (pathParts.length == 5) { pathParts.splice(2, 0, "library"); const redirectUrl = new URL(url); redirectUrl.pathname = pathParts.join("/"); return Response.redirect(redirectUrl, 301); } } const newUrl = new URL(upstream + url.pathname); const newReq = new Request(newUrl, { method: request.method, headers: request.headers, redirect: "follow", }); return await fetch(newReq); }
function parseAuthenticate(authenticateStr) { const re = /(?<=\=")(?:\\.|[^"\\])*(?=")/g; const matches = authenticateStr.match(re); if (matches == null || matches.length < 2) { throw new Error(`invalid Www-Authenticate Header: ${authenticateStr}`); } return { realm: matches[0], service: matches[1], }; }
async function fetchToken(wwwAuthenticate, scope, authorization) { const url = new URL(wwwAuthenticate.realm); if (wwwAuthenticate.service.length) { url.searchParams.set("service", wwwAuthenticate.service); } if (scope) { url.searchParams.set("scope", scope); } headers = new Headers(); if (authorization) { headers.set("Authorization", authorization); } return await fetch(url, { method: "GET", headers: headers }); }
|
替换为自己的域名后, 直接部署即可
自定义域名
在worker的页面点击刚才新建好的cloudflare-docker-proxy, 在设置的触发器, 这里添加自定义域, 然后人别填写你自己域名的子域名即可, 就是上面替换后的域名,
1 2 3 4 5 6
| docker.yyy.xyz quay.yyy.xyz gcr.yyy.xyz k8s-gcr.yyy.xyz ghcr.yyy.xyz docker-cloudsmith.yyy.xyz
|
创建后如下
创建后, 就会出现6个自定义域
验证
登录dockerhub验证
使用docker login docker.yyy.com可以看到是能正常代理到dockers.io, 当然了, 账号密码用你在dockerhub的账号密码
1
| docker login docker.yyy.com -u 23523523 -p 232523525
|
可以看到, 能够登录成功, 也就是说明正常代理到了dockerhub了
拉取dockerhub镜像验证
拉取busybox的镜像
1
| docker pull docker.yyy.com/library/busybox:latest
|
可以看到能够正常拉取
拉取quay镜像验证
拉取镜像如下
1
| docker pull quay.yyy.com/brancz/kube-rbac-proxy:v0.14.2
|
可以看到能正常拉取
可以看到均通过cloudflare正常代理了