利用GitHub配置镜像加速,解决 Docker镜像拉取问题 起因docker pull nginx卡了两分钟结果甩一句font stylecolor:#c00;TLS handshake timeout/font连换三四个国内加速器不是 404 就是 unauthorized。不用买代理、不用租境外服务器一个 GitHub 仓库加一段 Actions让海外机器帮你拉好、打包下载回本地docker load直接用。最终成品就是这个公开仓库README 写明它是Docker 镜像同步中转站一、场景现在拉镜像到底卡在哪国内直连 Docker HubDocker 官方镜像仓库的链路本身不稳定过去大家习惯在/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 ActionsGitHub 内置的持续集成服务的运行器runner部署在海外机房默认就能正常访问 Docker Hub。工作流里的docker pull走的是 GitHub 机房到 Docker Hub 的网络和你本机的网络环境无关。整条链路的数据流向是这样的你的本机(国内) GitHub 运行器(海外) Docker Hub | | | | ① 触发工作流 | | | ---------------------- | | | | ② docker pull | | | ---------------------- | | | 镜像层 | | | | | | ③ save | gzip 打包 | | ④ 下载产物(zip) | | | ---------------------- | | | | | | ⑤ unzip docker load |三、一个 workflow 文件搞定你可以直接用我建好的仓库https://github.com/ruigeda/Dockerbuild 也可以在自己的公开仓库里新建文件.github/workflows/save-image.yml内容如下name:image_nameon:workflow_dispatch:inputs:image_name:description:镜像全名例如 postgres:16 或 redis:7-alpinerequired:trueplatform:description:目标架构default:linux/amd64jobs:pull_and_save:runs-on:ubuntu-lateststeps:-name:Login to Docker Hub (突破匿名限速)uses:docker/login-actionv3with:username:${{secrets.DOCKERHUB_USERNAME}}password:${{secrets.DOCKERHUB_TOKEN}}continue-on-error:true# 如果没配密钥也不中断-name:Pull Save Compressrun:|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 artifactuses:actions/upload-artifactv4with:name:docker-imagepath:*.tar.gzretention-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解压、加载、确认unzipdocker-image.zipdockerload-i*.tar.gzdockerimages终端返回如下结果说明镜像已经原样进了本地镜像库Archive: docker-image.zip inflating: nginx.tar.gz Loaded image: nginx:latestdocker images 能看到 nginx:latest镜像 100% 可用全程没碰本机的 Docker Hub 连接镜像加载回来再顺手起个容器确认能跑dockerrun-d--nameweb-p8080:80 nginx浏览器访问http://本机IP:8080看到 nginx 欢迎页整条链路才算彻底闭环。五、总结延伸这套方案的本质是把拉镜像这件网络受困的事外包给海外的 GitHub 运行器再用产物artifact把结果运回本地拉取环境海外运行器直连 Docker Hub无需代理分发形式docker save gzip 压缩产物以 artifact 下载复用方式手动触发 参数化换镜像只改一个输入框几百 MB 的常规镜像走这条路又快又稳多 GB 的超大镜像受上传下载耗时影响建议优先考虑专用镜像仓库。术语速查表术语含义Docker HubDocker 官方公共镜像仓库Registry镜像仓库存储和分发容器镜像的服务GitHub ActionsGitHub 提供的持续集成 / 自动化服务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_dispatchdocker/login-action 仓库https://github.com/docker/login-actionactions/upload-artifact 仓库https://github.com/actions/upload-artifactdocker save 官方文档https://docs.docker.com/reference/cli/docker/image/save/