利用Cloudflare workers拉取dockerhub镜像

关于cloudflare workers

在 Cloudflare Workers 部署一个 Worker 时,它会在30秒之内部署到 Cloudflare 的整个边缘网络,全世界95个国家/200个城市节点。域中的每个请求都会由离用户更近地点的 Worker 来处理,基于此来实现代码的 “随处运行”。

借助 Cloudflare Workers,开发人员能够在 Cloudflare 的全球云网络上部署无服务器的 JavaScript 应用程序,应用程序能够在这个网络中无缝扩展,更加接近最终用户。Workers 基于 Service Workers API 构建,可为向应用程序发出的每次 HTTP(S) 请求接收事件。然后,Workers 运行应用程序逻辑,并可向 Cloudflare Cache、Cloudflare Workers KV 或应用程序原始服务器发出后续请求,以将数据返回给用户。

  • 计费相关

免费版每天有 10 万次免费请求,并且有每分钟1000次请求的限制,每个请求最多占用 10 毫秒 CPU 时间。超过限制后,会返回错误。对于大多数人来说已经足够用了。

  • 网络相关

如果说你访问workers.dev的域名也是非常慢,或者访问不到的时候,可以试试 hosts 绑定, 大几率你能访问到。更多内容请见 官方文档

https://developers.cloudflare.com/workers/

cloudflare中添加自己的域名

  1. 注册cloudflare账号,过程不赘述

https://dash.cloudflare.com/login

  1. 注册一个域名,可以阿里云、华为云、腾讯云等购买,便宜点的8块钱首年

阿里云:https://wanwang.aliyun.com/domain

图片

华为云:https://www.huaweicloud.com/product/domain/search.html

图片

腾讯云:https://buy.cloud.tencent.com/domain

图片

  1. 登录cloudflare,添加站点

https://dash.cloudflare.com

点击右上角添加站点,输入自己需要添加的域名:

图片

图片

选择免费计划:

图片

如果有dns记录可以此时添加,点击继续:

图片

图片

点击继续,会提示需要修改dns服务器,此时需要去域名对应的注册商修改域名dns服务器:

图片

我这里的域名是阿里云的,就去阿里云域名控制台找到修改dns服务器,填入刚刚cf名称服务器提交即可,其他服务商修改方法大同小异,一般十几分钟就可以生效,此时就可以使用cloudflare来管理在别处购买的域名:

图片

图片

图片

图片

此时回到cloudflare,点击继续:

图片

图片

激活了会发邮件:

图片

cloudflare中创建worker

  1. 激活之后,进入Workers 和 Pages,再点击概述,创建works。

图片

图片

图片

验证完进入页面,点击创建worker,输入项目名称,然后在下面会有一行小字:您的 Worker 将被部署到:xxxxx,这个是cf自动分配给你的域名,通过这个就可以访问这个项目,有童鞋就会想那为啥还要自己准备域名,因为很简单,cf分配的那个域名目前打不开,只能绑定自己的域名。输入完名称后点击保存,会出现默认的worker.js,这个不用管,点击完成就行.

图片

图片

点击保存进入预览页面:

图片

点击完成后会出现初始界面,点击编辑代码:

图片

