ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Docker镜像源配置全解析:原理、实操与故障排查

Docker镜像源配置全解析:原理、实操与故障排查 先交代一下背景我最近连续几天被同一种问题缠上——docker pull 一个普通的 nginx 镜像进度条卡在 waiting 半天不动偶尔直接报 i/o timeout。翻了一圈论坛和博客发现“到底哪有docker镜像源”这句话快成经典提问了回答倒是不少但真正能一次解决问题的没几个。有人在评论区甩一个地址让你填进去结果还是拉不动有人说把默认源换掉就行但你连默认源在哪、为什么换、换了之后发生了什么都不知道。这篇文章就是把“镜像源”这件事彻底拆开讲清楚。不只是甩你几个可用地址而是告诉你这些地址为什么有用、怎么配置、遇到问题怎么查。适合正在被拉取超时折磨的开发者也适合刚接触 docker、对镜像下载机制还一知半解的运维新人。1. 镜像源到底是什么先搞清楚它解决什么问题1.1 一次失败的 docker pull 背后发生了什么在讨论镜像源在哪之前得先明白 docker pull 到底走了哪条路。你在终端输入 docker pull nginxdocker 客户端立即把请求交给本机的 dockerd 守护进程dockerd 解析镜像名 nginx发现你没写仓库地址就自动补全成 docker.io/library/nginx然后向 Docker Hub 发起 HTTPS 请求。也就是说默认情况下你的镜像下载链路是dockerd → Docker Hub。镜像源准确说是镜像加速器英文叫 registry mirror就是在这条链路上插进一个代理节点dockerd → 镜像加速器 → Docker Hub。加速器先把镜像从 Docker Hub 拉到自己服务器上再转交给你。后续别人请求同一个镜像就直接命中加速器的缓存不再回源 Docker Hub。这个机制有很关键的一点registry mirror 只对 Docker Hub 官方仓库生效。你配置了镜像加速器之后docker pull nginx 会走加速器但如果你执行 docker pull quay.io/prometheus/node-exporterdockerd 一看镜像名里带了明确的仓库地址 quay.io就直接连 quay.io 去了你配的加速器完全管不着。很多人配置完发现某些镜像还是拉不动多半就是栽在这个细节上。1.2 镜像加速器的工作机制与局限性加速器本质上是一个缓存代理不是新的镜像仓库。它帮你做的是“内容中转”而不是“内容托管”。这意味着几个事情它只加速拉取不加速推送。你 docker push 自己的镜像到 Docker Hub加速器帮不上忙推送还是走 Docker Hub 的原始地址。它只加速公开镜像。Docker Hub 上的私有仓库镜像加速器没有你的认证信息照样拉不到。它不解决 DNS 解析问题。如果你的机器连加速器域名本身都解析不了配置再多也没用。它缓存的是 Docker Hub 官方镜像仓库的内容。如果你的镜像名里带了自己的私有仓库地址加速器只能放弃处理。很多人在这一步犯糊涂以为换了镜像源就能解决所有拉取问题。实际情况是镜像源只能缓解 Docker Hub 直连不稳的问题对于其他仓库、私有仓库、推送场景该配什么还得配什么。2. 镜像源去哪儿找按场景分类别再被无效教程坑2.1 公共镜像加速器大厂基础设施优先公共镜像加速器是个人开发者最先接触到的镜像源。国内几个大型云厂商都提供过免费的 Docker 镜像加速服务从公开资料里可以整理出下面这些地址配置前建议先实测本文只基于公开信息整理具体可用性以最新公告为准来源加速器地址说明某云厂商容器镜像服务https://xxxx.mirror.aliyuncs.com登录容器镜像服务控制台后在镜像加速器页面能看到专属地址每个人不一样某云厂商容器服务https://mirror.ccs.tencentyun.com腾讯云容器服务的公共加速器地址某互联网公司开源镜像http://hub-mirror.c.163.com网易的公共镜像加速器http 协议部分环境需要注意某云厂商公共镜像https://mirror.baidubce.com百度智能云提供的容器镜像加速器某社区容器加速服务https://docker.mirrors.daocloud.ioDaoCloud 提供的公共加速器这类大厂加速器的好处是基础设施扎实带宽充足不会像个人维护的第三方源一样突然消失。但有个问题需要注意部分云厂商加速器地址是账号绑定的比如那个 xxxx.mirror.aliyuncs.com你需要登录控制台获取自己的专属地址拿别人的地址填进去大概率是访问不了的。配置公共加速器时建议一次配 2 到 3 个。docker 会按顺序尝试如果第一个源返回失败它会自动切换下一个这比只配一个源稳妥得多。注意不要迷信某一份帖子列出的“永久有效地址”。镜像加速器本质是商业基础设施或社区公益服务地址变动、策略调整都属于正常现象。配置完一定要实测隔几个月再复查一次。2.2 开源镜像站与软件安装源别混淆两类资源很多人搜索“docker 镜像源”时会搜出一堆称“镜像站”的地址。这里有个容易混淆的坑国外很多开源软件镜像站提供的是 docker-ce 的安装包镜像而不是 docker pull 的镜像加速器。具体来说是两类完全不同的东西Docker 软件源docker-ce repo解决的是 apt-get install docker-ce 或 yum install docker-ce 时软件包下载慢的问题。它的地址通常是类似 download.docker.com 的镜像改的是 apt/yum 的源配置。容器镜像加速器registry mirror解决的是 docker pull 拉取镜像超时的问题。它对应上面说的 registry-mirrors 配置。不少教程把这两者混为一谈导致有人改了 apt 源然后兴冲冲地去 docker pull发现该卡还是卡。碰到自称“镜像站”的资源先确认它到底是提供 docker-ce 软件包还是提供容器镜像加速再动手配置。高校和社区维护的 Linux 软件镜像站里有一部分也提供容器镜像的缓存服务但口径不一致有的只缓存几个常用镜像有的提供完整的 registry mirror而且服务范围也常有变动。用于生产环境前务必先查看该镜像站的公告文档确认服务方式再使用。2.3 特殊仓库与第三方镜像的拉取路径除了 Docker Hub你还会遇到 ghcr.ioGitHub 容器仓库、quay.io红帽容器仓库、gcr.ioGoogle 容器仓库这类第三方 registry。它们的问题同样存在直连慢、超时、证书握手失败。你需要知道的是配置 registry-mirrors 对它们无效。想顺利拉取这些仓库的镜像常见的几种做法使用对应仓库的回源镜像服务例如某些第三方平台提供 ghcr.io 的代理地址把镜像名里的 ghcr.io 替换成代理地址再拉取。在能正常访问外网的 CI 环境或海外服务器上先把镜像拉到本地再 docker save 成 tar 包转存到内网。使用 skopeo 这类工具直接把镜像从源仓库复制到你的私有仓库绕开 docker pull 的限制。这些路径不像配置一个 mirror 那么简单但确实能解决特殊场景的拉取问题。后面第 3 章讲自建方案时会再展开内网镜像仓库的做法。3. 镜像源配置实操四个环境的完整参考3.1 Docker EngineLinux配置 registry-mirrorsLinux 服务器上 docker 的配置文件是 /etc/docker/daemon.json。打开文件把 registry-mirrors 字段填进去{ registry-mirrors: [ https://docker.mirrors.daocloud.io, https://mirror.baidubce.com, http://hub-mirror.c.163.com ] }保存后重启 docker 服务sudo systemctl daemon-reload sudo systemctl restart docker验证配置是否生效用 docker info 命令在看到 Registry Mirrors 字段时检查输出docker info输出中会出现类似这样的内容Registry Mirrors: https://docker.mirrors.daocloud.io/ https://mirror.baidubce.com/如果这里列出的地址和你配置的一致说明 dockerd 已经识别到了镜像源。接下来跑一次 docker pull hello-world测试实际拉取链路是否通畅。一个小细节配置里同时写了 https 和 http 的地址docker 在访问 http 源时可能会在日志里打出不安全提示这是正常的。生产环境优先使用 https 地址但确实有些公共源只提供 http也不影响正常使用。我个人建议在 daemon.json 中同时配置 3 个源左右。有一个源挂了docker 会自动回退到下一个不会直接拉取失败。只配一个源的话一旦源出问题整个拉取任务就卡住了。3.2 Docker DesktopWindows / macOS配置桌面端配置入口不一样但原理相同。打开 Docker Desktop进入 Settings切到 Docker Engine 标签页界面上展示的就是 daemon.json 的内容把 registry-mirrors 字段加进去点击 Apply Restart 即可。有一点需要提醒Docker Desktop 的配置界面在不同版本中的展示位置略有差异老版本叫 Daemon 标签页新版本叫 Docker Engine。如果你用的是 macOS 上的 Docker Desktop操作路径基本一致。桌面端的 Docker Engine 配置和 Linux 服务器上的 daemon.json 完全对应所以你在 Linux 上适用的 registry-mirrors 配置可以原样搬到桌面上。改完之后同样可以在 docker info 里验证。另外 Windows 上如果用了 WSL 2 后端配置的是 Docker Desktop 里的引擎配置不要单独去 WSL 发行版里再改一遍 /etc/docker/daemon.json两边配置存在同一处改了其中一边重启后会被覆盖回去。3.3 containerd 与 Kubernetes 节点配置Kubernetes 节点很多都是 containerd 作为容器运行时不再用 docker。这时候配置镜像源的地方变了得改 /etc/containerd/config.toml。通常在 CRI 插件的配置段里有一段 registry.mirrors 的配置加上你要用的源[plugins.io.containerd.grpc.v1.cri.registry.mirrors] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.docker.io] endpoint [https://docker.mirrors.daocloud.io, https://mirror.baidubce.com]注意里面配置了一个镜像仓库地址 docker.io意思是只在拉取 docker.io 仓库的镜像时才走后面的加速器地址。其他仓库的镜像containerd 不会使用这些加速器。修改完成后重启 containerdsudo systemctl restart containerd然后随便拉一个镜像验证crictl pull nginx如果你在 Kubernetes 环境遇到过明明配置了镜像加速器但节点拉镜像还是超时的情况多半是改错了配置位置。kubelet 本身不负责拉镜像它只负责调用容器运行时所以别在 kubelet 的启动参数里找镜像源配置那是找错方向的。3.4 自建内网镜像仓库一劳永逸的方案如果你在团队或公司环境里公共加速器再稳也属于外部依赖。更可控的做法是自建一个内网镜像仓库让所有人从内网拉取镜像。常用的方案是部署 Harbor 或 Nexus它们都支持镜像代理缓存功能。以 Harbor 为例开启代理缓存项目Proxy Cache之后配置一个指向 Docker Hub 的上游地址Harbor 会像镜像加速器一样把拉过的镜像缓存到本地存储。组内成员把镜像源配置成内网 Harbor 地址以后拉镜像全部走内网带宽又稳又快。整个流程基本就是客户端 → Harbor → Docker HubHarbor 内部完成缓存工作。如果你只是暂时需要一个轻量代理不想部署重型的 Harbor也可以直接用官方 registry 镜像启动一个带缓存代理的 registrydocker run -d \ --name local-registry \ --restartalways \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURLhttps://registry-1.docker.io \ registry:2这个容器本质上就是一个私有的 registry mirror它会把所有拉取请求转发给 Docker Hub并在本地保留缓存。客户端配置很简单在 daemon.json 的 registry-mirrors 里加上 http://你的服务器IP:5000 即可。由于自建服务通常没有配置 HTTPS 证书记得同时把该地址放进 insecure-registries 字段否则 docker 会因为它不是安全地址而拒绝连接。这个轻量方案的好处是部署快、依赖少适合个人服务器或者小团队使用缺点是缺少权限管理、镜像清理等功能需要自己定期处理存储膨胀的问题。团队规模较大、镜像管理需求重的场景建议直接上一套 Harbor。4. 镜像源故障排查从拉取失败到恢复的完整路径4.1 典型错误信息与对应处理配置完镜像源不代表万事大吉。这里把最常见的几类报错和排查方向列成一张速查表方便对照处理错误信息可能原因处理方向Get https://...: net/http: TLS handshake timeout加速器与你的网络之间握手超时换其他加速器或者确认加速器域名在你的网络下可访问Error response from daemon: manifest unknown镜像名或 tag 写错了镜像不存在核对镜像名和 tag确认拼写Error response from daemon: pull access denied镜像属于私有仓库未认证先 docker login 对应仓库再拉取Get https://...: dial tcp: lookup xxx on ...: no such hostDNS 解析失败检查 DNS 配置排查加速器域名是否可以解析Error response from daemon: Get ...: i/o timeout网络链路不通或源服务器无响应依次用 curl 测试多个加速器地址的连通性http: server gave HTTP response to HTTPS client加速器只支持 http但你写成了 https 地址把地址改成 http:// 形式再配置大部分报错背后都不是单一原因用上面的表先定位到大致方向再按下面的诊断步骤逐步收敛。4.2 诊断思路与验证步骤拉取镜像失败时先不要急着换源按一条清晰的路径排查下去很快能锁定问题。第一步测试加速器地址本身是否连通。直接 curl 加速器域名curl -I https://docker.mirrors.daocloud.io如果返回 200 或者 301 之类的 HTTP 状态码说明地址能访问如果超时或拒绝连接这个源对你不可用直接换下一个。注意有的加速器地址访问根路径返回 404这属于正常现象关键是看连接能不能建立而不是看 HTTP 状态码。第二步确认 docker daemon 的日志信息。很多情况下docker pull 超时后daemon 日志里已经有明确的错误原因journalctl -u docker -f观察日志里的错误行通常能看到是连接超时、证书校验失败还是 DNS 解析失败这一步能帮你精确定位。第三步做一次最小化验证。清空 registry-mirrors只保留一个源然后拉取docker pull hello-worldhello-world 镜像非常小拉取速度快适合做通路测试。如果 hello-world 能拉到说明基础链路没问题再去排查具体业务镜像的问题。这里有一个常见的隐蔽坑某些云服务器的安全组规则只放行了特定域名加速器的域名在服务器里能 ping 通但 docker pull 仍然超时原因可能是防火墙对 443 端口做了精细限制。这种情况用 wget 或 curl 测试的时候最好指定 HTTPS 协议完整访问不要只做 ICMP 测试。4.3 关于镜像源选择的三条原则踩过几次坑之后我总结出三条镜像源选择原则按优先级排序可以直接作为判断依据第一就近原则。选择与你网络出口到达最快的源。国内服务器选国内源海外服务器优先选所在区域的源不要盲目照搬别人的配置。一个源国内访问很快不代表你的机房访问也快。第二多源冗余。配置多个镜像源不要死磕一个。重点不是找一个“最好的源”而是保证列表里有至少两个可用的备选这样单点故障才不会影响你的拉取链路。第三可回退意识。保留直连 Docker Hub 的能力。如果你的服务器能直连 Docker Hub哪怕慢一点也要保证这条路没被完全堵死。有些发行版默认没有 daemon.json你如果已有文件编辑前先备份一份。公共加速器全部失效时直连 Docker Hub 拉镜像总比完全拉不了要强。还有一个需要注意的细节在配置 registry-mirrors 时尽量使用 https 地址避免明文传输。尤其在公网环境下镜像内容虽然没有被篡改的风险但链路中的相关信息还是尽量加密传输比较好。5. 针对镜像源问题的几点经验补充实际操作中还会遇到一些不容易归类的小问题单独拎出来补充。第一个是版本问题。不同 docker 版本对 registry-mirrors 配置的解析行为有细微差异旧版本可能要求地址末尾不要带斜杠新版本则无所谓。配置完成后用 docker info 验证一次就永远不会踩这个坑。第二个是代理环境的问题。如果你的服务器配置了 HTTP 代理环境变量docker 的拉取请求会走代理。这时即使镜像源配置正确也可能因为代理本身的问题导致超时。排查镜像问题时记得确认环境变量里的 HTTP_PROXY / HTTPS_PROXY / NO_PROXY 是否合理。有些公司内部代理只允许特定域名加速器域名不在白名单里就会反复超时。第三个是缓存问题。公共加速器有缓存不代表你的 Docker 本地也有缓存。如果镜像 tag 相同但内容变了比如 latest 被更新了你的 docker 节点上历史残留可能导致 pull 之后实际使用的还是旧镜像。遇到镜像内容不对的情况先 docker pull 一个新 tag 或加上 sha256 摘要验证避免误判成镜像源的问题。第四个是关于拆卸问题。如果你是在长时间运行的服务器上修改镜像源改完重启 dockerd 会导致所有容器被重启影响在线服务。稳妥做法是先在低峰期操作或者使用 docker daemon 的 reload 机制。实际上除非配置结构有变化某些场景可以通过发送 SIGHUP 信号让 daemon 重新加载配置但最靠谱的还是先备份配置后再重启。最后再说一个技巧在配置镜像源之前用 dig 或 nslookup 查一下加速器域名在你的网络下解析到哪个 IP这个 IP 是否在预期区域内。如果解析到异常 IP大概率是你本机的 DNS 配置有问题换源之前先修复 DNS否则换多少个源都一样。镜像源这件事说难不难说简单也不简单。核心就是理解拉取链路、分清镜像仓库和软件源、配置时保持多源冗余。按照上面的思路走一遍基本能解决绝大多数镜像拉取问题。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进