如果你正在读这篇文章,很可能正面临两个场景中的一个:要么系统已经出了问题,准备重装Windows或Linux,突然想起来Docker里还躺着好几个镜像;要么已经重装完了,打开Docker Desktop发现镜像列表空空如也,心态瞬间爆炸。标题里“系统重装不丢镜像”这八个字,就是我踩过三次坑之后悟出来的刚需。
Docker镜像的备份与恢复,本质上就是四个字:导出、导入。但你真去操作的时候会发现,单机备份好说,批量迁移才是噩梦;镜像能打tar包,可恢复了之后容器起不来、数据卷没挂载、端口全部冲突……这些问题每一个我都会在后面拆开来讲。
这篇文章适合谁?适合正在用Docker Desktop的Windows用户、服务器上用Docker跑生产服务但准备迁移或重装的运维,以及刚学Docker不久、想知道save/load和export/import到底有什么区别的新手。我会结合自己重装系统的实际操作经验,把从备份到恢复的完整流程、踩坑点和避雷技巧全部捋清楚。
1. 系统重装场景下的镜像迁移难点与思路拆解
1.1 为什么镜像会丢:不只是重装的问题
先说一个大家容易忽略的事实:重装系统丢了镜像,其实根本不是重装这件事本身造成的,而是重装前的“环境清理”把Docker的存储目录一起干掉了。
Windows上如果你用的是Docker Desktop,镜像默认存放在WSL2发行版的虚拟磁盘里,也就是那个vhdx文件里。你重装系统,整个C盘被格式化,这个虚拟磁盘自然跟着灰飞烟灭。更隐蔽的是,即使你只是重置了WSL2发行版——比如因为Docker Desktop启动不了,顺手执行了wsl --unregister docker-desktop——镜像和数据卷也会被一并清空。这一点我特别要提醒:很多人以为Docker Desktop卸载重装不会动镜像,实际上如果你在卸载时勾选了删除WSL数据,或者WSL发行版本身损坏导致需要重建,镜像一样保不住。
Linux服务器上情况类似。镜像默认存在/var/lib/docker目录下,重装系统格式化分区,目录没了;即便是无损重装,只要/var/lib/docker所在的分区没单独划出来,也一样被覆盖。所以结论很清晰:镜像备份不是“要不要做”的问题,而是“每一次系统级变更前必须做”的固定动作。
1.2 三种主流备份方案对比
针对“系统重装不丢镜像”这句话,目前我能想到的可靠方案有这三种:
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| docker save + tar归档 | 把镜像导出为本地tar文件 | 操作简单、离线可用、可控性强 | 不能自动增量、大镜像占用磁盘空间 | 单机迁移、系统重装前手动备份 |
| 自建Docker Registry私有仓库 | 通过push/pull同步镜像到仓库服务器 | 可增量、适合长期维护、恢复速度快 | 需要额外一台服务器或存储空间 | 多台机器、定期备份、生产环境 |
| 直接复制/var/lib/docker目录 | 停服后压缩整个Docker数据目录 | 镜像、容器、数据卷全部保留 | 对运行中的Docker有风险、跨系统版本兼容性差 | Linux物理机整机迁移 |
我自己的习惯是:手动操作前用方案一,日常定期备份用方案二,LVM快照或者整盘灾备用方案三。方案一操作最直观,适合绝大多数人;方案二适合有一定基础、有多台机器的人;方案三我不建议新手用,因为如果新旧系统内核版本差异大,/var/lib/docker目录里的存储驱动元数据很容易不兼容,恢复后Docker守护进程会报错。
1.3 一个容易搞混的概念:备份镜像 ≠ 备份数据
在展开实操之前,我必须先把这件事说透:Docker镜像是个只读模板,真正跑起来的业务数据在容器层和数据卷里。
打个比方,镜像就像一张Windows安装光盘,容器就是从光盘启动起来的系统。你重装电脑时如果只把光盘带走了,那C盘里的文档、桌面上的照片全都没了——文档照片相当于容器内改动和数据卷。后面你会看到,我备份的时候永远是“镜像tar包”加“数据卷tar包”一起打包,两个都留好,恢复的时候才能真正还原到重装前的状态。这个认知如果不建立,就算你照着本文把镜像load回去了,容器里的配置、数据库文件该缺还是缺。
2. 核心细节解析:save/load与export/import的取舍
2.1 docker save和docker load的正确用法
Docker官方提供的最基础备份手段是docker save和docker load。先看命令格式:
# 备份单个镜像 docker save -o nginx-backup.tar nginx:latest # 备份多个镜像 docker save -o images-backup.tar nginx:latest mysql:8.0 redis:7-alpine # 恢复 docker load -i nginx-backup.tar-o后面的文件可以任意命名,但后缀建议用.tar。如果你用了.tar.gz,注意docker save并不会帮你压缩,gz后缀只是你手动或者用管道压缩后的结果。想压缩的话可以这样:
docker save nginx:latest | gzip > nginx-backup.tar.gz # 恢复时 gunzip -c nginx-backup.tar.gz | docker load为什么我推荐管道压缩而不是先docker save -o再gzip?因为前者不落中间文件,省一次磁盘写放大。但对于几十GB的大镜像,我建议别省这一步,直接先出tar再单独压缩反而更好排查问题,因为docker load对损坏的tar包报错信息比较明确,而对被截断的gz流报错比较晦涩。
还要提一个关键细节:docker save保存的是镜像的完整层结构和历史元数据,docker load能还原出完全一样的镜像。但docker pull下来的一些元信息如Digest(摘要)也会保留,后期你用docker inspect看RepoDigests属性时能看到。这个特性决定了save/load是“标准备份方式”。
2.2 docker export和docker import:别看错了
和save/load特别容易搞混的还有一对命令:docker export和docker import。docker export是把一个容器的文件系统导出成tar包,而不是镜像。换句话说,它扁平化了镜像层和容器层,把当前容器所有文件打在一起。
# 将容器mywebserver的文件系统导出 docker export -o mywebserver-fs.tar mywebserver # 从该tar包导入为一个新镜像 docker import mywebserver-fs.tar mywebserver:202401这里有个非常隐蔽的坑:docker export导出的文件系统里,很多容器运行时的元数据(环境变量、工作目录、启动命令、暴露端口)会被丢弃。导入后的新镜像的Entrypoint和CMD很可能变成空。你docker run这个导入出来的镜像时,得手动加-e、-p、--entrypoint参数,非常麻烦。
那export/import有什么用?我的判断是:它适合做“现场取证式”的快照,不适合做常规备份。比如一个容器被改得面目全非、镜像却在早期版本时,export一下可以把现场文件保留下来。常规重装场景下,优先用save/load,别用export/import。
2.3 为什么还要考虑docker commit?
有一种特殊情况:镜像是从Docker Hub拉的,你直接在docker run容器里改了一堆配置,比如安装了Vim、修改了Nginx的配置文件,然后希望把“这个改好的容器”备份下来。这时候docker commit可以帮你把容器当前状态固化成新镜像,再docker save备份。
# 在容器内做完修改后,提交为新镜像 docker commit mynginx mynginx:with-vim # 再备份 docker save -o mynginx-with-vim.tar mynginx:with-vim不过commit有个老生常谈的问题:它不太适合有数据卷的容器,因为数据卷里的内容不会进镜像。而且commit出来的镜像体积往往臃肿,因为原本属于临时文件、日志文件的内容也被一起打包了。所以我给这个操作的定位是:临时固化状态时用,重装前的正式备份中,它只对“没有卷且需要保留容器内改动”的容器有意义。
2.4 备份前必看的Docker环境信息
重装系统之前,建议先跑一遍以下命令,把环境信息收拢到一个文本文件里,恢复时能少走很多弯路:
# 列出所有镜像及大小 docker images --format "table {{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.Size}}" # 列出所有容器(含停止的) docker ps -a # 列出所有数据卷 docker volume ls # 导出容器的完整配置,以备重建 docker inspect $(docker ps -aq) > /path/to/backup/container-inspect.jsondocker inspect导出的那份JSON很有价值。恢复后你如果要重建容器,这份文件里能看到之前用什么镜像、什么端口映射、哪些卷、哪些环境变量。当然,最直接的还是用Docker Compose管理容器,因为compose文件本身就是最好的配置备份——这点我放到后面第五节讲。
3. 实操备份流程:从单镜像导出到批量脚本化
3.1 单机单个镜像备份
假设现在机器上跑了一堆服务,我要赶在重装系统前把它备份干净。最简单的是从单个镜像开始:
docker save -o /backup/nginx-latest.tar nginx:latest ls -lh /backup/nginx-latest.tar这里的一个小动作是:备份完毕后建议立刻执行sha256sum生成校验文件,防止后面拷贝、复制过程中损坏了tar包却不知道:
sha256sum /backup/nginx-latest.tar > /backup/nginx-latest.tar.sha256恢复的时候先校验一下,再docker load:
cd /backup echo "校验收到的文件" sha256sum -c nginx-latest.tar.sha256 docker load -i nginx-latest.tar有些人嫌麻烦,觉得多此一举,但我在系统迁移时真的遇到过U盘拷一半断连、tar文件损坏的情况。没有校验文件,你可能在docker load时报一个莫名其妙的archive/tar: invalid tar header,就必须重新到处找备份来源了。多一行命令,少一次抓狂,性价比极高。
3.2 全量镜像批量导出与压缩
机器上镜像一多,一个个docker save显然不现实。这里贴一个我常用的脚本,它会把当前机器上所有镜像逐一遍历并保存为独立的tar文件:
#!/bin/bash # 批量导出所有Docker镜像 # 用法: ./backup-images.sh /path/to/backup/dir BACKUP_DIR="${1:-./docker-image-backup}" mkdir -p "$BACKUP_DIR" # 获取镜像列表:仓库:标签 docker images --format "{{.Repository}}:{{.Tag}}" | while read -r image; do # 过滤掉悬空镜像或纯ID列表 if [ "$image" = "<none>:<none>" ]; then echo "[跳过悬空镜像] $image" continue fi # 将路径中的 / 替换为 _ ,避免文件名不合法 safe_name=$(echo "$image" | tr '/:' '__') file_name="$BACKUP_DIR/${safe_name}.tar" echo "正在导出 $image -> $file_name" docker save -o "$file_name" "$image" done # 生成所有文件的校验信息 echo "生成SHA256校验文件..." (cd "$BACKUP_DIR" && sha256sum *.tar > checksum.sha256) echo "备份完成,文件列表:" ls -lh "$BACKUP_DIR"注意我在脚本里做了一个安全处理:镜像名中的斜杠和冒号替换成下划线。因为镜像名可能是registry.example.com/team/app:1.2.3,直接当文件名会带/导致目录层级错乱,带:在Windows上又会被拒。这个细节不处理,脚本在Windows上大概率会炸。
如果你希望所有镜像打包成一个文件(这样好拷贝,但恢复时没办法单选),也可以这样:
docker save $(docker images -q) > /backup/all-images.tardocker images -q会输出所有镜像ID,注意系统里如果有悬空镜像(<none>),这也会被包含进去。恢复时docker load -i all-images.tar会把所有镜像全部导入。
跑完批量脚本后,我的习惯产物是这样的目录:
/backup/ ├── nginx_latest.tar ├── mysql_8.0.tar ├── redis_7-alpine.tar ├── my-service_1.0.tar └── checksum.sha2563.3 使用私有Registry进行推送式备份
对服务器环境,我强烈建议搭建一个本地私有Registry,把重要的镜像统一推过去。这样重装后的恢复就是一条docker pull命令的事。搭建方式如下:
# 启动一个本地registry容器,端口5000 docker run -d -p 5000:5000 --restart=always --name registry registry:2然后给镜像打一个私有仓库的标签,再推送过去:
docker tag nginx:latest localhost:5000/nginx:latest docker push localhost:5000/nginx:latest恢复端只需要:
docker pull localhost:5000/nginx:latest # 如果你不想要带仓库地址的标签,可以重新打标签 docker tag localhost:5000/nginx:latest nginx:latest这个方案平时看起来比docker save厚重,但它的优势在于仓库天然是集中式、支持多版本管理。如果搭配一个内网存储,甚至可以把它当成团队内部镜像源来用。不过要提醒,私有仓库的镜像文件存储在你指定的服务器目录里,这个目录本身也要纳入备份计划,否则服务器挂了镜像一样丢。
3.4 数据卷的备份:镜像之外的另一半战场
还记得前面说的“备份镜像 ≠ 备份数据”吗?现在来处理数据卷。
Docker数据卷主要有两类。一类是docker volume管理的命名卷,另一类是bind mount宿主机目录。备份命名卷最通用的方式是启动一个临时容器,把它挂载到卷上,然后打包:
# 假设有一个名为mysql-data的卷需要备份 docker run --rm -v mysql-data:/source -v /backup:/backup alpine tar czf /backup/mysql-data.tar.gz -C /source ./一句话解释这条命令:用一个临时alpine容器,把mysql-data卷挂到容器的/source,同时把宿主机的/backup挂到容器的/backup,然后在容器内把/source里的内容压缩到/backup/mysql-data.tar.gz。--rm保证容器用完自动删掉,不残留。
bind mount目录就更简单了,直接压缩宿主机目录即可:
tar czf /backup/mysql-bind.tar.gz /data/mysql注意bind mount打包前,最好先确保容器停了再打包,否则数据库文件处于热写状态,打出来的包的一致性没有保障。MySQL这类数据库尤其如此。
4. 实操恢复流程:干净环境重建与验证
4.1 新系统安装Docker的关键准备
重装好系统后,第一件事不是立刻导入镜像,而是先装一个能用的Docker环境。如果你之前用的是Docker Desktop,记得开启Windows的虚拟机平台选项:控制面板 -> 启用或关闭Windows功能 -> 勾选“虚拟机平台”和“适用于Linux的Windows子系统”,然后重启。这一步漏了,Docker Desktop会报“Virtualization support not detected”或者“Failed to start because v..."这样的错,热词里提到了相关错误,基本就是虚拟化没开。Linux服务器上没有这个问题,直接装docker-ce即可,但要注意当前账户是否有权限操作Docker,记得把用户加入docker组:
sudo usermod -aG docker $USER # 重新登录后生效4.2 通过docker load逐个恢复镜像
环境就绪后,把备份文件拿到新机器上,先校验完整性:
cd /path/to/backup sha256sum -c checksum.sha256校验通过后批量导入镜像:
# 逐个导入 for f in *.tar; do echo "导入 $f"; docker load -i "$f"; done如果你备份时是导出成一个超大all-images.tar,那一条命令搞定:
docker load -i all-images.tar导入完成后验证一下:
docker images这一看就能确认镜像是不是都回来了。
4.3 从Registry拉取恢复
如果使用的是私有仓库方式,那就更轻松了,先启动registry容器(或者直接指向远程仓库地址),再从仓库pull:
docker pull localhost:5000/nginx:latest docker tag localhost:5000/nginx:latest nginx:latest需要注意一点:如果你的私有Registry开启了认证,那么恢复服务器上需要先docker login localhost:5000,并且这里要手动输入用户名密码。没有配认证的话,默认可以匿名拉取,这种方便在隔离内网可以用,但连着外网就别这么裸奔了。
4.4 恢复数据卷并重建容器
镜像导入只是第一步,要跑起来还得恢复数据卷和容器配置。
针对命名卷,参考备份时的反向操作:
# 先创建一个空数据卷 docker volume create mysql-data # 把备份的压缩包解压进卷里 docker run --rm -v mysql-data:/target -v /backup:/backup alpine tar xzf /backup/mysql-data.tar.gz -C /target针对bind mount路径,先在宿主机建好目录并解压,再重建容器。
容器重建有两条路。第一条是直接用docker run命令重建,这要求你备份时把docker run的参数都记下来了;第二条是之前有docker-compose.yml,那直接用compose恢复:
docker compose up -d我现在强烈建议,从第一次部署某个容器开始就用Compose管理,因为它的可恢复性比裸docker run好太多。镜像能备份、卷能备份,但一条裸docker run命令是不会自动备份的,你恢复时全靠回忆当初“-p 8080:80 -e xxx=yyy”写了什么——迟早翻车。
4.5 恢复后的验证清单
镜像和容器都恢复后,不要直接就认为万事大吉。我给自己定了一份验证清单,每一条都会过一遍:
- 容器进程状态:
docker ps -a,看看是不是所有预期的容器都变成Up而不是Exited。 - 端口监听:
ss -tlnp | grep -E '8080|3306'这类命令,确认端口映射没被其他进程占掉。 - 业务探活:如果是Web服务,curl一下本机地址确认能拿到200响应;如果是数据库,用客户端连一下确认数据都在。
- 日志没有持续报错:
docker logs --tail 50 <container>看一眼最近日志,防止恢复后容器在疯狂重启。 - 数据卷文件:进容器里
ls一下相关数据目录,或者直接查数据库表,确认不是空卷。
这套验证流程看起来繁琐,但总比重装完一周后才发现某个服务的数据库是空的强。
5. 备份恢复中的常见问题与排查技巧实录
5.1 Docker Desktop重装后镜像空间丢失,如何找回?
这是Windows用户的高频问题。场景是:Docker Desktop某次更新失败,或WSL2的docker-desktop发行版异常,你wsl --unregister docker-desktop后重装Docker Desktop,结果之前拉取的镜像全没了。
原因在于Docker Desktop在WSL2中的镜像存储位于docker-desktop发行版里,而你unregister了这个发行版,存储文件就没了。
这类情况救不救得回来,取决于有没有提前备份。如果提前做了docker save备份,用本文第4节恢复即可;如果没有备份,可以尝试在WSL2的vhdx文件中做数据恢复,但成功率不稳定,而且vhdx文件很少能完整恢复出来。
所以这里真的要说一句经验之谈:Docker Desktop每当你准备升级版本或者系统重装前,先把镜像批量导一遍,成本远低于事后抢救。
5.2 备份tar文件完好,但docker load导入时报错
docker load -i xxx.tar报错信息五花八门,常见的有:
file does not exist:路径写错,检查文件名。invalid tar header:tar文件损坏,先跑sha256sum -c校验;如果校验通过仍报错,可能是tar包本身不完整或导出时Docker版本跨度过大。Error processing tar file: unexpected EOF:同样指向文件不完整,重新拷贝或重新导出。no space left on device:磁盘空间不足,Docker需要把镜像层解压到存储目录,空间不够就导入失败。先清理一下旧镜像或日志,再导入。
这里提醒一下,导入新镜像时,如果本地已有同名不同ID的镜像,docker load会保留原有镜像并加载新镜像,可能让docker images里出现两个相同标签但ID不同条目的情况。遇到这种情况,用docker tag重新打标签,或者直接docker rmi旧ID来清理。
5.3 恢复后容器起不来,疯狂重启
镜像和卷都恢复好之后,容器启动仍可能报错。比较典型的几个原因:
- 数据卷路径不一致:bind mount的宿主机路径和原来不一样,容器内进程找不到数据文件,比如MySQL起不来,报
Can't open the mysql.plugin table。检查挂载路径是否准确,必要时新建目录并把解压的数据放过去。 - 环境变量缺失:很多镜像靠
-e MYSQL_ROOT_PASSWORD之类的环境变量初始化,恢复时如果忘了写,数据库容器可能直接用默认配置启动,或者直接启动失败。 - 端口被占用:新系统上可能已经有一个服务占用了3306、8080等端口,容器起不来就查一下端口冲突。
- 依赖的其他容器还没就绪:比如应用容器依赖数据库容器,数据库还在初始化时应用就先启动了,导致应用退出。这是编排层面的问题,最好用Docker Compose管理,配合healthcheck来控制启动顺序。
排查手法其实很简单:docker logs <container>看报错,docker inspect <container>看挂载和环境变量,把这两条命令用熟了,大部分问题都能定位。
5.4 旧配置“硬编码”在容器里,导出镜像时没包含,恢复后丢失
还有一个高频问题是:你在容器里用了一个bind mount,挂载了宿主机某个目录;备份镜像时只备份了镜像本身,却忘了这个目录,结果恢复后容器是起来了,但配置是空的。
这种事情我遇到太多次了。印象最深的是某次跑Grafana,所有面板配置都在挂载的宿主机目录下,镜像tar包只有程序本体。恢复后Grafana起得飞快,但面板全空。
所以请一定记住,每次备份的产物应该是“镜像tar包 + 数据卷tar包 + 配置文件tar包”三件套,而不是只有镜像tar包。
5.5 备份恢复后的数据一致性检查
对于数据库类容器,恢复后千万急着把容器设为Up完了就完事,要检查一下数据。顺手列几条:
- MySQL:登录后执行
SHOW DATABASES;,看库里表是否齐全。 - Redis:
redis-cli DBSIZE看key数量,或者对比一下KEYS *里关键的key是否存在。 - PostgreSQL:
\l列出数据库,\dt看表。 - 文件类服务(如Nginx):
ls /usr/share/nginx/html确认静态文件都在。
数据完整性的验证不能省,尤其是有段时间空窗期的备份,备份时数据是什么状态,恢复后就要是什么状态,别到业务报警了才发现数据不对。
6. 进阶:从“备份镜像”到“完整恢复工作流”
6.1 用Docker Compose管理可复现的容器配置
如果说镜像tar包是“可运行的软件”,那Compose文件就是“怎么运行这个软件的说明书”。有了Compose文件,恢复容器就是一条命令;没有Compose文件,你得靠docker inspect去逆向推导。
一个最小示例:
# docker-compose.yml services: web: image: nginx:latest ports: - "8080:80" volumes: - ./html:/usr/share/nginx/html db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: appdb volumes: - mysql-data:/var/lib/mysql volumes: mysql-data:重装后,在新系统上执行:
docker compose up -d它会自动按Compose文件创建网络、创建卷、拉取或加载镜像(如果是load进本地的镜像)并启动容器。
所以我现在每次部署新服务,几乎都是先写Compose文件。备份时,把docker-compose.yml和.env文件放进备份目录,这件事比写任何脚本都有价值。
6.2 随时可用的备份徽章脚本:一键备份全部
为了方便起见,我后来把备份流程整合成了一个“备份徽章”脚本,所谓一键备份,说的是执行一个脚本后把镜像、数据卷、Compose文件一起处理好。
这里贴一个我的实用简化版:
#!/bin/bash # docker-backup-all.sh # 备份所有镜像 + 所有命名数据卷 + Compose配置 set -e BACKUP_ROOT="./docker-backup-$(date +%Y%m%d-%H%M%S)" mkdir -p "$BACKUP_ROOT/images" "$BACKUP_ROOT/volumes" "$BACKUP_ROOT/compose" # 1. 备份镜像 echo "==> 备份镜像" docker images --format "{{.Repository}}:{{.Tag}}" | while read -r image; do case "$image" in "<none>:<none>") continue ;; esac safe=$(echo "$image" | tr '/:' '__') docker save -o "$BACKUP_ROOT/images/${safe}.tar" "$image" done # 2. 备份命名数据卷 echo "==> 备份数据卷" for vol in $(docker volume ls -q); do echo " 卷 $vol" docker run --rm -v "$vol":/source -v "$PWD/$BACKUP_ROOT/volumes":/target alpine tar czf "/target/${vol}.tar.gz" -C /source ./ done # 3. 备份compose文件 echo "==> 备份compose文件" find . -maxdepth 2 -name "docker-compose*.yml" -o -name "docker-compose*.yaml" -o -name "compose.yaml" 2>/dev/null | while read -r f; do cp "$f" "$BACKUP_ROOT/compose/" done echo "==> 校验信息生成" (cd "$BACKUP_ROOT" && sha256sum images/*.tar volumes/*.tar.gz > checksum.sha256) echo "备份完成:$BACKUP_ROOT"这个脚本有个偷懒的地方:卷备份用了alpine容器,每次都会拉取一个很小的alpine镜像,内网环境第一次执行时如果连不了外网会卡住。提前docker pull alpine即可,或者直接改用宿主机tar命令处理bind mount。
6.3 数据卷备份的三条路,如何选?
数据卷备份看起来简单,实际上细节很多。我总结三条路:
- 命名卷用临时容器打包:最通用,但需要能跑临时容器,对正在运行的容器会有影响吗?没有,只读取卷文件。推荐。
- bind mount不用容器,直接tar宿主机目录:简单直接,但必须保证目录没有被容器写入,否则热拷贝可能不一致。建议先停容器再备份。
- 数据库类用数据库自带工具:MySQL用
mysqldump、PostgreSQL用pg_dump,先在SQL层面逻辑导出,再压缩备份。逻辑备份的好处是可移植性强,而且能规避直接复制文件带来的引擎版本兼容问题。
我自己对数据库卷一律是“双保险”:既用卷整体打包,又跑一次逻辑导出。前者图恢复快,后者图容量小、兼容性好。恢复时先用逻辑导出文件冷启动一遍,确认数据无误后再切到卷整体挂载,这样最稳。
6.4 跨Docker版本恢复的兼容性心法
如果你是从旧版本Docker导出镜像,到新版本Docker导入,一般都能正常运作,毕竟镜像格式向后兼容做得不错。但你如果反向导——新版本导出到就旧版本Docker——可能会遇到镜像架构或OCI规范不兼容问题。
举个例子,我用Docker Desktop 4.x导出的是OCI布局,老版本的Docker如果还停留在旧格式上,导入时会报“保留层失败”之类的错误。解决办法是导出前确认目标环境的Docker版本,或者干脆在目标环境上用新版Docker再拉一次远程仓库里的镜像。
跨版本恢复更稳妥的操作是:如果两端都能访问同一个Registry,直接用push/pull模式,Registry负责格式转换和存储,客户端只管拉取,兼容问题会少很多。
7. 写在最后的个人建议
最后分享一条我从重装系统里悟出来的真建议:备份不是重装前的“临时操作”,而是日常运维的一部分。
我现在给自己定了个习惯:每个月用那套一键备份脚本全量备一次,定期检查备份文件是否能成功恢复。别小看这个动作,很多人备份完了从来不验证,到了真正要用的时候才发现文件早损坏了。我就在系统迁移前发生过一次,拿着备份U盘上原封不动的tar包做恢复演练,发现校验值对不上——因为那张U盘本身就已经是劣质存储,悄悄丢数据。自此以后,每个备份产物生成后的第一时间,我一定会sha256sum -c校验一次,恢复前再校验一次。校验过的备份,才是真正有效的备份。
系统重装这件事,谁都不希望年年碰到,但一旦要面对,能提前20分钟做备份,恢复时就能少折腾两小时。希望这篇文章能帮你把“丢镜像”从重装的焦虑清单里彻底划掉。
如果动手能力强的话,还可以把备份脚本挂到cron job或者Windows计划任务里定期自动执行,再把备份目录同步到另一块硬盘或NAS上。备份守着两份,恢复的时候无论哪一份坏掉,情况都不会太糟——这算是我从多次系统迁移里捡到的最大教训了。