惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
K
Kaspersky official blog
V
Vulnerabilities – Threatpost
Hacker News - Newest:
Hacker News - Newest: "LLM"
Security Archives - TechRepublic
Security Archives - TechRepublic
S
Secure Thoughts
I
Intezer
TaoSecurity Blog
TaoSecurity Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Spread Privacy
Spread Privacy
A
About on SuperTechFans
NISL@THU
NISL@THU
The GitHub Blog
The GitHub Blog
Hugging Face - Blog
Hugging Face - Blog
S
Security @ Cisco Blogs
S
SegmentFault 最新的问题
G
Google Developers Blog
B
Blog
N
News and Events Feed by Topic
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
V2EX - 技术
V2EX - 技术
V
Visual Studio Blog
MyScale Blog
MyScale Blog
Webroot Blog
Webroot Blog
Vercel News
Vercel News
IT之家
IT之家
Microsoft Security Blog
Microsoft Security Blog
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
S
Security Affairs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
博客园 - 叶小钗
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Know Your Adversary
Know Your Adversary
T
Tailwind CSS Blog
F
Fortinet All Blogs
D
DataBreaches.Net
博客园 - Franky
博客园_首页
H
Heimdal Security Blog
宝玉的分享
宝玉的分享
阮一峰的网络日志
阮一峰的网络日志
Attack and Defense Labs
Attack and Defense Labs
Project Zero
Project Zero
雷峰网
雷峰网

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
国内网络环境下的 Docker 镜像迁移与加速实战:用 Skopeo 替代 docker pull + docker tag + docker push
billsking · 2026-05-04 · via 博客园_首页

在国内网络环境下做 Docker 开发和运维,很多人都踩过同一个坑:

  • docker pull 拉国外镜像,卡在几十 KB/s
  • CI/CD 构建时偶发超时,流水线一会儿红一会儿绿
  • 生产环境不允许直接访问 Docker Hub,只能走内网仓库
  • 想把一批镜像迁到私有仓库,结果只能一台机器一条条 pull/tag/push
  • 离线环境、内外网隔离环境下,镜像同步又麻烦又慢

很多团队的第一反应是:
配 Docker 镜像加速器手动拉取后再推送到 Harbor写 Shell 循环同步。这些方法不能说错,但都不够优雅,也不够稳。

这篇文章我想讲清楚一个非常实用、但国内很多开发和运维还没真正用起来的工具:Skopeo

它特别适合解决这类问题:

  • 国内网络环境下的 Docker 镜像迁移与加速
  • Docker Hub / Quay / GCR 镜像同步到私有仓库
  • 不落地镜像直接在仓库之间拷贝
  • 离线环境镜像导出、导入、批量同步
  • 无需 Docker Daemon 的镜像检查与复制

一句话概括:

Skopeo 的核心价值,就是让你“跳过本地 Docker 守护进程”,直接在镜像源和镜像目标之间做检查、迁移和同步。

这对国内网络环境尤其有用。


一、为什么国内网络环境下,Docker 镜像迁移与加速这么痛?

先说结论:
很多慢,不是你的机器慢,而是你的链路和使用方式本身就低效。

1.1 常见低效链路

很多团队平时迁移镜像是这么干的:

docker pull nginx:1.27
docker tag nginx:1.27 harbor.company.local/base/nginx:1.27
docker push harbor.company.local/base/nginx:1.27

看起来很正常,但本质上你走的是这条链路:

flowchart LR A[远程镜像仓库 Docker Hub] --> B[本机 docker daemon] B --> C[本地磁盘解包/缓存] C --> B B --> D[内网 Harbor / 私有仓库]

这条链路的问题很明显:

  1. 必须先完整拉到本地
  2. 依赖 Docker Daemon
  3. 占本地磁盘
  4. 批量同步时非常慢
  5. CI 机器要有 Docker 权限
  6. 多架构镜像、manifest list 处理不直观

对于“只是想把镜像从 A 仓库搬到 B 仓库”的场景,这个流程其实绕远了。


二、Skopeo 是什么?为什么它适合国内 Docker 镜像迁移与加速?

