经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Docker » 查看文章
使用Cloudflare Worker加速docker镜像
来源:cnblogs  作者:程序设计实验室  时间:2024/7/19 10:37:45  对本文有异议

前言

开发者越来越难了??,现在国内的docker镜像也都???了,没有镜像要使用docker??太难了,代理??又很慢

现在就只剩下自建镜像的办法了??

GitHub上有开源项目可以快速搭建自己的镜像库,不过还是有点麻烦,还好Cloudflare暂时还活着?????

本文记录一下使用 Cloudflare Worker 搭建 docker 镜像的方法??

关于 worker

Cloudflare Workers 是 Cloudflare 提供的一个无服务器(serverless)计算平台,允许你在 Cloudflare 的全球边缘网络上运行 JavaScript、Rust、C、C++ 和 COBOL 等编写的代码。它主要用于创建高性能、高可扩展性的网页应用程序和API。??

Cloudflare Workers 非常适合处理各种网络请求,例如 API网关、内容定制和动态渲染等任务,同时还可以用来修改或决定网络请求如何响应。它为开发人员提供了在全球范围内快速部署应用程序和服务的能力。

一些关键特性:

  1. 边缘计算:由于代码直接在 Cloudflare 的边缘节点上执行,可以显著减少数据传输时间,提高响应速度。
  2. 无服务器架构:你不需要管理任何服务器或实例,只需关注代码的编写和部署。Cloudflare 负责代码的运行和扩展。
  3. 按需计费:Cloudflare Workers 的计费模式基于请求次数和执行时间,而不是预先设定的资源分配,这意味着你可以根据实际使用量付费。
  4. 高度集成:它可以与 Cloudflare 的其他服务(如 KV 存储、Durable Objects 等)紧密集成,方便数据存储和状态管理。
  5. 安全性:由于 Workers 运行在隔离的环境中,它们提供了与传统服务器或容器相比更高的安全级别。

创建 worker

打开 Cloudflare 的 Worker and Pages 页面,创建一个 worker

起个直观的名字,比如 docker-proxy 之类的

然后点【部署】按钮

编辑代码

部署完成之后?,点旁边的【编辑代码】按钮

把下面的 JavaScript????? 代码输进去