先删掉默认的代码,然后把以下代码复制到里面,并替换workers_url为自己的域名,再点击部署:

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
'use strict'
const hub_host = 'registry-1.docker.io'
const auth_url = 'https://auth.docker.io'
const workers_url = 'https://自己的域名'
const PREFLIGHT_INIT = {
status: 204,
headers: new Headers({
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age': '1728000',
}),
}
function makeRes(body, status = 200, headers = {}) {
headers['access-control-allow-origin'] = '*'
return new Response(body, {status, headers})
}
function newUrl(urlStr) {
try {
return new URL(urlStr)
} catch (err) {
return null
}
}
addEventListener('fetch', e => {
const ret = fetchHandler(e)
.catch(err => makeRes('cfworker error:\n' + err.stack, 502))
e.respondWith(ret)
})
async function fetchHandler(e) {
const getReqHeader = (key) => e.request.headers.get(key);
let url = new URL(e.request.url);
if (url.pathname === '/token') {
let token_parameter = {
headers: {
'Host': 'auth.docker.io',
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
}
};
let token_url = auth_url + url.pathname + url.search
return fetch(new Request(token_url, e.request), token_parameter)
}
url.hostname = hub_host;
let parameter = {
headers: {
'Host': hub_host,
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
},
cacheTtl: 3600
};
if (e.request.headers.has("Authorization")) {
parameter.headers.Authorization = getReqHeader("Authorization");
}
let original_response = await fetch(new Request(url, e.request), parameter)
let original_response_clone = original_response.clone();
let original_text = original_response_clone.body;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;
if (new_response_headers.get("Www-Authenticate")) {
let auth = new_response_headers.get("Www-Authenticate");
let re = new RegExp(auth_url, 'g');
new_response_headers.set("Www-Authenticate", response_headers.get("Www-Authenticate").replace(re, workers_url));
}
if (new_response_headers.get("Location")) {
return httpHandler(e.request, new_response_headers.get("Location"))
}
let response = new Response(original_text, {
status,
headers: new_response_headers
})
return response;
}
function httpHandler(req, pathname) {
const reqHdrRaw = req.headers
// preflight
if (req.method === 'OPTIONS' &&
reqHdrRaw.has('access-control-request-headers')
) {
return new Response(null, PREFLIGHT_INIT)
}
let rawLen = ''
const reqHdrNew = new Headers(reqHdrRaw)
const refer = reqHdrNew.get('referer')
let urlStr = pathname
const urlObj = newUrl(urlStr)
/** @type {RequestInit} */
const reqInit = {
method: req.method,
headers: reqHdrNew,
redirect: 'follow',
body: req.body
}
return proxy(urlObj, reqInit, rawLen, 0)
}
async function proxy(urlObj, reqInit, rawLen) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)
// verify
if (rawLen) {
const newLen = resHdrOld.get('content-length') || ''
const badLen = (rawLen !== newLen)
if (badLen) {
return makeRes(res.body, 400, {
'--error': `bad len: ${newLen}, except: ${rawLen}`,
'access-control-expose-headers': '--error',
})
}
}
const status = res.status
resHdrNew.set('access-control-expose-headers', '*')
resHdrNew.set('access-control-allow-origin', '*')
resHdrNew.set('Cache-Control', 'max-age=1500')
resHdrNew.delete('content-security-policy')
resHdrNew.delete('content-security-policy-report-only')
resHdrNew.delete('clear-site-data')
return new Response(res.body, {
status,
headers: resHdrNew
})
}

图片

cloudflare中绑定自己的域名并配置路由

cf workers默认使用的是自动分配的域名,这个目前国内很难访问到,所以还需要绑定自己的域名。

  1. 进入项目详细-设置里面,选择触发器,点击添加路由。路由就填写对应的子(主)域名,例如主域名是“testmirror.com”,想要通过“dockerhub.testmirror.com”拉取镜像,那路由就填写“dockerhub.testmirror.com/*”,当然这里想直接用主域名也可以,没限制;区域就选择对应的主域名,然后添加路由。

图片

图片

点击添加路由即可看到自己添加的路由:

图片

图片

  1. 之后进入dns解析,添加一个对应的二级域名的解析,例如上面是用“dockerhub.testmirror.com”,那这里就添加一个对应的ipv4解析记录;解析地址随便填写,填8.8.8.8就可以,然后旁边的代理状态一定要启用。

图片

图片

验证并拉取镜像

如果以上步骤都无误,就可以直接拉取docker镜像,但是需要对相应的拉取命令做更改。

  1. 服务器上拉取

例如原拉取命令如下:

1
docker pull library/nginx:1.20.2

那就需要在前面加上自己的域名:

1
docker pull 自己的域名/library/nginx:1.20.2

当然也可以直接在配置文件中设置registry-mirrors,替换成自己的域名,然后重启下docker服务即可:

1
2
3
{
"registry-mirrors": ["https://自己的域名"]
}