~ 4 min
docker代理问题
最近自己的docker总是抽风出现各种各样的问题,因为事情过于忙碌来不及处理,一些安装的项目秉持能用则用的心态便拖到如今。昨天升级自己的docker项目出现镜像错误问题,自己的镜像都是到处去网上找的,刚开始能用就没换掉,在google了一堆解决方法之后均无果,于是虚心请教杜老师,杜老师很爽快的给出了他的一篇教程,其实我看过这篇教程,但是因为自己下意识的觉得代理这一块对于我比较陌生,所以就没在意,今天按照教程做了之后立马成功,实在感谢杜老师。因为自己在操作的过程中还是有些微不同,所以还是选择复盘一下,这样也才能加深自己的印象,真正选择实操可以选择去看杜老师的这篇借助 CF 解决 Docker 镜像拉取问题。
首先需要自己注册一个域名,其实我最开始拥有好几个域名,但是自己管理问题导致只剩下一个重要域名,注册新域名的时候竟然发现自己wangyunzi.xyz
域名处于待售状态,说实话我都不知道这个域名是在哪一个平台上购买的了,我只记得好久没用了,应该没什么大问题,这次为了谨慎起见也是为了方便管理和续费,选择统一在阿里云上注册一个域名,希望大家都能统一注册管理自己的域名吧。
将域名的DNS改成cloudfare,因为我的主域名也是在cloudfare,这样比较方便管理。点击进入新注册的域名,接着点击左侧的workers路由
,继续点击管理workers
,最后创建。
创建后修改名称之后直接点击部署,之后复制需要的代码进去覆盖掉,然后记得修改第三行的域名成为自己最开始注册的域名。
let hub_host = 'registry-1.docker.io'
const auth_url = 'https://auth.docker.io'
let workers_url = 'https://docker.birdteam.net'
let UA = ['netcraft'];
function routeByHosts(host) {
const routes = {
"quay": "quay.io",
"gcr": "gcr.io",
"k8s-gcr": "k8s.gcr.io",
"k8s": "registry.k8s.io",
"ghcr": "ghcr.io",
"cloudsmith": "docker.cloudsmith.io",
"test": "registry-1.docker.io",
};
if (host in routes) return [ routes[host], false ];
else return [ hub_host, true ];
}
const PREFLIGHT_INIT = {
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
}
}
function isUUID(uuid) {
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;
return uuidRegex.test(uuid);
}
async function nginx() {
const text = `
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
`
return text ;
}
export default {
async fetch(request, env, ctx) {
const getReqHeader = (key) => request.headers.get(key);
let url = new URL(request.url);
const userAgentHeader = request.headers.get('User-Agent');
const userAgent = userAgentHeader ? userAgentHeader.toLowerCase() : "null";
if (env.UA) UA = UA.concat(await ADD(env.UA));
workers_url = `https://${url.hostname}`;
const pathname = url.pathname;
const hostname = url.searchParams.get('hubhost') || url.hostname;
const hostTop = hostname.split('.')[0];
const checkHost = routeByHosts(hostTop);
hub_host = checkHost[0];
const fakePage = checkHost[1];
console.log(`域名头部: ${hostTop}\n反代地址: ${hub_host}\n伪装首页: ${fakePage}`);
const isUuid = isUUID(pathname.split('/')[1].split('/')[0]);
if (UA.some(fxxk => userAgent.includes(fxxk)) && UA.length > 0){
return new Response(await nginx(), {
headers: {
'Content-Type': 'text/html; charset=UTF-8',
},
});
}
const conditions = [
isUuid,
pathname.includes('/_'),
pathname.includes('/r'),
pathname.includes('/v2/user'),
pathname.includes('/v2/orgs'),
pathname.includes('/v2/_catalog'),
pathname.includes('/v2/categories'),
pathname.includes('/v2/feature-flags'),
pathname.includes('search'),
pathname.includes('source'),
pathname === '/',
pathname === '/favicon.ico',
pathname === '/auth/profile',
];
if (conditions.some(condition => condition) && (fakePage === true || hostTop == 'docker')) {
if (env.URL302){
return Response.redirect(env.URL302, 302);
} else if (env.URL){
if (env.URL.toLowerCase() == 'nginx'){
return new Response(await nginx(), {
headers: {
'Content-Type': 'text/html; charset=UTF-8',
},
});
} else return fetch(new Request(env.URL, request));
}
const newUrl = new URL("https://registry.hub.docker.com" + pathname + url.search);
const headers = new Headers(request.headers);
headers.set('Host', 'registry.hub.docker.com');
const newRequest = new Request(newUrl, {
method: request.method,
headers: headers,
body: request.method !== 'GET' && request.method !== 'HEAD' ? await request.blob() : null,
redirect: 'follow'
});
return fetch(newRequest);
}
if (!/%2F/.test(url.search) && /%3A/.test(url.toString())) {
let modifiedUrl = url.toString().replace(/%3A(?=.*?&)/, '%3Alibrary%2F');
url = new URL(modifiedUrl);
console.log(`handle_url: ${url}`)
}
if (url.pathname.includes('/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, request), token_parameter)
}
if (/^\/v2\/[^/]+\/[^/]+\/[^/]+$/.test(url.pathname) && !/^\/v2\/library/.test(url.pathname)) {
url.pathname = url.pathname.replace(/\/v2\//, '/v2/library/');
console.log(`modified_url: ${url.pathname}`)
}
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 (request.headers.has("Authorization")) {
parameter.headers.Authorization = getReqHeader("Authorization");
}
let original_response = await fetch(new Request(url, 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(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
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)
const reqInit = {
method: req.method,
headers: reqHdrNew,
redirect: 'follow',
body: req.body
}
return proxy(urlObj, reqInit, rawLen)
}
async function proxy(urlObj, reqInit, rawLen) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)
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
})
}
async function ADD(envadd) {
var addtext = envadd.replace(/[ |"'\r\n]+/g, ',').replace(/,+/g, ',');
//console.log(addtext);
if (addtext.charAt(0) == ',') addtext = addtext.slice(1);
if (addtext.charAt(addtext.length -1) == ',') addtext = addtext.slice(0, addtext.length - 1);
const add = addtext.split(',');
//console.log(add);
return add ;
}
最后按照杜老师评论区首评的做法就是如下图所示:
将自己的镜像添加到docker中,打开根目录/etc/docker/daemon.json
文件,修改成下面:
{
"registry-mirrors": [
"https://wangyunzi.ren"
]
}
至此,docker pull圆满成功,再次感谢杜老师的教程!