Skopeo 是一个容器镜像操作工具,主要能力包括:

  • 查看远程镜像信息
  • 在不同镜像存储之间直接复制镜像
  • 删除仓库中的镜像
  • 同步整个镜像仓库
  • 支持 Docker Registry、OCI、本地目录、docker-archive 等多种格式

它最关键的两个特点是:

2.1 不依赖 Docker Daemon

也就是说,很多操作不需要:

  • 启动 Docker
  • 有 root 权限
  • 把镜像先拉到本地

2.2 可以直接在仓库之间复制镜像

这就是它最值钱的地方。

比如你可以直接把 Docker Hub 的镜像复制到 Harbor:

skopeo copy docker://docker.io/library/nginx:1.27 docker://harbor.company.local/library/nginx:1.27

注意,这里不是:

  • 先 pull
  • 再 tag
  • 再 push

而是直接 copy

这条链路会变成:

flowchart LR A[远程仓库 Docker Hub] --> B[Skopeo] B --> C[目标仓库 Harbor]

中间少了本地 Docker Daemon,也通常少了很多无意义的本地存储开销。


三、Skopeo 能解决哪些典型问题?

围绕“国内网络环境下的 Docker 镜像迁移与加速”,Skopeo 最常见的几个落地场景如下。

3.1 场景一:把公网镜像迁移到内网 Harbor

比如你的 Kubernetes 集群只能拉 Harbor,不能直接访问 Docker Hub。
那你要做的不是让每台机器都科学拉镜像,而是:

在一台能访问外网的中转机上,用 Skopeo 把镜像同步到 Harbor。

3.2 场景二:做企业内部镜像缓存仓库

很多公司会有统一基础镜像:

  • nginx
  • redis
  • mysql
  • openjdk
  • alpine
  • busybox
  • node
  • python

可以定期同步到企业仓库,所有开发和集群统一从内网拉,速度稳定得多。

3.3 场景三:离线环境镜像打包与迁移

如果生产环境完全离线,可以这样处理:

  • 外网机器用 skopeo copy 导出为 docker-archive
  • U 盘/介质带到内网
  • 内网再导入目标仓库或 Docker

3.4 场景四:批量同步镜像,替代手写脚本 docker pull/tag/push

如果你有几十上百个镜像版本要同步,Skopeo 的 sync 会比手工脚本更清晰。


四、先安装 Skopeo

官方支持很多发行版,安装很简单。

4.1 Ubuntu / Debian

sudo apt-get update
sudo apt-get install -y skopeo

4.2 CentOS / RHEL / Rocky / AlmaLinux

sudo yum install -y skopeo

或:

sudo dnf install -y skopeo

4.3 macOS

brew install skopeo

4.4 验证安装

skopeo --version

五、先理解 Skopeo 最重要的几个概念

如果你是第一次接触 Skopeo,这几个前缀一定要先认清。

5.1 docker://

表示远程镜像仓库中的镜像。

例如:

docker://docker.io/library/nginx:1.27
docker://harbor.company.local/base/redis:7.2

5.2 docker-archive:

表示 docker save 格式的 tar 文件。

例如:

docker-archive:/tmp/nginx.tar

5.3 dir:

表示一个本地目录格式,适合调试和查看层文件。

5.4 oci:

表示 OCI 镜像布局目录。


六、国内网络环境下 Docker 镜像迁移与加速的 4 种实战方式

下面直接上最有用的部分。


6.1 方式一:直接从公网仓库复制到私有仓库

这是最推荐的方式。

6.1.1 登录目标仓库

比如 Harbor:

skopeo login harbor.company.local

输入账号密码即可。

6.1.2 复制镜像

skopeo copy \
  docker://docker.io/library/nginx:1.27 \
  docker://harbor.company.local/library/nginx:1.27

命令解释

skopeo copy \
  docker://docker.io/library/nginx:1.27 \
  docker://harbor.company.local/library/nginx:1.27
  • skopeo copy:复制镜像
  • 第一个地址:源镜像
  • 第二个地址:目标镜像
  • 中间不需要先 docker pull

对比:错误写法 vs 更优写法

