马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
Docker 镜像导出为本地文件与离线导入的完整做法
平时拉镜像靠配国内镜像源加速就够了,但有两类场景绕不开"导出再拷过去":一是目标机器完全不能上网,只能从能联网的机器下好镜像、拷到离线机器;二是镜像只存在于私有仓库或内网 registry,外部根本拉不到。这两种情况都用 docker save 导出、docker load 导入就能解决。
一、把镜像保存为本地文件
1. 先看现有镜像
docker images
列出当前机器上已有的全部镜像,记下名字和 tag。
2. 导出为 tar 文件
两个要点要先记住:
- 产物必须是 tar 类型文件。
- 导出指令里如果用的是镜像 ID,导出的 tar 恢复后
REPOSITORY 和 TAG 会显示为 none,需要再用镜像 ID 重新打标签;如果用的是镜像名则没有这个问题。
导出方式一,用 -o 指定输出文件:
# 导出到 /data/docker/nginx_latest.tar,文件名必须是 tar 类型,可以带路径
docker save -o /data/docker/nginx_latest.tar nginx
其中 nginx 是要导出的镜像(名称或 ID 均可,名称后面可以跟 TAG 指定版本)。
导出方式二,用重定向:
docker save nginx > nginx_latest01.tar
两种方式效果一样,都会在本地生成 nginx_latest.tar 和 nginx_latest01.tar。实际生产更推荐 -o,路径和文件名一目了然,重定向时如果忘了写重定向符号会直接把内容刷到终端里。
走镜像 ID 导出,用来验证上面那条注意点:
docker save -o nginx_latest_byID.tar 89da1fb6dcb9
这个 tar 用 docker load 导回来时就会出现 REPOSITORY/TAG = none,需要手动 docker tag 补标签。
二、把本地文件载入 Docker
把导好的 tar 复制到目标机器(scp、U 盘、内网传输都行),然后导入:
方式一,标准输入:
docker load < nginx_latest.tar
方式二,指定输入文件:
docker load --input nginx_latest.tar
第二种写法本质上和第一种一样。用方式一时可以配合管道,一边 cat 一边导,适合单文件传输的场景。
再强调一次 ID 导出的问题:如果把 nginx_latest_byID.tar 导进来,docker images 里看到的是 <none> 一行。补标签:
docker tag 89da1fb6dcb9 nginx:latest
补完就能正常 run 了。
三、批量导出与批量导入脚本
3.1 批量导出脚本 save_images.sh
#!/bin/bash
# 取出 "image:tag" 格式的镜像全名
IMG_NAME=`docker images | grep -v TAG | awk '{print $1":"$2}'`
# 镜像名里含 "/" 的转成 "_",避免做文件名
echo $IMG_NAME | awk '{gsub(/\//,"\n",$0)}{print $0}'
# 定义镜像存放目录
DIR="/data/docker/image_save"
if [ ! -d "$DIR" ]; then
echo -e "\033[34m${DIR}\033[0m 不存在"
mkdir -p "$DIR"
echo -e "\033[34m${DIR}\033[0m 已创建"
else
echo -e "\033[34m${DIR}\033[0m 已存在"
fi
echo ""
for IMAGE in $IMG_NAME
do
echo -e "正在保存 \033[33m${IMAGE}\033[0m"
SAVE_NAME=`echo $IMAGE | awk -F: '{print $1"_"$2}' | sed 's/\//_/g'`
docker save $IMAGE -o ${DIR}/${SAVE_NAME}.tar
echo -e "已保存到 \033[34m${DIR}/\033[31m${SAVE_NAME}.tar\033[0m"
echo ""
done
脚本要点:grep -v TAG 是为了去掉 docker images 表头那行 REPOSITORY TAG ...;gsub 把仓库名里的斜杠换成下划线,否则私有仓库的 registry:5000/team/app 直接拿来当文件名会出问题;最后用 -F: 把 name 和 tag 拼成保存文件名。
保存后给执行权限(演示环境图省事直接 777,生产建议按最小权限给):
chmod 777 save_images.sh
3.2 批量导入脚本 load_images.sh
#!/bin/bash
# 这里填镜像文件的存放目录
IMAGE_DIR="/data/docker/image_save"
for IMAGE in `ls $IMAGE_DIR`
do
echo -e "正在导入镜像 \033[33m$IMAGE\033[0m"
docker load -i ${IMAGE_DIR}/${IMAGE}
echo -e "已成功导入镜像 \033[33m$IMAGE\033[0m"
echo ""
done
四、容易出现的问题
- 导出后
docker images 找不到:先看 docker load 的输出,是否报镜像已存在而跳过;确认文件完整(tar tf xxx.tar 能列出层目录)。
- 导入后 tag 是 none:导出时用了镜像 ID,补一条
docker tag <id> 名字:版本。
- 磁盘空间不够:多镜像同时导出很容易撑爆 /var/lib/docker,先
df -h 看一眼,导完用 docker image prune 清理无用层。
- 跨架构拷过去跑不了:在 arm 机器上导出的 tar 拷到 amd64 机器上,镜像能导入但容器启动会报 exec format error,导出前确认架构一致。
- 离线机内核模块缺失:镜像能导入但依赖的内核模块目标机没有,这类问题 save/load 解决不了,得换镜像或补驱动。
小结
离线环境分发镜像的核心操作就两条:docker save -o 文件.tar 镜像名 导出,docker load -i 文件.tar 导入。批量场景用上面两个脚本,一个遍历 docker images 全量导出到指定目录,一个遍历目录全量导入。唯一要留心的坑是镜像 ID 导出会导致 REPOSITORY/TAG 变成 none,要么导出时用镜像名,要么导入后补一条 docker tag。
qidao123.com企服评测-应用市场 编辑提示 |