需要把 workers_url 替换成自己的域名,比如 https://docker.example.com

  1. // Docker镜像仓库主机地址
  2. let hub_host = 'registry-1.docker.io'
  3. // Docker认证服务器地址
  4. const auth_url = 'https://auth.docker.io'
  5. // 自定义的工作服务器地址
  6. let workers_url = 'https://你的域名'
  7. let 屏蔽爬虫UA = ['netcraft'];
  8. // 根据主机名选择对应的上游地址
  9. function routeByHosts(host) {
  10. // 定义路由表
  11. const routes = {
  12. // 生产环境
  13. "quay": "quay.io",
  14. "gcr": "gcr.io",
  15. "k8s-gcr": "k8s.gcr.io",
  16. "k8s": "registry.k8s.io",
  17. "ghcr": "ghcr.io",
  18. "cloudsmith": "docker.cloudsmith.io",
  19. // 测试环境
  20. "test": "registry-1.docker.io",
  21. };
  22. if (host in routes) return [ routes[host], false ];
  23. else return [ hub_host, true ];
  24. }
  25. /** @type {RequestInit} */
  26. const PREFLIGHT_INIT = {
  27. // 预检请求配置
  28. headers: new Headers({
  29. 'access-control-allow-origin': '*', // 允许所有来源
  30. 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS', // 允许的HTTP方法
  31. 'access-control-max-age': '1728000', // 预检请求的缓存时间
  32. }),
  33. }
  34. /**
  35. * 构造响应
  36. * @param {any} body 响应体
  37. * @param {number} status 响应状态码
  38. * @param {Object<string, string>} headers 响应头
  39. */
  40. function makeRes(body, status = 200, headers = {}) {
  41. headers['access-control-allow-origin'] = '*' // 允许所有来源
  42. return new Response(body, { status, headers }) // 返回新构造的响应
  43. }
  44. /**
  45. * 构造新的URL对象
  46. * @param {string} urlStr URL字符串
  47. */
  48. function newUrl(urlStr) {
  49. try {
  50. return new URL(urlStr) // 尝试构造新的URL对象
  51. } catch (err) {
  52. return null // 构造失败返回null
  53. }
  54. }
  55. function isUUID(uuid) {
  56. // 定义一个正则表达式来匹配 UUID 格式
  57. const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
  58. // 使用正则表达式测试 UUID 字符串
  59. return uuidRegex.test(uuid);
  60. }
  61. async function nginx() {
  62. const text = `
  63. <!DOCTYPE html>
  64. <html>
  65. <head>
  66. <title>Welcome to nginx!</title>
  67. <style>
  68. body {
  69. width: 35em;
  70. margin: 0 auto;
  71. font-family: Tahoma, Verdana, Arial, sans-serif;
  72. }
  73. </style>
  74. </head>
  75. <body>
  76. <h1>Welcome to nginx!</h1>
  77. <p>If you see this page, the nginx web server is successfully installed and
  78. working. Further configuration is required.</p>
  79. <p>For online documentation and support please refer to
  80. <a href="http://nginx.org/">nginx.org</a>.<br/>
  81. Commercial support is available at
  82. <a href="http://nginx.com/">nginx.com</a>.</p>
  83. <p><em>Thank you for using nginx.</em></p>
  84. </body>
  85. </html>
  86. `
  87. return text ;
  88. }
  89. export default {
  90. async fetch(request, env, ctx) {
  91. const getReqHeader = (key) => request.headers.get(key); // 获取请求头
  92. let url = new URL(request.url); // 解析请求URL
  93. const userAgentHeader = request.headers.get('User-Agent');
  94. const userAgent = userAgentHeader ? userAgentHeader.toLowerCase() : "null";
  95. if (env.UA) 屏蔽爬虫UA = 屏蔽爬虫UA.concat(await ADD(env.UA));
  96. workers_url = `https://${url.hostname}`;
  97. const pathname = url.pathname;
  98. const hostname = url.searchParams.get('hubhost') || url.hostname;
  99. const hostTop = hostname.split('.')[0];// 获取主机名的第一部分
  100. const checkHost = routeByHosts(hostTop);
  101. hub_host = checkHost[0]; // 获取上游地址
  102. const fakePage = checkHost[1];
  103. console.log(`域名头部: ${hostTop}\n反代地址: ${hub_host}\n伪装首页: ${fakePage}`);
  104. const isUuid = isUUID(pathname.split('/')[1].split('/')[0]);
  105. if (屏蔽爬虫UA.some(fxxk => userAgent.includes(fxxk)) && 屏蔽爬虫UA.length > 0){
  106. //首页改成一个nginx伪装页
  107. return new Response(await nginx(), {
  108. headers: {
  109. 'Content-Type': 'text/html; charset=UTF-8',
  110. },
  111. });
  112. }
  113. const conditions = [
  114. isUuid,
  115. pathname.includes('/_'),
  116. pathname.includes('/r'),
  117. pathname.includes('/v2/user'),
  118. pathname.includes('/v2/orgs'),
  119. pathname.includes('/v2/_catalog'),
  120. pathname.includes('/v2/categories'),
  121. pathname.includes('/v2/feature-flags'),
  122. pathname.includes('search'),
  123. pathname.includes('source'),
  124. pathname === '/',
  125. pathname === '/favicon.ico',
  126. pathname === '/auth/profile',
  127. ];
  128. if (conditions.some(condition => condition) && (fakePage === true || hostTop == 'docker')) {
  129. if (env.URL302){
  130. return Response.redirect(env.URL302, 302);
  131. } else if (env.URL){
  132. if (env.URL.toLowerCase() == 'nginx'){
  133. //首页改成一个nginx伪装页
  134. return new Response(await nginx(), {
  135. headers: {
  136. 'Content-Type': 'text/html; charset=UTF-8',
  137. },
  138. });
  139. } else return fetch(new Request(env.URL, request));
  140. }
  141. const newUrl = new URL("https://registry.hub.docker.com" + pathname + url.search);
  142. // 复制原始请求的标头
  143. const headers = new Headers(request.headers);
  144. // 确保 Host 头部被替换为 hub.docker.com
  145. headers.set('Host', 'registry.hub.docker.com');
  146. const newRequest = new Request(newUrl, {
  147. method: request.method,
  148. headers: headers,
  149. body: request.method !== 'GET' && request.method !== 'HEAD' ? await request.blob() : null,
  150. redirect: 'follow'
  151. });
  152. return fetch(newRequest);
  153. }
  154. // 修改包含 %2F 和 %3A 的请求
  155. if (!/%2F/.test(url.search) && /%3A/.test(url.toString())) {
  156. let modifiedUrl = url.toString().replace(/%3A(?=.*?&)/, '%3Alibrary%2F');
  157. url = new URL(modifiedUrl);
  158. console.log(`handle_url: ${url}`)
  159. }
  160. // 处理token请求
  161. if (url.pathname.includes('/token')) {
  162. let token_parameter = {
  163. headers: {
  164. 'Host': 'auth.docker.io',
  165. 'User-Agent': getReqHeader("User-Agent"),
  166. 'Accept': getReqHeader("Accept"),
  167. 'Accept-Language': getReqHeader("Accept-Language"),
  168. 'Accept-Encoding': getReqHeader("Accept-Encoding"),
  169. 'Connection': 'keep-alive',
  170. 'Cache-Control': 'max-age=0'
  171. }
  172. };
  173. let token_url = auth_url + url.pathname + url.search
  174. return fetch(new Request(token_url, request), token_parameter)
  175. }
  176. // 修改 /v2/ 请求路径
  177. if (/^\/v2\/[^/]+\/[^/]+\/[^/]+$/.test(url.pathname) && !/^\/v2\/library/.test(url.pathname)) {
  178. url.pathname = url.pathname.replace(/\/v2\//, '/v2/library/');
  179. console.log(`modified_url: ${url.pathname}`)
  180. }
  181. // 更改请求的主机名
  182. url.hostname = hub_host;
  183. // 构造请求参数
  184. let parameter = {
  185. headers: {
  186. 'Host': hub_host,
  187. 'User-Agent': getReqHeader("User-Agent"),
  188. 'Accept': getReqHeader("Accept"),
  189. 'Accept-Language': getReqHeader("Accept-Language"),
  190. 'Accept-Encoding': getReqHeader("Accept-Encoding"),
  191. 'Connection': 'keep-alive',
  192. 'Cache-Control': 'max-age=0'
  193. },
  194. cacheTtl: 3600 // 缓存时间
  195. };
  196. // 添加Authorization头
  197. if (request.headers.has("Authorization")) {
  198. parameter.headers.Authorization = getReqHeader("Authorization");
  199. }
  200. // 发起请求并处理响应
  201. let original_response = await fetch(new Request(url, request), parameter)
  202. let original_response_clone = original_response.clone();
  203. let original_text = original_response_clone.body;
  204. let response_headers = original_response.headers;
  205. let new_response_headers = new Headers(response_headers);
  206. let status = original_response.status;
  207. // 修改 Www-Authenticate 头
  208. if (new_response_headers.get("Www-Authenticate")) {
  209. let auth = new_response_headers.get("Www-Authenticate");
  210. let re = new RegExp(auth_url, 'g');
  211. new_response_headers.set("Www-Authenticate", response_headers.get("Www-Authenticate").replace(re, workers_url));
  212. }
  213. // 处理重定向
  214. if (new_response_headers.get("Location")) {
  215. return httpHandler(request, new_response_headers.get("Location"))
  216. }
  217. // 返回修改后的响应
  218. let response = new Response(original_text, {
  219. status,
  220. headers: new_response_headers
  221. })
  222. return response;
  223. }
  224. };
  225. /**
  226. * 处理HTTP请求
  227. * @param {Request} req 请求对象
  228. * @param {string} pathname 请求路径
  229. */
  230. function httpHandler(req, pathname) {
  231. const reqHdrRaw = req.headers
  232. // 处理预检请求
  233. if (req.method === 'OPTIONS' &&
  234. reqHdrRaw.has('access-control-request-headers')
  235. ) {
  236. return new Response(null, PREFLIGHT_INIT)
  237. }
  238. let rawLen = ''
  239. const reqHdrNew = new Headers(reqHdrRaw)
  240. const refer = reqHdrNew.get('referer')
  241. let urlStr = pathname
  242. const urlObj = newUrl(urlStr)
  243. /** @type {RequestInit} */
  244. const reqInit = {
  245. method: req.method,
  246. headers: reqHdrNew,
  247. redirect: 'follow',
  248. body: req.body
  249. }
  250. return proxy(urlObj, reqInit, rawLen)
  251. }
  252. /**
  253. * 代理请求
  254. * @param {URL} urlObj URL对象
  255. * @param {RequestInit} reqInit 请求初始化对象
  256. * @param {string} rawLen 原始长度
  257. */
  258. async function proxy(urlObj, reqInit, rawLen) {
  259. const res = await fetch(urlObj.href, reqInit)
  260. const resHdrOld = res.headers
  261. const resHdrNew = new Headers(resHdrOld)
  262. // 验证长度
  263. if (rawLen) {
  264. const newLen = resHdrOld.get('content-length') || ''
  265. const badLen = (rawLen !== newLen)
  266. if (badLen) {
  267. return makeRes(res.body, 400, {
  268. '--error': `bad len: ${newLen}, except: ${rawLen}`,
  269. 'access-control-expose-headers': '--error',
  270. })
  271. }
  272. }
  273. const status = res.status
  274. resHdrNew.set('access-control-expose-headers', '*')
  275. resHdrNew.set('access-control-allow-origin', '*')
  276. resHdrNew.set('Cache-Control', 'max-age=1500')
  277. // 删除不必要的头
  278. resHdrNew.delete('content-security-policy')
  279. resHdrNew.delete('content-security-policy-report-only')
  280. resHdrNew.delete('clear-site-data')
  281. return new Response(res.body, {
  282. status,
  283. headers: resHdrNew
  284. })
  285. }
  286. async function ADD(envadd) {
  287. var addtext = envadd.replace(/[ |"'\r\n]+/g, ',').replace(/,+/g, ','); // 将空格、双引号、单引号和换行符替换为逗号
  288. //console.log(addtext);
  289. if (addtext.charAt(0) == ',') addtext = addtext.slice(1);
  290. if (addtext.charAt(addtext.length -1) == ',') addtext = addtext.slice(0, addtext.length - 1);
  291. const add = addtext.split(',');
  292. //console.log(add);
  293. return add ;
  294. }

OK??,代码输入之后,重新点击【部署】,部署成功就可以打开 docker??hub 页面了

设置域名

刚才不是在代码里配置了域名吗?

接下来还得继续配置一下

返回【Workers 和 Pages / docker-proxy】配置页面

点【设置】-【触发器】??

在【自定义域】里点添加,输入域名,例如?? docker.example.com

搞定??,cloudflare 会自动申请 SSL 证书什么的??

配置registry

修改 /etc/docker/daemon.json 文件

  1. {
  2. "registry-mirrors": ["https://docker.example.com"],
  3. "insecure-registries": ["docker.example.com"]
  4. }

重新启动 docker

  1. sudo systemctl daemon-reload
  2. sudo systemctl restart docker

接下来再 pull image 速度就快到起飞??了??

参考资料

原文链接:https://www.cnblogs.com/deali/p/18310886

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号