传统写法

# 传统方式:依赖 docker daemon,本地要落盘
docker pull nginx:1.27
docker tag nginx:1.27 harbor.company.local/library/nginx:1.27
docker push harbor.company.local/library/nginx:1.27

更优写法

# 推荐方式:直接仓库到仓库复制
skopeo copy \
  docker://docker.io/library/nginx:1.27 \
  docker://harbor.company.local/library/nginx:1.27

为什么更优?

  • 少一次本地落盘
  • 不依赖 Docker Daemon
  • 更适合批量同步
  • 更适合 CI/CD 中转机
  • 更适合受限服务器环境

⚠️ 避坑点:目标仓库项目要提前存在
很多 Harbor 配置下,项目不存在时不会自动创建,直接报错。


6.2 方式二:先导出为 tar,再带到离线环境

如果你的生产环境完全无法联网,这种方式最实用。

6.2.1 从公网仓库导出为 Docker Archive

skopeo copy \
  docker://docker.io/library/redis:7.2 \
  docker-archive:/tmp/redis_7.2.tar:redis:7.2

解释

这里的目标:

docker-archive:/tmp/redis_7.2.tar:redis:7.2

含义是:

  • 导出成 docker save 兼容格式 tar 包
  • 文件路径:/tmp/redis_7.2.tar
  • 镜像名标签:redis:7.2

6.2.2 在离线机器中导入 Docker

docker load -i /tmp/redis_7.2.tar

6.2.3 再推送到内网私有仓库

docker tag redis:7.2 harbor.company.local/base/redis:7.2
docker push harbor.company.local/base/redis:7.2

对比:错误理解 vs 正确认知

错误理解

Skopeo 只能在联网仓库之间复制,离线没法用。

正确认知

Skopeo 支持:

  • 仓库 -> tar
  • tar -> 仓库
  • 仓库 -> OCI
  • 仓库 -> 本地目录

它并不只是“在线复制工具”,它也是一个镜像搬运格式转换工具


6.3 方式三:批量同步镜像到内网仓库

当你不是同步一个镜像,而是一批镜像时,copy 逐条执行会很烦。

这时候可以考虑:

  • Shell 批量循环
  • skopeo sync

6.3.1 用 Shell 批量迁移

先准备镜像列表:

docker.io/library/nginx:1.27
docker.io/library/redis:7.2
docker.io/library/alpine:3.20
docker.io/library/busybox:1.36

然后执行脚本:

#!/usr/bin/env bash
set -euo pipefail

# 私有仓库地址
TARGET_REGISTRY="harbor.company.local/base"

# 镜像列表文件
IMAGE_LIST="images.txt"

while read -r image; do
  # 跳过空行
  [[ -z "$image" ]] && continue

  # 取出最后一段作为目标名,例如 nginx:1.27
  name_with_tag="${image##*/}"

  echo ">>> 正在同步: $image -> $TARGET_REGISTRY/$name_with_tag"

  skopeo copy \
    "docker://$image" \
    "docker://$TARGET_REGISTRY/$name_with_tag"

done < "$IMAGE_LIST"

echo ">>> 全部同步完成"

脚本说明

#!/usr/bin/env bash
set -euo pipefail
  • -e:任一命令失败立即退出
  • -u:使用未定义变量时报错
  • -o pipefail:管道中任一命令失败都能感知

⚠️ 避坑点:不要写成“失败继续但最终显示成功”
很多人写批量迁移脚本时,最后打印“同步完成”,结果中间已经失败好几个镜像了。


6.4 方式四:同步整个仓库或指定仓库内容

skopeo sync 更适合做镜像仓库同步。

例如:

skopeo sync --src docker --dest dir registry.example.com/busybox /tmp/busybox-sync

这条命令含义是:

  • 源是 docker registry
  • 目标是本地目录
  • 把指定仓库同步下来

如果你要做更完整的离线同步,可以先同步到目录,再转运,再推入内网仓库。


七、先别急着拉镜像:用 skopeo inspect 先看清楚

这是我非常建议养成的习惯。
很多时候镜像拉不下来、架构不对、标签不对,不是网络问题,而是你拿错镜像了。

