






















# 方法一:直接打包所有镜像
docker save $(docker images -q) -o all_images.tar
# 方法二:包含标签信息
docker save $(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>") -o all_images.tar
# 方法三:包含所有,包括没有标签的镜像
docker images --format "{{.Repository}}:{{.Tag}}" | xargs docker save -o all_images.tar
#!/bin/bash
# save-all-images.sh
# 设置输出文件名
OUTPUT_FILE="all_docker_images_$(date +%Y%m%d_%H%M%S).tar"
echo "开始收集所有镜像..."
# 获取所有镜像列表,处理特殊字符
IMAGE_LIST=()
while IFS= read -r line; do
# 跳过空行和表头
if [[ -n "$line" && ! "$line" =~ ^REPOSITORY ]]; then
# 提取镜像名和标签
repo_tag=$(echo "$line" | awk '{print $1":"$2}')
# 跳过 <none>:<none>
if [[ "$repo_tag" != "<none>:<none>" ]]; then
IMAGE_LIST+=("$repo_tag")
fi
fi
done < <(docker images)
# 如果镜像列表为空
if [ ${#IMAGE_LIST[@]} -eq 0 ]; then
echo "没有找到任何镜像"
exit 1
fi
echo "找到 ${#IMAGE_LIST[@]} 个镜像:"
printf '%s\n' "${IMAGE_LIST[@]}"
echo "正在打包到 $OUTPUT_FILE ..."
# 方法A:逐个打包再合并(适用于大量镜像)
if false; then
# 创建临时目录
TEMP_DIR=$(mktemp -d)
echo "使用临时目录: $TEMP_DIR"
# 逐个保存镜像
for image in "${IMAGE_LIST[@]}"; do
echo "保存: $image"
# 替换特殊字符作为文件名
safe_name=$(echo "$image" | tr '/:' '_-')
docker save "$image" -o "$TEMP_DIR/${safe_name}.tar"
done
# 合并所有tar文件
tar -cf "$OUTPUT_FILE" -C "$TEMP_DIR" .
# 清理临时文件
rm -rf "$TEMP_DIR"
else
# 方法B:一次性保存(推荐,但可能命令行过长)
docker save "${IMAGE_LIST[@]}" -o "$OUTPUT_FILE"
fi
# 验证文件
echo "打包完成!"
echo "文件大小: $(du -h "$OUTPUT_FILE" | cut -f1)"
echo "文件信息:"
file "$OUTPUT_FILE"
#!/bin/bash
# docker-save-all.sh
set -e
# 配置
BACKUP_DIR="${BACKUP_DIR:-/tmp/docker-backup}"
OUTPUT_FILE="${BACKUP_DIR}/docker-images-$(date +%Y%m%d-%H%M%S).tar"
LOG_FILE="${BACKUP_DIR}/backup-$(date +%Y%m%d-%H%M%S).log"
# 创建备份目录
mkdir -p "$BACKUP_DIR"
echo "========================================" | tee -a "$LOG_FILE"
echo "Docker 镜像备份开始: $(date)" | tee -a "$LOG_FILE"
echo "========================================" | tee -a "$LOG_FILE"
# 1. 获取镜像列表
echo "1. 获取镜像列表..." | tee -a "$LOG_FILE"
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>")
IMAGE_COUNT=$(echo "$IMAGES" | wc -l)
echo "找到 $IMAGE_COUNT 个镜像" | tee -a "$LOG_FILE"
echo "$IMAGES" | tee -a "$LOG_FILE"
if [ "$IMAGE_COUNT" -eq 0 ]; then
echo "没有镜像需要备份" | tee -a "$LOG_FILE"
exit 0
fi
# 2. 保存镜像列表到文件(用于恢复时参考)
echo "$IMAGES" > "${BACKUP_DIR}/image-list.txt"
# 3. 获取镜像详细信息
echo "2. 获取镜像详细信息..." | tee -a "$LOG_FILE"
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Size}}" > "${BACKUP_DIR}/image-details.txt"
# 4. 打包所有镜像
echo "3. 开始打包镜像..." | tee -a "$LOG_FILE"
echo "输出文件: $OUTPUT_FILE" | tee -a "$LOG_FILE"
start_time=$(date +%s)
# 使用 tee 命令同时输出到文件和屏幕
{
echo "开始保存镜像..."
docker save $(echo "$IMAGES") -o "$OUTPUT_FILE"
} 2>&1 | tee -a "$LOG_FILE"
end_time=$(date +%s)
duration=$((end_time - start_time))
# 5. 验证打包结果
echo "4. 验证打包文件..." | tee -a "$LOG_FILE"
if [ -f "$OUTPUT_FILE" ]; then
file_size=$(du -h "$OUTPUT_FILE" | cut -f1)
echo "文件大小: $file_size" | tee -a "$LOG_FILE"
# 检查tar文件是否有效
if tar -tf "$OUTPUT_FILE" &>/dev/null; then
echo "✓ Tar 文件格式正确" | tee -a "$LOG_FILE"
tar_count=$(tar -tf "$OUTPUT_FILE" | grep "manifest.json" | wc -l)
echo "包含 $tar_count 个镜像" | tee -a "$LOG_FILE"
else
echo "✗ Tar 文件损坏" | tee -a "$LOG_FILE"
exit 1
fi
else
echo "✗ 输出文件不存在" | tee -a "$LOG_FILE"
exit 1
fi
echo "========================================" | tee -a "$LOG_FILE"
echo "备份完成!" | tee -a "$LOG_FILE"
echo "总耗时: ${duration}秒" | tee -a "$LOG_FILE"
echo "输出文件: $OUTPUT_FILE" | tee -a "$LOG_FILE"
echo "日志文件: $LOG_FILE" | tee -a "$LOG_FILE"
echo "镜像列表: ${BACKUP_DIR}/image-list.txt" | tee -a "$LOG_FILE"
echo "镜像详情: ${BACKUP_DIR}/image-details.txt" | tee -a "$LOG_FILE"
echo "========================================" | tee -a "$LOG_FILE"
#!/bin/bash
# save-docker-images-batch.sh
# 配置
MAX_ARGS=20 # 每次传递的最大镜像数,避免参数过长
OUTPUT_BASE="docker-images-backup"
# 创建备份目录
BACKUP_DIR="${OUTPUT_BASE}-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
echo "备份目录: $BACKUP_DIR"
# 获取所有镜像
mapfile -t IMAGES < <(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>")
TOTAL=${#IMAGES[@]}
echo "总共 $TOTAL 个镜像需要备份"
# 分批处理
BATCH=0
for ((i=0; i<TOTAL; i+=MAX_ARGS)); do
BATCH=$((BATCH+1))
END_INDEX=$((i+MAX_ARGS))
if [ $END_INDEX -gt $TOTAL ]; then
END_INDEX=$TOTAL
fi
# 获取当前批次的镜像
BATCH_IMAGES=("${IMAGES[@]:i:MAX_ARGS}")
echo "处理第 $BATCH 批: ${#BATCH_IMAGES[@]} 个镜像"
echo "镜像列表: ${BATCH_IMAGES[*]}"
# 保存当前批次
OUTPUT_FILE="$BACKUP_DIR/batch-${BATCH}.tar"
docker save "${BATCH_IMAGES[@]}" -o "$OUTPUT_FILE"
# 验证
if [ -s "$OUTPUT_FILE" ]; then
size=$(du -h "$OUTPUT_FILE" | cut -f1)
echo "✓ 批次 $BATCH 完成: $size"
else
echo "✗ 批次 $BATCH 失败"
fi
done
# 创建合并脚本
cat > "$BACKUP_DIR/load-all.sh" << 'EOF'
#!/bin/bash
echo "加载所有Docker镜像..."
for tar_file in batch-*.tar; do
echo "加载: $tar_file"
docker load -i "$tar_file"
done
echo "完成!"
EOF
chmod +x "$BACKUP_DIR/load-all.sh"
# 创建恢复说明
cat > "$BACKUP_DIR/README.txt" << EOF
Docker 镜像备份
备份时间: $(date)
镜像总数: $TOTAL
批次数量: $BATCH
恢复方法:
1. 将所有 batch-*.tar 文件复制到目标机器
2. 运行: ./load-all.sh
3. 或者逐个加载: docker load -i batch-*.tar
镜像列表:
$(printf '%s\n' "${IMAGES[@]}")
EOF
echo "备份完成! 目录: $BACKUP_DIR"
echo "恢复时请运行: cd '$BACKUP_DIR' && ./load-all.sh"
# 直接打包并压缩
docker save $(docker images -q) | gzip > all_images.tar.gz
# 或者使用并行压缩(更快)
docker save $(docker images -q) | pigz -9 > all_images.tar.gz
# 完整脚本
#!/bin/bash
OUTPUT="docker-images-$(date +%Y%m%d).tar.gz"
echo "打包并压缩所有镜像到 $OUTPUT ..."
docker save $(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>") | gzip -c > "$OUTPUT"
echo "完成! 文件大小: $(du -h $OUTPUT | cut -f1)"
# 从tar文件恢复所有镜像
docker load -i all_images.tar
# 如果使用gzip压缩
gunzip -c all_images.tar.gz | docker load
# 或者
docker load < all_images.tar.gz
# 从分批次备份恢复
for tar_file in batch-*.tar; do
echo "Loading $tar_file..."
docker load -i "$tar_file"
done
#!/bin/bash
# docker-backup-manager.sh
ACTION="$1"
BACKUP_FILE="${2:-docker-images-backup.tar}"
case "$ACTION" in
"save"|"backup"|"export")
echo "备份所有Docker镜像到 $BACKUP_FILE ..."
IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>")
if [ -z "$IMAGES" ]; then
echo "没有找到任何镜像"
exit 1
fi
echo "备份以下镜像:"
echo "$IMAGES"
docker save $IMAGES -o "$BACKUP_FILE"
echo "备份完成!"
echo "文件大小: $(du -h $BACKUP_FILE | cut -f1)"
;;
"load"|"restore"|"import")
if [ ! -f "$BACKUP_FILE" ]; then
echo "错误: 备份文件 $BACKUP_FILE 不存在"
exit 1
fi
echo "从 $BACKUP_FILE 恢复Docker镜像..."
docker load -i "$BACKUP_FILE"
echo "恢复完成!"
;;
"list")
echo "当前Docker镜像:"
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}"
;;
"info")
if [ -f "$BACKUP_FILE" ]; then
echo "备份文件信息:"
echo "大小: $(du -h $BACKUP_FILE | cut -f1)"
echo "修改时间: $(stat -c %y $BACKUP_FILE)"
# 列出tar中的镜像
echo "包含的镜像:"
tar -xf "$BACKUP_FILE" -O manifest.json 2>/dev/null | jq -r '.[].RepoTags[]' 2>/dev/null || \
echo "无法读取镜像列表,可能格式不支持"
else
echo "备份文件不存在"
fi
;;
*)
echo "用法: $0 {save|load|list|info} [备份文件]"
echo "示例:"
echo " $0 save # 备份到 docker-images-backup.tar"
echo " $0 save my-backup.tar # 备份到指定文件"
echo " $0 load # 从默认文件恢复"
echo " $0 load my-backup.tar # 从指定文件恢复"
echo " $0 list # 列出当前镜像"
echo " $0 info # 查看备份文件信息"
exit 1
;;
esac
# Dockerfile.backup
FROM alpine:latest
RUN apk add --no-cache docker-cli
COPY backup.sh /backup.sh
RUN chmod +x /backup.sh
ENTRYPOINT ["/backup.sh"]
# backup.sh
#!/bin/sh
# 挂载Docker socket,备份所有镜像
docker save $(docker images -q) -o /backup/images.tar
echo "备份完成!"
最简单的单行命令
# 备份所有镜像
docker save $(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>") -o all-images.tar
# 恢复所有镜像
docker load -i all-images.tar
注意事项
权限问题:确保有足够的磁盘空间
镜像数量:如果有大量镜像,考虑分批处理
特殊字符:镜像名中的特殊字符可能需要处理
版本兼容性:备份的镜像在不同Docker版本间可能有限制
推荐使用第3个脚本(高级脚本),它包含验证和日志记录,更安全可靠。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。