之前寫過一篇關(guān)于在NAS中部署游戲的攻略,后臺(tái)有粉絲反映他的docker鏡像不能拉取。

本期文章通過Cloudflare Workers搭建一個(gè)免費(fèi)的Docker鏡像加速。跟著本文步驟操作,小白也可以部署成功。

搭建準(zhǔn)備:一個(gè)域名+一個(gè)Cloudflare賬戶。Cloudflare賬戶注冊(cè)很簡(jiǎn)單,搜索Cloudflare即可注冊(cè),本文的域名是在騰訊云購(gòu)買(域名需要付費(fèi))。

文章目錄

一、域名注冊(cè)

二、域名托管至Cloudflare

三、在Cloudflare部署服務(wù)

四、Container 部署

一、域名注冊(cè)

登錄騰訊云進(jìn)行注冊(cè)。

【保姆級(jí)攻略】Docker 鏡像提取失?。恳晃妮p松搞定

根據(jù)自己的預(yù)算和需求選擇想要的域名,點(diǎn)擊添加購(gòu)物車,然后進(jìn)行購(gòu)買。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

購(gòu)買之前需要進(jìn)行實(shí)名認(rèn)證,官方給的消息是1~N個(gè)工作日,我大概三十分鐘實(shí)名認(rèn)證成功,認(rèn)證成功后,接著去購(gòu)買自己想要的域名。

【保姆級(jí)攻略】Docker 鏡像提取失?。恳晃妮p松搞定

購(gòu)買成功后,這里還需要對(duì)域名進(jìn)行審核,同業(yè)也是說需要N個(gè)工作日后能審核成功,差不多一個(gè)小時(shí)后就審核通過,服務(wù)狀態(tài)這里就顯示正常。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

登錄騰訊云DNSPOD

地址:https://www.dnspod.cn/login?login_jump=yes&s_url=https://console.dnspod.cn/dns/list&sync_code=1

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

登錄后,點(diǎn)擊頭像,接著點(diǎn)擊API密鑰。

【保姆級(jí)攻略】Docker 鏡像提取失?。恳晃妮p松搞定

 

然后新建API密鑰。注意:API密鑰是構(gòu)建騰訊云APIA請(qǐng)求的重要憑證,不要外泄,要妥善保存。

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

創(chuàng)建Token:新建完密鑰后,轉(zhuǎn)到DNSPod Token

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

輸入密鑰名稱,方便管理。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

創(chuàng)建完密鑰后,后跳出以下彈窗,DNSPod 不會(huì)存儲(chǔ)原始密鑰,將以上的信息只出現(xiàn)一次,可以保存在筆記本中。

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

 

二、域名托管至Cloudflare

登入Cloudflare 后,點(diǎn)擊添加站點(diǎn)。

【保姆級(jí)攻略】Docker 鏡像提取失?。恳晃妮p松搞定

輸入上面在騰訊云申請(qǐng)的域名。

【保姆級(jí)攻略】Docker 鏡像提取失?。恳晃妮p松搞定

接著往下拉選擇免費(fèi)的。

【保姆級(jí)攻略】Docker 鏡像提取失?。恳晃妮p松搞定

接著下來可以看到Cloudflare 分配的兩個(gè)服務(wù)器名稱,需要返回到騰訊云,添加分配的這兩個(gè) Cloudflare 名稱服務(wù)器,刪除任何其他名稱服務(wù)器,然后保存更改。

 

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

返回到騰訊云,修改DNS服務(wù)器。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

點(diǎn)擊自定義DNS,將上面分配的兩個(gè) Cloudflare 名稱服務(wù)器復(fù)制到這里。

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

回到Cloudflare ,左上角顯示已激活,右下方的基本功能進(jìn)行啟用。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

 

三、在Cloudflare部署服務(wù)

進(jìn)入Cloudflare主頁(yè)面,按照下圖依次點(diǎn)擊Workers和Pages→創(chuàng)建Workers。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

登錄前需要進(jìn)行郵箱驗(yàn)證。

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

下圖位置輸入docker,然后進(jìn)行部署。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

部署完成后,點(diǎn)擊編輯代碼。

 

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

代碼如下

'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 (!/%2F/.test(url.search) && /%3A/.test(url.toString())) { let modifiedUrl = url.toString().replace(/%3A(?=.*?&)/, '%3Alibrary%2F'); url = new URL(modifiedUrl); } 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); } if (/^/v2/[^/]+/[^/]+/[^/]+$/.test(url.pathname) && !/^/v2/library/.test(url.pathname)) { url.pathname = url.pathname.replace(//v2//, '/v2/library/'); } 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 = await original_response_clone.text(); 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; if (req.method === 'OPTIONS' && reqHdrRaw.has('access-control-request-headers')) { return new Response(null, PREFLIGHT_INIT); } let rawLen = ''; const reqHdrNew = new Headers(reqHdrRaw); 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 }); }

粘貼完代碼點(diǎn)擊部署。

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

返回上一菜單,找到設(shè)置→觸發(fā)器→添加定義域。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

 

筆者這里輸入docker+申請(qǐng)的域名。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

接著等待域名證書發(fā)放,幾分鐘就可以成功,在等待期間去點(diǎn)擊右上角【編輯代碼】。

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

把如下位置,填上自己的域名,按照下圖格式填寫。

【保姆級(jí)攻略】Docker 鏡像提取失敗?一文輕松搞定

部署完就結(jié)束了。

四、Container 部署

回到威聯(lián)通NAS進(jìn)入 Container Station,進(jìn)入存儲(chǔ)庫(kù)→添加。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

按照下圖填寫,測(cè)試連接不要忘記點(diǎn)。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

接著在【映像】中點(diǎn)擊提取,同樣按照下圖操作,最后提取。

【保姆級(jí)攻略】Docker 鏡像提取失?。恳晃妮p松搞定

這樣就部署成功了,接下來進(jìn)行測(cè)試,提取之前一個(gè)游戲的映像名稱。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

可以成功提取。

【保姆級(jí)攻略】Docker 鏡像提取失???一文輕松搞定

希望本期文章對(duì)你有所幫助,感興趣的朋友可以點(diǎn)贊收藏關(guān)注,咱們下期見!

,

聲明:本站所有文章,如無特殊說明或標(biāo)注,均為本站原創(chuàng)發(fā)布。任何個(gè)人或組織,在未征得本站同意時(shí),禁止復(fù)制、盜用、采集、發(fā)布本站內(nèi)容到任何網(wǎng)站、書籍等各類媒體平臺(tái)。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。