7.1 查看远程镜像信息

skopeo inspect docker://docker.io/library/nginx:1.27

输出中重点关注这些字段

  • Digest:镜像摘要,判断版本是否一致
  • Architecture:架构,如 amd64 / arm64
  • Os:系统
  • Layers:镜像层
  • Env:环境变量
  • RepoTags:仓库所有标签

7.2 只看镜像摘要

skopeo inspect docker://docker.io/library/nginx:1.27 | jq '.Digest'

7.3 查看配置层

skopeo inspect --config docker://docker.io/library/nginx:1.27 | jq

这在排查以下问题时非常有用:

  • 为什么镜像拉下来跑不起来
  • 为什么同名标签内容变了
  • 为什么 ARM 机器拉 AMD64 镜像失败

⚠️ 避坑点:标签相同,不代表 digest 相同
latest 这种标签最容易坑人。
真正稳定的是 digest,不是 tag。


八、国内网络环境下,镜像加速到底该怎么做?

很多人看到“加速”两个字,第一反应是找“加速地址”。
这不完全错,但如果你从工程实践角度看,真正稳定的加速方案是分层的。


8.1 第一层:优先使用企业私有仓库做统一缓存

最靠谱的做法不是让每台机器都直连外网,而是:

  1. 用一台网络条件较好的中转机
  2. 用 Skopeo 定时同步常用镜像到 Harbor
  3. 所有开发机、测试机、K8s 节点只从 Harbor 拉取

架构如下:

flowchart LR A[Docker Hub / Quay / GCR] --> B[同步机 Skopeo] B --> C[企业 Harbor / 私有仓库] C --> D[开发机] C --> E[CI/CD Runner] C --> F[Kubernetes 节点]

这套方案比“每台机器自己配加速源”稳定太多。

优势

  • 统一治理
  • 可审计
  • 可控版本
  • 减少公网依赖
  • 构建速度更稳定
  • 更适合生产环境

8.2 第二层:构建“白名单基础镜像池”

建议企业维护一份基础镜像清单,比如:

  • nginx
  • redis
  • mysql
  • postgres
  • openjdk
  • eclipse-temurin
  • node
  • python
  • golang
  • alpine
  • busybox

每天或每周定时同步指定版本。这样:

  • 开发不需要到处找镜像
  • 安全团队更容易做漏洞治理
  • 线上版本来源统一

这比大家各自 docker pull 要专业得多。


九、多架构镜像迁移时的注意事项

现在 ARM 机器越来越多,尤其是:

  • Apple Silicon 开发机
  • ARM 服务器
  • 边缘设备
  • 某些国产化环境

所以你迁移镜像时,不能只看 tag,还要看架构。

9.1 查看架构

skopeo inspect docker://docker.io/library/nginx:1.27 | jq '.Architecture, .Os'

9.2 为什么会出问题?

同一个标签可能对应:

  • 单架构镜像
  • 多架构 manifest list

如果你目标环境是 ARM,但你同步的只是 AMD64 镜像,最后运行就会报:

  • exec format error
  • 镜像拉取正常但容器启动失败

⚠️ 避坑点:镜像能 pull,不代表能 run
很多问题不是出在仓库,也不是出在网络,而是架构不匹配


十、认证、登录与凭据管理

私有仓库几乎都需要认证。

10.1 登录仓库

skopeo login harbor.company.local

10.2 直接在命令中传凭据

skopeo inspect \
  --creds='username:password' \
  docker://harbor.company.local/base/nginx:1.27

或者 copy 时分别指定源和目标凭据:

skopeo copy \
  --src-creds='src_user:src_pass' \
  --dest-creds='dst_user:dst_pass' \
  docker://docker.io/library/nginx:1.27 \
  docker://harbor.company.local/base/nginx:1.27

⚠️ 避坑点:不要把明文密码硬编码进 Git 仓库脚本
更好的做法:

  • 用 CI Secret
  • 用环境变量
  • 用独立凭据文件
  • skopeo login 预先登录

十一、实战:做一个“国内 Docker 镜像迁移与加速”同步脚本

