Docker镜像跨机器迁移工程指南
一、迁移方案概览
1.1 方案对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
docker save/load |
离线迁移、批量迁移 | 完整保存镜像层级,保留所有历史 | 文件较大,不支持增量 |
docker export/import |
容器状态迁移 | 导出容器当前状态,文件较小 | 丢失镜像历史信息 |
| Registry仓库 | 团队协作、持续部署 | 集中管理,支持版本控制 | 需要搭建仓库服务 |
docker commit+迁移 |
保存容器修改 | 保存运行时修改 | 可能包含不必要数据 |
二、docker save/load 方案(推荐)
2.1 源机器操作:导出镜像
# 1. 查看本地镜像
docker images
# 2. 导出单个镜像(推荐)
docker save -o [输出文件名].tar [镜像名]:[标签]
# 示例:
docker save -o nginx-latest.tar nginx:latest
docker save -o myapp-v1.0.tar myapp:v1.0
# 3. 导出多个镜像到单个文件
docker save -o all-images.tar nginx:latest redis:alpine mysql:5.7
# 4. 使用镜像ID导出(避免重名问题)
docker save -o image-by-id.tar fce289e99eb9
# 5. 导出并压缩(节省空间)
docker save nginx:latest | gzip > nginx-latest.tar.gz
2.2 压缩优化策略
# 方案1:gzip压缩(通用)
docker save myapp:latest | gzip > myapp-latest.tar.gz
# 方案2:pigz压缩(多核加速)
sudo apt install pigz # Ubuntu/Debian
docker save myapp:latest | pigz > myapp-latest.tar.gz
# 方案3:分卷压缩(大文件传输)
docker save large-image:latest | gzip | split -b 2G - large-image.tar.gz.part
# 方案4:评估镜像大小后再决策
docker image inspect myapp:latest --format='{{.Size}}' | \
awk '{printf "%.2f GB\n", $1/1024/1024/1024}'
2.3 传输到目标机器
# 方法1:scp(安全复制)
scp nginx-latest.tar user@目标机器IP:/目标路径/
scp -C nginx-latest.tar.gz user@192.168.1.100:/tmp/
# 方法2:rsync(断点续传、增量)
rsync -avP --progress nginx-latest.tar user@目标机器IP:/目标路径/
rsync -avPz --progress nginx-latest.tar.gz user@192.168.1.100:/tmp/
# 方法3:nc(netcat,内网快速传输)
# 接收端先监听:
nc -l 1234 > nginx-latest.tar
# 发送端:
nc 目标机器IP 1234 < nginx-latest.tar
# 方法4:HTTP服务器(多机分发)
python3 -m http.server 8000 # 在源机器启动
# 目标机器下载:
curl -O http://源机器IP:8000/nginx-latest.tar
2.4 目标机器操作:导入镜像
# 1. 基本导入
docker load -i nginx-latest.tar
# 2. 从压缩文件导入
docker load < nginx-latest.tar.gz
gzip -dc nginx-latest.tar.gz | docker load
# 3. 查看导入的镜像
docker images
# 4. 批量导入多个镜像
tar -xf all-images.tar -O | docker load
# 5. 导入后重新打标签(如果需要)
docker tag 镜像ID 新镜像名:新标签
三、Registry仓库方案(生产环境推荐)
3.1 私有仓库搭建与使用
# 1. 启动私有Registry容器
docker run -d \
-p 5000:5000 \
--name registry \
-v /data/registry:/var/lib/registry \
--restart=always \
registry:2
# 2. 标记镜像指向私有仓库
docker tag nginx:latest localhost:5000/nginx:latest
docker tag myapp:v1.0 192.168.1.100:5000/myapp:v1.0
# 3. 推送到私有仓库
docker push localhost:5000/nginx:latest
docker push 192.168.1.100:5000/myapp:v1.0
# 4. 从目标机器拉取
docker pull 192.168.1.100:5000/nginx:latest
# 5. 查看仓库中的镜像
curl http://localhost:5000/v2/_catalog
curl http://localhost:5000/v2/nginx/tags/list
3.2 安全认证配置
# 1. 创建认证文件
mkdir -p auth
docker run --rm \
--entrypoint htpasswd \
httpd:2 -Bbn username password > auth/htpasswd
# 2. 启动带认证的Registry
docker run -d \
-p 5000:5000 \
--name registry \
-v /data/registry:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
# 3. 登录认证
docker login 192.168.1.100:5000
四、高级批量操作脚本
4.1 批量导出脚本 export-images.sh
#!/bin/bash
# 批量导出所有镜像
BACKUP_DIR="./docker-backup-$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR
echo "开始导出Docker镜像..."
# 导出所有镜像
docker images --format "{{.Repository}}:{{.Tag}}" | while read image
do
if [[ "$image" != "<none>:<none>" ]]; then
echo "正在导出: $image"
filename=$(echo $image | sed 's/[\/:]/-/g')
docker save $image | gzip > "$BACKUP_DIR/${filename}.tar.gz"
fi
done
echo "导出完成!文件保存在: $BACKUP_DIR"
echo "总大小: $(du -sh $BACKUP_DIR | cut -f1)"
4.2 批量导入脚本 import-images.sh
#!/bin/bash
# 批量导入镜像
IMPORT_DIR="$1"
if [[ -z "$IMPORT_DIR" || ! -d "$IMPORT_DIR" ]]; then
echo "用法: $0 [镜像目录]"
exit 1
fi
echo "开始导入Docker镜像..."
for file in $IMPORT_DIR/*.tar.gz; do
if [[ -f "$file" ]]; then
echo "正在导入: $(basename $file)"
gunzip -c "$file" | docker load
fi
done
echo "导入完成!"
docker images
4.3 镜像同步工具 sync-images.sh
#!/bin/bash
# 同步镜像到远程机器
REMOTE_USER="user"
REMOTE_HOST="192.168.1.100"
REMOTE_PATH="/tmp/docker-images"
IMAGE_LIST=("nginx:latest" "redis:alpine")
# 1. 在远程创建目录
ssh $REMOTE_USER@$REMOTE_HOST "mkdir -p $REMOTE_PATH"
# 2. 导出并传输每个镜像
for image in "${IMAGE_LIST[@]}"; do
echo "处理镜像: $image"
# 导出镜像
filename=$(echo $image | sed 's/[\/:]/-/g').tar
docker save -o $filename $image
# 传输到远程
scp $filename $REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/
# 在远程导入
ssh $REMOTE_USER@$REMOTE_HOST "docker load -i $REMOTE_PATH/$filename"
# 清理本地文件
rm $filename
done
echo "镜像同步完成!"
五、验证与最佳实践
5.1 完整性验证
# 1. 导出后验证
sha256sum nginx-latest.tar > nginx-latest.tar.sha256
# 2. 传输后验证
scp nginx-latest.tar.sha256 user@目标机器IP:/tmp/
ssh user@目标机器IP "cd /tmp && sha256sum -c nginx-latest.tar.sha256"
# 3. 导入后验证
docker images --digests | grep nginx
docker inspect nginx:latest --format='{{.Id}}'
5.2 空间清理
# 1. 清理传输文件
rm -f *.tar *.tar.gz
# 2. 清理无用镜像
docker image prune -f
# 3. 清理悬空镜像
docker image prune -a -f
# 4. 清理构建缓存
docker builder prune -f
5.3 性能优化建议
- 网络优化 ```bash # 使用压缩传输 scp -C source.tar user@host:/path/
# 调整docker守护进程并行下载数 echo '{"max-concurrent-downloads": 3}' > /etc/docker/daemon.json ```
- 磁盘优化 ```bash # 导出前清理不必要的层 docker export | docker import
# 使用小基础镜像 FROM alpine:latest # 而非 ubuntu:latest ```
- 批量操作优化
bash # 并行导出 parallel -j 4 docker save {} \| gzip \> {}.tar.gz ::: $(docker images -q)
六、故障排查
常见问题及解决方案
- 空间不足 ```bash # 检查磁盘空间 df -h
# 清理docker缓存 docker system df docker system prune -af ```
- 导入失败 ```bash # 检查文件完整性 tar -tf image.tar | head
# 检查docker版本兼容性 docker version
# 尝试重新导出 docker save --format docker-archive -o new-image.tar image:tag ```
- 权限问题 ```bash # 使用sudo sudo docker load -i image.tar
# 或将用户加入docker组 sudo usermod -aG docker $USER ```
七、自动化流程示例
# docker-compose迁移示例
version: '3.8'
services:
# 源服务定义
app:
image: myapp:${TAG:-latest}
build: .
# 导出任务
exporter:
image: alpine
command: >
sh -c "
apk add --no-cache docker &&
docker save myapp:latest | gzip > /backup/myapp.tar.gz"
volumes:
- ./backup:/backup
- /var/run/docker.sock:/var/run/docker.sock
总结建议
场景选择指南:
- 开发环境迁移:使用
docker save/load+ 压缩 - 生产环境部署:使用私有Registry + 版本标签
- 持续集成/持续部署:Registry + 自动化脚本
- 大规模集群:Registry镜像仓库 + 分布式存储
关键检查点:
- [ ] 镜像完整性验证(SHA256校验)
- [ ] 磁盘空间充足(源端和目标端)
- [ ] 网络带宽评估(大镜像分时段传输)
- [ ] 版本兼容性(Docker版本匹配)
- [ ] 安全策略(镜像来源可信)
通过本指南,您可以系统化地进行Docker镜像的跨机器迁移操作,确保迁移过程的可靠性、高效性和可追溯性。