Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a67ef6c52c | ||
|
|
0adf11099e | ||
|
|
dbb9432eb0 |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 sky22333
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -35,6 +35,8 @@ docker run -d \
|
|||||||
curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install-service.sh | sudo bash
|
curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install-service.sh | sudo bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
可直接下载二进制文件执行`./hubproxy`使用,无需配置文件即可启动,内置默认配置,支持所有功能。初始内存占用约18M,二进制文件大小约12M
|
||||||
|
|
||||||
这个命令会:
|
这个命令会:
|
||||||
- 🔍 自动检测系统架构(AMD64/ARM64)
|
- 🔍 自动检测系统架构(AMD64/ARM64)
|
||||||
- 📥 从 GitHub Releases 下载最新版本
|
- 📥 从 GitHub Releases 下载最新版本
|
||||||
@@ -52,10 +54,12 @@ curl -fsSL https://raw.githubusercontent.com/sky22333/hubproxy/main/install-serv
|
|||||||
docker pull nginx
|
docker pull nginx
|
||||||
|
|
||||||
# 使用加速
|
# 使用加速
|
||||||
docker pull yourdomain.com/nginx
|
docker pull demo.52013120.xyz/nginx
|
||||||
|
|
||||||
# ghcr加速
|
# ghcr加速
|
||||||
docker pull yourdomain.com/ghcr.io/user/images
|
docker pull demo.52013120.xyz/ghcr.io/sky22333/hubproxy
|
||||||
|
|
||||||
|
# 符合Docker Registry API v2标准的仓库都支持
|
||||||
```
|
```
|
||||||
|
|
||||||
### GitHub 文件加速
|
### GitHub 文件加速
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
services:
|
services:
|
||||||
ghproxy:
|
hubproxy:
|
||||||
build: .
|
build: .
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -211,51 +211,8 @@ func (is *ImageStreamer) getImageDescriptor(ref name.Reference, options []remote
|
|||||||
|
|
||||||
// getImageDescriptorWithPlatform 获取指定平台的镜像描述符
|
// getImageDescriptorWithPlatform 获取指定平台的镜像描述符
|
||||||
func (is *ImageStreamer) getImageDescriptorWithPlatform(ref name.Reference, options []remote.Option, platform string) (*remote.Descriptor, error) {
|
func (is *ImageStreamer) getImageDescriptorWithPlatform(ref name.Reference, options []remote.Option, platform string) (*remote.Descriptor, error) {
|
||||||
if isCacheEnabled() {
|
// 直接从网络获取完整的descriptor,确保对象完整性
|
||||||
var reference string
|
return remote.Get(ref, options...)
|
||||||
if tagged, ok := ref.(name.Tag); ok {
|
|
||||||
reference = tagged.TagStr()
|
|
||||||
} else if digested, ok := ref.(name.Digest); ok {
|
|
||||||
reference = digested.DigestStr()
|
|
||||||
}
|
|
||||||
|
|
||||||
if reference != "" {
|
|
||||||
cacheKey := buildManifestCacheKeyWithPlatform(ref.Context().String(), reference, platform)
|
|
||||||
if cachedItem := globalCache.Get(cacheKey); cachedItem != nil {
|
|
||||||
desc := &remote.Descriptor{
|
|
||||||
Manifest: cachedItem.Data,
|
|
||||||
}
|
|
||||||
log.Printf("使用缓存的manifest: %s (平台: %s)", ref.String(), platform)
|
|
||||||
return desc, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
desc, err := remote.Get(ref, options...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if isCacheEnabled() {
|
|
||||||
var reference string
|
|
||||||
if tagged, ok := ref.(name.Tag); ok {
|
|
||||||
reference = tagged.TagStr()
|
|
||||||
} else if digested, ok := ref.(name.Digest); ok {
|
|
||||||
reference = digested.DigestStr()
|
|
||||||
}
|
|
||||||
|
|
||||||
if reference != "" {
|
|
||||||
cacheKey := buildManifestCacheKeyWithPlatform(ref.Context().String(), reference, platform)
|
|
||||||
ttl := getManifestTTL(reference)
|
|
||||||
headers := map[string]string{
|
|
||||||
"Docker-Content-Digest": desc.Digest.String(),
|
|
||||||
}
|
|
||||||
globalCache.Set(cacheKey, desc.Manifest, string(desc.MediaType), headers, ttl)
|
|
||||||
log.Printf("缓存manifest: %s (平台: %s, TTL: %v)", ref.String(), platform, ttl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StreamImageToGin 流式响应到Gin
|
// StreamImageToGin 流式响应到Gin
|
||||||
@@ -503,7 +460,7 @@ func (is *ImageStreamer) streamSingleImageForBatch(ctx context.Context, tarWrite
|
|||||||
|
|
||||||
switch desc.MediaType {
|
switch desc.MediaType {
|
||||||
case types.OCIImageIndex, types.DockerManifestList:
|
case types.OCIImageIndex, types.DockerManifestList:
|
||||||
// 处理多架构镜像,复用单个下载的逻辑
|
// 处理多架构镜像
|
||||||
img, err := is.selectPlatformImage(desc, options)
|
img, err := is.selectPlatformImage(desc, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("选择平台镜像失败: %w", err)
|
return nil, nil, fmt.Errorf("选择平台镜像失败: %w", err)
|
||||||
@@ -574,6 +531,8 @@ func (is *ImageStreamer) streamSingleImageForBatch(ctx context.Context, tarWrite
|
|||||||
return manifest, repositories, nil
|
return manifest, repositories, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// selectPlatformImage 从多架构镜像中选择合适的平台镜像
|
// selectPlatformImage 从多架构镜像中选择合适的平台镜像
|
||||||
func (is *ImageStreamer) selectPlatformImage(desc *remote.Descriptor, options *StreamOptions) (v1.Image, error) {
|
func (is *ImageStreamer) selectPlatformImage(desc *remote.Descriptor, options *StreamOptions) (v1.Image, error) {
|
||||||
index, err := desc.ImageIndex()
|
index, err := desc.ImageIndex()
|
||||||
|
|||||||
Reference in New Issue
Block a user