下面给一个更接近生产可用的版本。

11.1 镜像清单文件

docker.io/library/nginx:1.27
docker.io/library/redis:7.2
docker.io/library/alpine:3.20
quay.io/prometheus/prometheus:v2.53.0

11.2 同步脚本

#!/usr/bin/env bash
set -euo pipefail

# ============================================
# 国内网络环境下的 Docker 镜像迁移与加速脚本
# 功能:
# 1. 从公网仓库读取镜像
# 2. 使用 skopeo 直接复制到 Harbor
# 3. 支持失败退出,避免“部分成功却误判整体成功”
# ============================================

# Harbor 仓库前缀
TARGET_REGISTRY="harbor.company.local/mirror"

# 镜像清单文件
IMAGE_LIST_FILE="./images.txt"

# 检查 skopeo 是否安装
if ! command -v skopeo >/dev/null 2>&1; then
  echo "错误:未安装 skopeo,请先安装"
  exit 1
fi

# 检查镜像文件是否存在
if [[ ! -f "$IMAGE_LIST_FILE" ]]; then
  echo "错误:镜像清单文件不存在: $IMAGE_LIST_FILE"
  exit 1
fi

# 开始循环处理每个镜像
while IFS= read -r image; do
  # 去掉空行和注释行
  [[ -z "$image" ]] && continue
  [[ "$image" =~ ^# ]] && continue

  # 取出镜像名+tag,例如 nginx:1.27
  image_name_tag="${image##*/}"

  # 构造目标镜像路径
  target_image="${TARGET_REGISTRY}/${image_name_tag}"

  echo "========================================"
  echo "开始同步镜像"
  echo "源镜像: docker://${image}"
  echo "目标镜像: docker://${target_image}"
  echo "========================================"

  # 执行复制
  skopeo copy \
    "docker://${image}" \
    "docker://${target_image}"

  echo "同步成功: ${image} -> ${target_image}"
  echo

done < "$IMAGE_LIST_FILE"

echo "全部镜像同步完成"

11.3 使用方式

chmod +x sync-images.sh
./sync-images.sh

十二、错误写法和正确写法对比

这一段最适合拿来给团队统一规范。


12.1 错误写法:把中转机当下载器

docker pull docker.io/library/nginx:1.27
docker tag docker.io/library/nginx:1.27 harbor.company.local/base/nginx:1.27
docker push harbor.company.local/base/nginx:1.27
docker rmi docker.io/library/nginx:1.27
docker rmi harbor.company.local/base/nginx:1.27

问题

  • 流程冗长
  • 占用磁盘
  • 依赖 daemon
  • 批量脚本维护差
  • 容易把本机磁盘打满

12.2 正确写法:直接 copy

skopeo copy \
  docker://docker.io/library/nginx:1.27 \
  docker://harbor.company.local/base/nginx:1.27

优势

  • 更直接
  • 更适合自动化
  • 更适合批量迁移
  • 更适合国内网络环境下的 Docker 镜像迁移与加速

12.3 错误写法:只信 tag,不校验 digest

# 只看 tag,觉得 latest 一定是对的
skopeo copy docker://docker.io/library/nginx:latest docker://harbor.company.local/base/nginx:latest

风险

  • 上游 latest 已变更
  • 测试和生产拿到的不是同一份内容
  • 追问题时找不到版本基准

更稳妥的思路

  • 先 inspect
  • 记录 digest
  • 优先固定 tag 甚至固定 digest

十三、常见排查思路:镜像同步失败时看什么?

这里我按实战经验给一个排查顺序。

13.1 第一步:先 inspect,确认镜像是否存在

skopeo inspect docker://docker.io/library/nginx:1.27

如果 inspect 都失败,那大概率是:

  • 源仓库连不通
  • 标签写错
  • 仓库路径写错
  • 凭据不对

13.2 第二步:检查目标仓库权限

skopeo login harbor.company.local

然后再 copy。

常见报错本质上就是:

  • 没有 push 权限
  • 项目不存在
  • 项目禁止匿名访问

13.3 第三步:检查仓库路径是否完整

Docker Hub 官方镜像很多人容易少写 library

容易误写

docker://docker.io/nginx:1.27

更稳妥写法

docker://docker.io/library/nginx:1.27

⚠️ 避坑点:不同 Registry 的命名规范不完全一样
不要把 Docker CLI 的“省略写法”直接等价到所有工具中。


13.4 第四步:检查是否是架构问题

skopeo inspect docker://docker.io/library/nginx:1.27 | jq '.Architecture'

如果目标机器是 ARM,而你同步的是 AMD64,后面容器运行就会出问题。


13.5 第五步:检查出口网络和 DNS

国内环境下,最真实的问题往往不是命令写错,而是:

  • DNS 解析慢
  • TLS 握手超时
  • 出口限流
  • 代理配置不一致
  • 某些仓库域名被拦截或丢包

这时候你应该把“镜像同步”从每个节点收口到统一同步机,而不是让每台机器都自己去碰运气。


十四、Skopeo 和 Docker 到底怎么分工?

这个问题很多人会问。

我的建议很简单:

用 Docker 的场景

  • 本地开发构建镜像
  • 运行容器
  • 日常调试容器
  • docker build / run / exec / logs

用 Skopeo 的场景

  • 远程镜像检查
  • 镜像仓库之间迁移
  • 批量同步
  • 离线打包/导出
  • 做企业镜像缓存
  • 不想依赖 Docker Daemon 的自动化任务

一句话:

Docker 更像“容器运行工具”,Skopeo 更像“镜像搬运工具”。


十五、一个非常实用的落地方案

如果你所在团队经常遇到国内拉镜像慢的问题,我建议直接落地这套方案:

方案步骤

  1. 准备一台网络较稳定的同步机
  2. 安装 Skopeo
  3. 登录 Harbor
  4. 维护一份基础镜像白名单
  5. 每天定时同步到 Harbor
  6. 开发机、CI、K8s 统一从 Harbor 拉镜像

定时任务示例

crontab -e

加入:

0 2 * * * /opt/scripts/sync-images.sh >> /var/log/sync-images.log 2>&1

这表示每天凌晨 2 点同步一次。

这样做的效果

  • 白天构建更稳定
  • 镜像来源统一
  • 版本更可控
  • 公网依赖更少
  • 故障排查更集中

十六、面试里如果被问到“如何解决国内 Docker 拉镜像慢”?

你不要只回答“配镜像加速器”。

更完整、更工程化的回答应该是:

可以这样答

  1. 开发环境 可以配置镜像加速器,提高常用镜像拉取速度
  2. 测试/生产环境 更推荐搭建企业私有仓库,比如 Harbor
  3. Skopeo 定时把 Docker Hub、Quay 等公网镜像同步到内网仓库
  4. 对于离线环境,可以用 skopeo copy 导出 docker-archive 再离线导入
  5. 同步前可以用 skopeo inspect 检查镜像 digest、架构、标签,避免拉错镜像
  6. 对关键基础镜像维护白名单和固定版本,避免 latest 带来的不可控变更

这类回答会明显比“用代理”更像真正做过事的人。


十七、总结:国内网络环境下,Docker 镜像迁移与加速,Skopeo 是非常值得掌握的工具

把这篇文章的核心内容收一下:

你应该记住的 5 个结论

  1. 传统 docker pull/tag/push 方式能用,但效率不高
  2. Skopeo 可以直接在仓库之间复制镜像,不依赖 Docker Daemon
  3. 国内网络环境下,最佳实践不是每台机器自己拉,而是统一同步到私有仓库
  4. skopeo inspect 很适合在拉取前确认 digest、架构和标签
  5. 离线环境、批量迁移、镜像缓存仓库,这些场景 Skopeo 都比 Docker 原生命令更顺手

最推荐的落地方式

用一台网络条件好的同步机 + Skopeo + Harbor,构建企业内部镜像缓存和迁移通道。

这套方案不花哨,但很稳,非常适合国内网络环境下的 Docker 镜像迁移与加速。


十八、拓展学习资料

官方文档


扫码关注不迷路
image