docker pull nginx 卡了两分钟,结果甩给我一句 <font style="color:#c00;">TLS handshake timeout</font>,连换三四个国内加速器,不是 404 就是 unauthorized。
不用买代理、不用租境外服务器,一个 GitHub 仓库加一段 Actions,让海外机器帮你拉好、打包,下载回本地 docker load 直接用。

最终成品就是这个公开仓库,README 写明它是"Docker 镜像同步中转站"
一、场景:现在拉镜像到底卡在哪
国内直连 Docker Hub(Docker 官方镜像仓库)的链路本身不稳定,过去大家习惯在 /etc/docker/daemon.json 里配 registry-mirrors 走加速器,而近一两年大批公开加速器陆续关停。
我这边反复出现的报错可以归成四类:
| 现象 / 报错 | 直接原因 |
|---|---|
TLS handshake timeout、i/o timeout |
直连 Docker Hub 握手超时 |
加速器返回 404 Not Found |
镜像站域名已关停或停止代理 |
toomanyrequests: too many requests |
匿名拉取触发 Docker Hub 限速 |
拉到一半断在 Pulling fs layer |
长连接被中断,链路不稳 |
加速器地址今天能用、明天挂,每失效一次就得改配置、重启 docker。那有没有一台"身在海外、能连 Docker Hub、还免费"的机器,能替我把镜像拉下来?
二、原理:GitHub Actions 凭什么能当中转站
GitHub Actions(GitHub 内置的持续集成服务)的运行器(runner)部署在海外机房,默认就能正常访问 Docker Hub。工作流里的 docker pull 走的是 GitHub 机房到 Docker Hub 的网络,和你本机的网络环境无关。
整条链路的数据流向是这样的:
latex
你的本机(国内) GitHub 运行器(海外) Docker Hub
| | |
| ① 触发工作流 | |
| ----------------------> | |
| | ② docker pull |
| | ----------------------> |
| | <====== 镜像层 ======== |
| | |
| | ③ save | gzip 打包 |
| ④ 下载产物(zip) | |
| <---------------------- | |
| | |
| ⑤ unzip + docker load |
三、一个 workflow 文件搞定
你可以直接用我建好的仓库:https://github.com/ruigeda/Dockerbuild ;也可以在自己的公开仓库里新建文件 .github/workflows/save-image.yml,内容如下:
yaml
name: image_name
on:
workflow_dispatch:
inputs:
image_name:
description: '镜像全名,例如 postgres:16 或 redis:7-alpine'
required: true
platform:
description: '目标架构'
default: 'linux/amd64'
jobs:
pull_and_save:
runs-on: ubuntu-latest
steps:
- name: Login to Docker Hub (突破匿名限速)
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
continue-on-error: true # 如果没配密钥也不中断
- name: Pull & Save & Compress
run: |
docker pull --platform ${{ github.event.inputs.platform }} ${{ github.event.inputs.image_name }}
# 用镜像名中的 tag 作为文件名,避免特殊字符
SAFE_NAME=$(echo "${{ github.event.inputs.image_name }}" | tr '/:' '_')
# docker save 后立刻 gzip,体积通常能压到 30%~50%
docker save ${{ github.event.inputs.image_name }} | gzip > ${SAFE_NAME}.tar.gz
ls -lh ${SAFE_NAME}.tar.gz
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: docker-image
path: "*.tar.gz"
retention-days: 5 # 只保留5天,省空间
工作流在网页上默认显示的名字,就是文件第一行 name 后面的值。你可以把 image_name 改成自己好认的名字,比如 镜像中转:

name 字段同时决定左侧工作流列表里显示的名称
注意:这一步只改显示名,真正决定拉哪个镜像的是运行时填写的参数,别把两者搞混。
四、实操验证:从触发到本地跑通
步骤 1:进入 Actions 页面
打开仓库顶部的 Actions 标签,左侧选中你的工作流,右侧能看到绿色的 Run workflow 按钮。

步骤 2:填写镜像全名
点 Run workflow,在弹窗里输入要拉的镜像,这里以 nginx 为例;目标架构保持默认 linux/amd64,再点一次绿色 Run workflow 提交。
镜像名要写完整,带 tag 的写法如 postgres:16、redis:7-alpine;**只写 nginx 等价于 **nginx:latest。

步骤 3:等待运行完成
几十秒后,列表里出现一条绿色对勾的运行记录,我这次只用了 26 秒。

没配密钥时,Annotations 里可能出现一条红色 Username and password required,属于登录步骤的提示,因设置了容错不影响结果
步骤 4:下载产物
点进这条记录,拉到页面最底部 Artifacts 区域,能看到名为 docker-image 的压缩包,点击下载。

步骤 5:拿到 zip 包
浏览器下载下来的是 docker-image.zip,我这个包约 60 MB,是 nginx 压缩后的体积。

步骤 6:传到 Linux 并加载
把 zip 传到你的 Linux 机器(或 WSL),解压、加载、确认:
bash
unzip docker-image.zip
docker load -i *.tar.gz
docker images
终端返回如下结果,说明镜像已经原样进了本地镜像库:
latex
Archive: docker-image.zip
inflating: nginx.tar.gz
Loaded image: nginx:latest

docker images 能看到 nginx:latest,镜像 100% 可用,全程没碰本机的 Docker Hub 连接
镜像加载回来,再顺手起个容器确认能跑:
bash
docker run -d --name web -p 8080:80 nginx
浏览器访问 http://本机IP:8080 看到 nginx 欢迎页,整条链路才算彻底闭环。

五、总结延伸
这套方案的本质,是把"拉镜像"这件网络受困的事,外包给海外的 GitHub 运行器,再用产物(artifact)把结果运回本地:
- 拉取环境:海外运行器直连 Docker Hub,无需代理
- 分发形式:
docker save+ gzip 压缩,产物以 artifact 下载 - 复用方式:手动触发 + 参数化,换镜像只改一个输入框
几百 MB 的常规镜像走这条路又快又稳;多 GB 的超大镜像受上传下载耗时影响,建议优先考虑专用镜像仓库。
术语速查表
| 术语 | 含义 |
|---|---|
| Docker Hub | Docker 官方公共镜像仓库 |
| Registry(镜像仓库) | 存储和分发容器镜像的服务 |
| GitHub Actions | GitHub 提供的持续集成 / 自动化服务 |
| workflow(工作流) | 定义自动化任务的 YAML 文件 |
| runner(运行器) | 实际执行工作流的机器 |
| artifact(产物) | 工作流运行后上传、可供下载的文件 |
| platform(架构) | 镜像运行的目标平台,如 linux/amd64 |
参考链接
- GitHub Actions 手动触发 workflow_dispatch 官方文档:https://docs.github.com/zh/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch
- docker/login-action 仓库:https://github.com/docker/login-action
- actions/upload-artifact 仓库:https://github.com/actions/upload-artifact
- docker save 官方文档:https://docs.docker.com/reference/cli/docker/image/save/