-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Open
Description
项目一段时间没维护,现在无法部署成功了。
不用想着怎么解决部署问题了,源码就是一个单文件,逻辑都很简单,我按照最新的 Workers 规范改了一下,直接使用即可。
新建一个 Workers,选 Hello World 项目,创建完成后点右上角的按钮进入编辑代码,填入以下代码:
const customDomain = '<换成你自己的域名>'
const dockerHub = 'https://registry-1.docker.io'
const routes = {
// ↓ 这一行是我加的,用不到可以去掉
[customDomain]: dockerHub,
['docker.' + customDomain]: dockerHub,
['quay.' + customDomain]: 'https://quay.io',
['gcr.' + customDomain]: 'https://gcr.io',
['k8s-gcr.' + customDomain]: 'https://k8s.gcr.io',
['k8s.' + customDomain]: 'https://registry.k8s.io',
['ghcr.' + customDomain]: 'https://ghcr.io',
['cloudsmith.' + customDomain]: 'https://docker.cloudsmith.io',
['ecr.' + customDomain]: 'https://public.ecr.aws',
['docker-staging.' + customDomain]: dockerHub,
}
export default {
async fetch(request) {
const url = new URL(request.url)
if (url.pathname == '/') {
return Response.redirect(url.protocol + '//' + url.host + '/v2/', 301)
}
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) {
return responseUnauthorized(url)
}
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')
// autocomplete repo part into scope for DockerHub library images
// Example: repository:busybox:pull => repository:library/busybox:pull
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)
}
// redirect for DockerHub library images
// Example: /v2/busybox/manifests/latest => /v2/library/busybox/manifests/latest
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)
}
}
// foward requests
const newUrl = new URL(upstream + url.pathname)
const newReq = new Request(newUrl, {
method: request.method,
headers: request.headers,
// don't follow redirect to dockerhub blob upstream
redirect: isDockerHub ? 'manual' : 'follow',
})
const resp = await fetch(newReq)
if (resp.status == 401) {
return responseUnauthorized(url)
}
// handle dockerhub blob redirect manually
if (isDockerHub && resp.status == 307) {
const location = new URL(resp.headers.get('Location'))
const redirectResp = await fetch(location.toString(), {
method: 'GET',
redirect: 'follow',
})
return redirectResp
}
return resp
},
}
function routeByHosts(host) {
if (host in routes) {
return routes[host]
}
return ''
}
function parseAuthenticate(authenticateStr) {
// sample: Bearer realm="https://auth.ipv6.docker.com/token",service="registry.docker.io"
// match strings after =" and before "
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)
}
const headers = new Headers()
if (authorization) {
headers.set('Authorization', authorization)
}
return await fetch(url, { method: 'GET', headers: headers })
}
function responseUnauthorized(url) {
const headers = new Headers()
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,
})
}
记得把代码第一行的变量替换成自己的域名,然后点击 “部署” 即可。
注意 Cloudflare 送的 *.workers.dev
在国内被 DNS 污染了,直接用是不行的,必须得绑定自己的域名。
想要测试是否部署成功,也很简单,在自己的电脑上运行:
docker pull <你自己的域名>/alpine
# 例如
docker pull example.com/alpine
试试镜像能不能拉下来就行,这里的域名不要带 https
前缀。
Gonglja, daydayup2005, tkkkkking, Nguyendream, CodingZx and 2 morexljya
Metadata
Metadata
Assignees
Labels
No labels