服务器不能访问 Docker Hub,镜像怎么搬过去?讲透 docker save、load、export、import 与离线镜像分发

很多人第一次遇到离线服务器部署 Docker,会想到一个最直接的问题:

这台服务器访问不了 Docker Hub,我能不能在另一台电脑把镜像下载好,然后拷过去?

当然可以。

比如本地:

bash 复制代码
docker pull nginx:latest

已经下载成功。

目标服务器:

text 复制代码
没有公网

访问 Docker Hub 超时

不能配置代理

甚至完全隔离网络

那最简单的思路就是:

text 复制代码
有网机器
↓
docker pull
↓
打包镜像
↓
U盘 / SCP / 内网
↓
目标服务器
↓
导入镜像
↓
docker run

Docker 自己就提供了:

text 复制代码
docker save
docker load

专门解决这个问题。

但很多人继续搜索以后,又会发现另外两个命令:

text 复制代码
docker export
docker import

然后彻底懵了:

save 和 export 都能生成 tar,到底有什么区别?
load 和 import 又有什么区别?

如果命令用错,确实都可能得到一个:

text 复制代码
.tar

文件。

但里面保存的东西:

完全不是一回事。

今天继续围绕:

text 复制代码
https://github.com/Rodert/DockerHub

把 Docker 离线镜像分发彻底讲清楚。

核心就四个命令:

text 复制代码
docker save
docker load

docker export
docker import

如果只想提前知道结论:

搬 Docker 镜像,通常用 save + load。

搬某个 Container 当前文件系统,才考虑 export + import。


一、先看最标准的离线部署流程

假设目标服务器需要:

text 复制代码
nginx:latest
redis:7
mysql:8.4

但是服务器:

text 复制代码
无法访问 Docker Hub。

先在一台可以联网的机器:

bash 复制代码
docker pull nginx:latest

docker pull redis:7

docker pull mysql:8.4

确认:

bash 复制代码
docker images

看到:

text 复制代码
nginx   latest

redis   7

mysql   8.4

然后:

bash 复制代码
docker save \
  -o images.tar \
  nginx:latest \
  redis:7 \
  mysql:8.4

Docker 官方当前对 docker image save 的定义就是:把一个或多个 Image 保存到 tar Archive,同时保留对应 Image 的父层、Tag 和版本信息。

现在得到:

text 复制代码
images.tar

二、把 tar 拷到目标服务器

比如:

bash 复制代码
scp images.tar \
  root@192.168.1.100:/tmp/

或者:

text 复制代码
U盘

移动硬盘

NAS

内网文件服务器

都可以。

目标服务器:

bash 复制代码
docker load \
  -i /tmp/images.tar

Docker 官方当前说明,docker load 可以从 tar 文件或者标准输入中载入 Image Repository,并恢复其中的 Image 和 Tag。

完成后:

bash 复制代码
docker images

应该重新看到:

text 复制代码
nginx   latest

redis   7

mysql   8.4

服务器:

全程不需要访问 Docker Hub。


三、这就是最核心的一对

text 复制代码
docker save
        ↓
   image.tar
        ↓
docker load

它操作的对象:

Docker Image。

所以你要:

text 复制代码
备份镜像

搬镜像

离线安装镜像

把一批 Image 送进内网

基本第一反应都应该是:

save / load。


四、docker save 保存的到底是什么?

例如:

bash 复制代码
docker save \
  nginx:latest \
  -o nginx.tar

里面不是简单:

text 复制代码
nginx 的最终 rootfs。

它会保留镜像本身的:

text 复制代码
Layer

Image Metadata

Tag

Repository Information

Docker 官方当前明确指出,docker save 会生成一个 tar Repository,其中包括父 Layer,以及被保存 Image 对应的 Tag/Version 信息。

这点非常关键。


五、为什么 Layer 要保留?

因为我们前面讲过:

text 复制代码
Docker Image

不是:

text 复制代码
一个最终目录压缩包。

而是:

text 复制代码
Manifest
+
Config
+
Layer 1
+
Layer 2
+
Layer 3

这些 Layer:

text 复制代码
有 Digest

可以复用

可以共享

save/load:

尽量保持 Image 的 Docker 镜像语义。


六、这有什么好处?

比如你保存:

text 复制代码
myapp:v1
myapp:v2

两者共享:

text 复制代码
Ubuntu Base

Node Runtime

npm dependencies

那么:

text 复制代码
公共 Layer

不需要在 tar 里无脑复制成两套完全独立文件系统。

Docker:

text 复制代码
知道哪些 Layer 是共享的。

这就是 Image Format 本身的价值。


七、Tag 也会保留

例如:

bash 复制代码
docker save \
  -o myapp.tar \
  mycompany/app:1.0 \
  mycompany/app:1.1

目标机器:

bash 复制代码
docker load \
  -i myapp.tar

可以恢复:

text 复制代码
mycompany/app:1.0

mycompany/app:1.1

而不是只剩:

text 复制代码
一个不知道叫什么的 rootfs。

所以:

做正式离线镜像交付时,save/load 更符合预期。


八、甚至可以一次保存很多镜像

例如一个完整 Compose:

yaml 复制代码
services:

  nginx:
    image: nginx:1.28

  redis:
    image: redis:7

  mysql:
    image: mysql:8.4

  api:
    image: mycompany/api:1.5

你完全可以:

bash 复制代码
docker save \
  -o production-images.tar \
  nginx:1.28 \
  redis:7 \
  mysql:8.4 \
  mycompany/api:1.5

交付给目标环境。

然后:

bash 复制代码
docker load \
  -i production-images.tar

最后:

bash 复制代码
docker compose up \
  -d \
  --pull never

整个生产服务器:

可以完全不碰公网 Registry。


九、为什么这里建议 --pull never?

因为镜像:

text 复制代码
已经提前 load。

你既然是:

text 复制代码
离线部署。

就没有必要让 Compose:

text 复制代码
再尝试 Registry。

所以:

bash 复制代码
docker compose up \
  -d \
  --pull never

表达非常明确:

只使用本地已经导入的镜像。


十、这就可以形成标准离线发布包

例如:

text 复制代码
release-1.5.0/
│
├── docker-compose.yml
│
├── images.tar
│
├── .env.example
│
├── install.sh
└── README.md

客户拿到:

text 复制代码
release-1.5.0.tar.gz

解压:

bash 复制代码
tar -xzvf \
  release-1.5.0.tar.gz

执行:

bash 复制代码
bash install.sh

十一、install.sh 可以很简单

bash 复制代码
#!/usr/bin/env bash

set -e

echo "[1/3] Load images..."

docker load \
  -i images.tar


echo "[2/3] Start services..."

docker compose up \
  -d \
  --pull never


echo "[3/3] Status..."

docker compose ps

这样用户:

text 复制代码
不需要知道 Docker Hub

不需要知道 Mirror

不需要知道 Registry。

真正做到:

离线一键部署。


十二、images.tar 会不会特别大?

会。

例如:

text 复制代码
mysql
800MB

api
1GB

node
1GB

一个发布包:

text 复制代码
几 GB

很正常。

但注意:

text 复制代码
docker save

默认生成:

Tar Archive。

并不是:

text 复制代码
追求最大压缩率的发布文件。

所以我们通常还可以压缩。


十三、最简单 gzip

bash 复制代码
docker save \
  nginx:latest \
  redis:7 \
  | gzip \
  > images.tar.gz

目标:

bash 复制代码
gzip -dc images.tar.gz \
  | docker load

Docker 当前 docker load 也支持读取 gzip、bzip2、xz 和 zstd 压缩的 Archive。

所以甚至可以直接:

bash 复制代码
docker load \
  -i images.tar.gz

十四、也可以 zstd

例如:

bash 复制代码
docker save \
  nginx:latest \
  redis:7 \
  | zstd -T0 \
  > images.tar.zst

目标:

bash 复制代码
docker load \
  -i images.tar.zst

对于大镜像:

text 复制代码
zstd

通常:

text 复制代码
压缩/解压速度

都不错。

适合:

大型离线发布包。


十五、还能边传边 Load

如果两台机器:

text 复制代码
网络互通

但目标机:

text 复制代码
无法访问 Docker Hub。

其实不一定非要:

text 复制代码
先生成 tar
↓
再 scp。

可以:

bash 复制代码
docker save \
  nginx:latest \
  redis:7 \
  | ssh root@server \
  docker load

流程:

text 复制代码
本地 Docker
↓
save stdout
↓
SSH
↓
远程 docker load

中间:

不落地 tar。


十六、再加压缩

bash 复制代码
docker save \
  nginx:latest \
  redis:7 \
  | gzip \
  | ssh root@server \
    'gzip -dc | docker load'

或者:

text 复制代码
zstd

类似操作。

对于:

text 复制代码
跳板机
内网服务器
临时搬镜像

特别方便。


十七、接下来讲最容易混淆的 docker export

假设我们启动:

bash 复制代码
docker run \
  --name demo \
  ubuntu:24.04

然后进入:

bash 复制代码
docker exec -it demo bash

在 Container 里:

bash 复制代码
apt-get update
apt-get install -y nginx

再创建:

bash 复制代码
echo hello \
  > /hello.txt

现在这个 Container:

text 复制代码
已经发生变化。

如果:

bash 复制代码
docker export demo \
  > demo.tar

它保存的是:

Container 当前文件系统内容。


十八、不是 Image Layer 结构

export 的逻辑更接近:

text 复制代码
Container 当前 root filesystem
↓
打平
↓
tar

它不关心:

text 复制代码
原来 Layer 1

Layer 2

Layer 3

哪个 Dockerfile RUN 生成了什么。

只关心:

当前看起来是什么文件系统。


十九、然后 docker import

bash 复制代码
docker import \
  demo.tar \
  mydemo:v1

会把这个:

text 复制代码
tar Filesystem

变成:

一个新的 Image。

Docker 当前对 docker image import 的定义正是:从 tarball 内容创建一个 filesystem image。

注意这个描述:

text 复制代码
filesystem image

和 save/load:

差别非常大。


二十、最直观的对比

save

输入:

text 复制代码
Image

输出:

text 复制代码
Image Archive

再:

text 复制代码
load

恢复:

text 复制代码
Image。

export

输入:

text 复制代码
Container

输出:

text 复制代码
Filesystem Tar。

再:

text 复制代码
import

创建:

text 复制代码
新的 Image。

二十一、可以用一句话记

text 复制代码
save / load
=
搬镜像
text 复制代码
export / import
=
搬容器文件系统

只要记住这句话:

大多数场景都不会选错。


二十二、为什么 export/import 不适合镜像正常备份?

假设 Image:

text 复制代码
myapp:v1

有:

text 复制代码
Layer A

Layer B

Layer C

CMD

ENTRYPOINT

ENV

WORKDIR

LABEL

你启动成 Container:

text 复制代码
demo。

然后:

bash 复制代码
docker export demo

你得到的主要是:

text 复制代码
当前 rootfs。

原来镜像:

text 复制代码
Layer History

不会按照原 Image 结构保留下来。

所以:

镜像备份不要用 export/import。


二十三、import 后启动可能发现 CMD 没了

例如原 Image:

Dockerfile 复制代码
CMD ["nginx", "-g", "daemon off;"]

export:

text 复制代码
只管文件系统。

import 以后:

bash 复制代码
docker run mydemo:v1

可能:

text 复制代码
不知道该执行什么。

这时候你需要:

bash 复制代码
docker run \
  mydemo:v1 \
  nginx -g 'daemon off;'

或者 import 时:

text 复制代码
手工重新加 Config。

二十四、docker import 可以 --change

Docker 当前支持:

text 复制代码
-c
--change

在 import 时应用部分 Dockerfile Instruction。

例如:

bash 复制代码
docker import \
  --change \
  'CMD ["nginx","-g","daemon off;"]' \
  demo.tar \
  nginx-custom:v1

但你会发现:

已经很麻烦。

原来 Image 本身就有这些 Metadata,

结果:

text 复制代码
export 打掉
↓
import 再手工补。

所以正常迁移镜像:

何必绕这个弯?

直接:

text 复制代码
save/load。

二十五、那 export/import 到底有什么用?

比如你有一个:

text 复制代码
已经运行很久的 Container。

里面:

text 复制代码
手工安装了各种软件

改了很多文件

没有 Dockerfile

没有原始镜像构建流程。

现在只是想:

把这个 Container 当前文件系统拍个快照。

export:

bash 复制代码
docker export \
  old-container \
  -o filesystem.tar

就很直接。


二十六、但这种方式不适合长期工程管理

因为:

text 复制代码
你不知道这个状态
是怎么一步一步产生的。

更好的长期方式:

text 复制代码
写 Dockerfile。

例如:

Dockerfile 复制代码
FROM ubuntu:24.04

RUN apt-get update \
    && apt-get install -y nginx

COPY nginx.conf \
  /etc/nginx/nginx.conf

CMD [
  "nginx",
  "-g",
  "daemon off;"
]

这样:

可重复构建。

而不是:

text 复制代码
靠某个 Container 手工改了一下午。

二十七、Docker 容器应该尽量 Immutable

比较理想:

text 复制代码
Image
↓
Run Container
↓
Container 出问题
↓
删掉
↓
重新创建

而不是:

text 复制代码
Container
↓
手工 SSH
↓
apt install
↓
改配置
↓
再 export 保存。

后者:

越来越像传统服务器。

Docker 的价值反而被削弱了。


二十八、再说一个非常危险的误区:Volume 不在 export 里

假设:

bash 复制代码
docker run \
  --name mysql \
  -v mysql_data:/var/lib/mysql \
  mysql:8.4

你的数据库数据:

text 复制代码
/var/lib/mysql

实际:

text 复制代码
在 Docker Volume。

你:

bash 复制代码
docker export mysql \
  > mysql.tar

就以为:

数据库备份好了。

非常危险。


二十九、Container Filesystem 和 Volume 是两套东西

结构:

text 复制代码
Container
│
├── Writable Layer
│
└── /var/lib/mysql
        ↓
      Volume

export:

text 复制代码
主要处理 Container Filesystem。

Volume:

需要单独备份。

所以:

docker export 不是数据库备份工具。


三十、Docker Image save 也不会备份 Volume

同样:

bash 复制代码
docker save mysql:8.4

只是在保存:

text 复制代码
mysql Image。

它和你运行中的:

text 复制代码
数据库数据

毫无关系。

这个概念一定要分清:

text 复制代码
Image
≠
Container Data

三十一、离线迁移一个完整业务系统,需要哪些东西?

例如 Compose:

yaml 复制代码
services:

  mysql:

    image:
      mysql:8.4

    volumes:
      - mysql_data:/var/lib/mysql

  api:

    image:
      mycompany/api:1.5

volumes:

  mysql_data:

完整迁移至少包含:

text 复制代码
1. Images

2. Compose

3. Environment Config

4. Volumes / Database Data

只:

text 复制代码
docker save

是不够的。


三十二、镜像部分

bash 复制代码
docker save \
  -o images.tar \
  mysql:8.4 \
  mycompany/api:1.5

三十三、配置部分

保存:

text 复制代码
docker-compose.yml

.env

nginx.conf

application config

当然:

text 复制代码
.env

如果有密码:

要按敏感文件管理。


三十四、数据库应该做数据库级备份

MySQL:

bash 复制代码
mysqldump ...

PostgreSQL:

bash 复制代码
pg_dump ...

通常比:

text 复制代码
直接打包整个 Volume

更加稳妥。

尤其:

text 复制代码
数据库还在运行

时。


三十五、为什么不能随便 tar 正在写的数据库目录?

因为:

text 复制代码
数据库文件

不是普通静态文件。

你复制过程中:

text 复制代码
一半属于时间点 A

另一半属于时间点 B

可能得到:

text 复制代码
不一致状态。

所以真正的数据迁移:

应该使用数据库自己的 Backup / Dump 机制。


三十六、这样整个离线发布包可以分成两个部分

text 复制代码
Application Artifact
│
├── Docker Images
├── Compose
├── Config
└── Install Scripts

和:

text 复制代码
Business Data
│
├── MySQL Dump
├── PostgreSQL Dump
└── Upload Files

不要:

混成一个"docker 备份"。


三十七、再看一个很实用的场景:从 Mac 搬镜像到 Linux Server

假设你 Mac:

text 复制代码
M4
=
ARM64

服务器:

text 复制代码
Intel
=
AMD64。

Mac 上:

bash 复制代码
docker pull nginx:latest

默认会拉:

text 复制代码
linux/arm64

然后:

bash 复制代码
docker save nginx:latest \
  -o nginx.tar

把它拿到:

text 复制代码
linux/amd64 Server

会发生什么?


三十八、这时候平台非常重要

我们上一篇刚讲过:

text 复制代码
Multi-Arch Image。

Tag:

text 复制代码
nginx:latest

背后可能同时:

text 复制代码
linux/amd64

linux/arm64。

但你本地实际 Image Store:

text 复制代码
保存了哪个 Platform

会影响:

text 复制代码
save 出去什么。

三十九、现在 docker save 已经支持 --platform

Docker 当前 docker image save 支持:

text 复制代码
--platform

来指定需要保存的 Platform,例如:

text 复制代码
linux/amd64
linux/arm64/v8

等。

例如你的目标:

text 复制代码
AMD64 Linux Server。

就应该特别注意:

bash 复制代码
docker pull \
  --platform linux/amd64 \
  nginx:latest

然后:

bash 复制代码
docker save \
  --platform linux/amd64 \
  -o nginx-amd64.tar \
  nginx:latest

四十、目标机器再 Load

bash 复制代码
docker load \
  -i nginx-amd64.tar

这样:

text 复制代码
平台明确。

避免:

text 复制代码
ARM Mac
打包 ARM Image
拿到 x86 Server

产生:

text 复制代码
platform mismatch。

四十一、docker load 现在也支持 --platform

Docker 当前的 docker image load 同样支持:

text 复制代码
--platform

用于从多平台 Archive 中只加载指定 Platform。

例如:

bash 复制代码
docker load \
  --platform linux/amd64 \
  -i myapp.tar

这个能力在:

text 复制代码
多平台离线发布包

场景非常有价值。


四十二、能不能做一个同时包含 amd64 和 arm64 的离线包?

现在是可以讨论的。

随着 Docker Engine / Docker Desktop 的 Image Store 逐渐使用 Containerd,现代 Docker 对 Multi-Platform Image 的本地存储能力已经增强;Docker 当前文档说明,Docker Desktop 和 Docker Engine 29+ 默认使用支持 Image Index / Manifest List 的 Containerd Image Store,而经典 Image Store 不支持完整的 Multi-Platform Image Index。

所以在现代环境中:

text 复制代码
Multi-Platform Save / Load

的能力比以前完整得多。

但是:

仍然必须看你的 Docker Image Store 和 Engine 版本。


四十三、老 Docker 为什么经常处理不了完整 Multi-Arch?

因为传统:

text 复制代码
Classic Image Store

本身:

text 复制代码
不支持 Image Index / Manifest List。

Docker 当前 Containerd Image Store 文档仍明确指出,经典 Image Store 不能完整保存这些多平台结构。

所以:

text 复制代码
老服务器

离线部署:

我会更保守:

明确按 Platform 打包。


四十四、比如准备两个包

text 复制代码
release-amd64/
└── images-amd64.tar.zst
text 复制代码
release-arm64/
└── images-arm64.tar.zst

客户选择:

text 复制代码
Intel / AMD Server
→ amd64
text 复制代码
ARM Server
→ arm64

这种交付方式:

最不容易出问题。


四十五、安装脚本还可以自动判断架构

例如:

bash 复制代码
ARCH=$(uname -m)

case "$ARCH" in

  x86_64)
    IMAGE_FILE="images-amd64.tar.zst"
    ;;

  aarch64|arm64)
    IMAGE_FILE="images-arm64.tar.zst"
    ;;

  *)
    echo "Unsupported architecture: $ARCH"
    exit 1
    ;;

esac

docker load \
  -i "$IMAGE_FILE"

用户:

bash 复制代码
bash install.sh

自动选择。

这就是:

真正成熟的离线安装包。


四十六、甚至 Docker 版本也可以检测

bash 复制代码
docker version

如果:

text 复制代码
Docker 不存在

提示:

text 复制代码
Please install Docker first.

如果:

text 复制代码
Docker Daemon 没启动

提示:

text 复制代码
Docker daemon is unavailable.

不要等:

text 复制代码
docker load

以后才抛一堆错误。


四十七、发布包还应该有 Checksum

比如:

text 复制代码
images-amd64.tar.zst

几 GB。

通过:

text 复制代码
U盘
网盘
内网

传输以后:

text 复制代码
有没有损坏?

可以提供:

bash 复制代码
sha256sum \
  images-amd64.tar.zst

输出:

text 复制代码
abc123...

发布:

text 复制代码
SHA256SUMS

四十八、安装前验证

bash 复制代码
sha256sum \
  -c SHA256SUMS

如果:

text 复制代码
OK

再:

text 复制代码
docker load。

这比:

text 复制代码
Load 到一半才发现 tar 损坏

友好很多。


四十九、这里的 SHA256 和 Docker Digest 是不是一回事?

不是完全一回事。

例如:

text 复制代码
images.tar.zst SHA256

是:

你这个离线发布文件的 Hash。

而:

text 复制代码
Docker Image Digest

对应:

text 复制代码
Manifest / Image 内容身份。

两个 Hash:

text 复制代码
解决不同层的问题。

五十、可以把它理解成

text 复制代码
Docker Digest
↓
证明 Image Content Identity
text 复制代码
Release File SHA256
↓
证明交付文件传输完整性

离线发布时:

两层都值得保留。


五十一、再进一步可以签名发布包

例如:

text 复制代码
SHA256SUMS

再:

text 复制代码
GPG Sign

或者:

text 复制代码
其他 Artifact Signature。

于是客户不仅知道:

text 复制代码
文件没坏。

还可以进一步验证:

text 复制代码
是谁发布的。

这又和前面讲:

text 复制代码
Cosign
Supply Chain

连起来了。


五十二、离线部署还有一个问题:Tag 是否覆盖

假设目标机原来:

text 复制代码
myapp:latest
→ Old Image

你:

bash 复制代码
docker load \
  -i new-images.tar

里面:

text 复制代码
myapp:latest
→ New Image

Tag:

text 复制代码
可能更新指向。

但是原来:

text 复制代码
已经运行中的 Container

不会因为:

text 复制代码
load 了新 Image

就自动变成新版本。


五十三、为什么?

Container 创建时:

text 复制代码
已经绑定具体 Image。

你只是:

text 复制代码
更新 Tag。

现有 Container:

text 复制代码
还是那个 Container。

所以 Load 完:

bash 复制代码
docker compose up \
  -d \
  --pull never

让 Compose:

text 复制代码
根据新 Image
重新创建需要更新的 Service。

五十四、不要只 docker compose restart

例如:

bash 复制代码
docker load \
  -i app-v2.tar

docker compose restart

restart:

text 复制代码
只是重启旧 Container。

并不会自动:

text 复制代码
根据新 Image 创建新 Container。

所以标准离线升级:

text 复制代码
Load New Image
↓
Compose Up
↓
Recreate

更合理。


五十五、生产版本最好不要用 latest

离线发布更应该:

text 复制代码
myapp:1.5.0

而不是:

text 复制代码
myapp:latest。

因为发布包:

text 复制代码
release-1.5.0

里面:

text 复制代码
myapp:1.5.0

一一对应。

将来:

text 复制代码
release-1.5.1

就是:

text 复制代码
myapp:1.5.1。

版本关系:

非常清晰。


五十六、回滚也容易

当前:

text 复制代码
1.5.1

有问题。

本地还有:

text 复制代码
myapp:1.5.0。

Compose:

yaml 复制代码
image:
  myapp:1.5.0

然后:

bash 复制代码
docker compose up \
  -d \
  --pull never

即可。

如果旧 Image:

text 复制代码
已经被 prune。

可以重新:

bash 复制代码
docker load \
  -i release-1.5.0/images.tar

再回滚。

这就是:

离线 Artifact Archive。


五十七、甚至可以保留每个 Release

例如:

text 复制代码
releases/
│
├── 1.4.0/
│   └── images.tar.zst
│
├── 1.5.0/
│   └── images.tar.zst
│
└── 1.5.1/
    └── images.tar.zst

这相当于:

一个非常朴素的离线 Registry。

当然规模大以后:

text 复制代码
还是应该上 Harbor / Registry。

但小规模交付:

text 复制代码
特别实用。

五十八、什么时候不应该使用 save/load?

如果你有:

text 复制代码
50 台

100 台

500 台

服务器。

每次发布:

text 复制代码
给每台 SCP 5GB tar。

效率会越来越低。

这时候:

text 复制代码
内网 Registry

明显更合理。


五十九、小规模

text 复制代码
1~5 台机器

save/load:

非常简单。


六十、中等规模

text 复制代码
几十台机器

可以:

text 复制代码
Internal Registry

例如:

text 复制代码
Distribution
Harbor

节点:

text 复制代码
统一 pull。

六十一、完全离线企业环境

可以:

text 复制代码
联网区
↓
下载 / 扫描 / 签名
↓
离线介质
↓
隔离区 Registry
↓
内网服务器

而不是:

text 复制代码
每台服务器单独 load tar。

这种:

Offline Registry

更专业。


六十二、典型 Air-Gapped 架构

text 复制代码
Internet
   │
   ↓
Staging Machine
   │
   │ Pull / Scan
   ↓
Offline Package
   │
   │ USB / Controlled Transfer
   ↓
Air-Gapped Network
   │
   ↓
Internal Harbor
   │
   ├── Server A
   ├── Server B
   └── Kubernetes

这里:

text 复制代码
save/load

更像:

跨安全边界的运输手段。

而不是最终:

text 复制代码
所有机器都靠 tar。

六十三、这个思路特别适合政企内网

例如:

text 复制代码
生产区
不能访问互联网。

开发区:

text 复制代码
可以联网。

流程:

text 复制代码
开发区

docker pull
↓
安全扫描
↓
固定 Digest
↓
docker save
↓
SHA256
↓
审批
↓
物理介质
↓
生产区
↓
docker load / Internal Registry

每一步:

都可以审计。


六十四、这就不只是"传一个 tar"

而是:

Artifact Promotion。

镜像从:

text 复制代码
Public Internet

进入:

text 复制代码
Trusted Internal Environment。

中间经过:

text 复制代码
扫描
验证
审批
记录

这就是:

企业软件供应链。


六十五、Rodert/DockerHub 项目可以增加离线包功能

例如用户输入:

text 复制代码
nginx:1.28

redis:7

mysql:8.4

工具生成:

bash 复制代码
docker pull \
  --platform linux/amd64 \
  nginx:1.28

docker pull \
  --platform linux/amd64 \
  redis:7

docker pull \
  --platform linux/amd64 \
  mysql:8.4

然后:

bash 复制代码
docker save \
  --platform linux/amd64 \
  -o docker-images.tar \
  nginx:1.28 \
  redis:7 \
  mysql:8.4

用户:

直接复制执行。


六十六、再生成压缩命令

bash 复制代码
zstd -T0 \
  docker-images.tar \
  -o docker-images.tar.zst

生成:

bash 复制代码
sha256sum \
  docker-images.tar.zst \
  > SHA256SUMS

目标:

bash 复制代码
sha256sum -c SHA256SUMS

docker load \
  -i docker-images.tar.zst

这样你的网站:

从镜像地址工具变成离线交付工具。


六十七、还能生成不同平台的安装包

用户选择:

text 复制代码
目标平台:

○ Linux AMD64

○ Linux ARM64

生成:

text 复制代码
--platform linux/amd64

或者:

text 复制代码
--platform linux/arm64

这和上一篇:

text 复制代码
Multi-Arch Checker

正好联动。


六十八、甚至可以自动分析 Compose

用户上传:

yaml 复制代码
services:

  nginx:
    image:
      nginx:1.28

  redis:
    image:
      redis:7

  api:
    image:
      mycompany/api:1.5

工具自动提取:

text 复制代码
3 个 Image。

然后生成:

bash 复制代码
docker pull ...

docker save ...

最终:

text 复制代码
offline-bundle.tar.zst

这会非常实用。


六十九、还可以检查是否有 build

比如 Compose:

yaml 复制代码
services:

  api:

    build:
      .

却没有:

text 复制代码
image:

工具提示:

text 复制代码
⚠️ 当前 Service 只有 build,
没有明确 Image Tag。

制作离线发布包前,
建议先 Build 并 Tag。

例如:

bash 复制代码
docker build \
  -t mycompany/api:1.5 \
  .

然后:

text 复制代码
加入 save。

七十、离线部署脚本甚至可以做 Preflight

比如:

bash 复制代码
#!/usr/bin/env bash

set -e

command -v docker \
  >/dev/null \
  || {
    echo "Docker not found"
    exit 1
  }

docker info \
  >/dev/null \
  || {
    echo "Docker daemon unavailable"
    exit 1
  }

sha256sum \
  -c SHA256SUMS

docker load \
  -i images.tar.zst

docker compose \
  up \
  -d \
  --pull never \
  --wait

整个流程:

text 复制代码
环境检查
↓
包完整性检查
↓
镜像导入
↓
离线部署
↓
健康检查

已经非常完整。


七十一、再回到 export/import

什么时候我真的会用?

大概只有这种场景:

text 复制代码
有一个历史 Container

不知道 Dockerfile

里面被人手工改了一堆东西

现在必须先把文件系统抢救出来。

可以:

bash 复制代码
docker export \
  legacy-container \
  -o legacy-rootfs.tar

至少:

text 复制代码
保存当前 rootfs。

然后:

bash 复制代码
docker import

临时重新运行。

但长期:

一定应该重新整理 Dockerfile。


七十二、正常项目不要把 export/import 当备份流程

如果你已经:

text 复制代码
有 Dockerfile

有 Image

有 Registry

有版本号

那:

text 复制代码
save/load

更加符合:

Docker 镜像模型。

而不是:

text 复制代码
把 Container 打平
再重建 Image。

七十三、四个命令最终这样记

text 复制代码
docker save

对象:

text 复制代码
Image

目的:

text 复制代码
保存完整镜像结构。

text 复制代码
docker load

对象:

text 复制代码
Image Archive

目的:

text 复制代码
恢复 Image + Tags。

text 复制代码
docker export

对象:

text 复制代码
Container

目的:

text 复制代码
导出当前文件系统。

text 复制代码
docker import

对象:

text 复制代码
Filesystem Archive

目的:

text 复制代码
创建一个新的 Filesystem Image。

七十四、如果只看输入输出就更清晰

text 复制代码
Image
↓
save
↓
Tar
↓
load
↓
Image

这是:

可逆的镜像搬运链。


text 复制代码
Container
↓
export
↓
RootFS Tar
↓
import
↓
New Image

这是:

文件系统快照链。

两条:

不要混。


七十五、最容易记错的一个点

有人问:

我要把运行中的 Container 搬到另一台机器,是不是应该 export?

要看目的。

如果这个 Container:

text 复制代码
根本没有发生值得保存的手工修改。

真正需要的是原 Image:

text 复制代码
直接 save Image。

如果它的业务数据在:

text 复制代码
Volume

那:

text 复制代码
单独备份 Volume / DB。

不要因为:

text 复制代码
对象叫 Container

就下意识:

text 复制代码
export。

七十六、完整 Docker 系统迁移应该分对象

text 复制代码
Image
→ save/load
text 复制代码
Compose / Config
→ 文件复制 / Git
text 复制代码
Database
→ dump/restore
text 复制代码
Volume Files
→ 单独备份
text 复制代码
Secret
→ Secret 管理
text 复制代码
Container
→ 尽量重新创建

这就是:

Docker 化系统真正正确的迁移方式。


总结

服务器访问不了 Docker Hub,并不意味着:

text 复制代码
Docker 项目就没办法部署。

最简单的离线流程就是:

text 复制代码
有网机器

docker pull
↓
docker save
↓
images.tar
↓
传输
↓
docker load
↓
docker compose up --pull never

对于少量机器:

这已经非常可靠。

而且一定要记住:

text 复制代码
save / load

操作的是:

Docker Image。

它会尽量保留:

text 复制代码
Layer

Image Metadata

Tag。

Docker 官方当前也明确说明,docker save 保存 Repository/Image Layer 和 Tag,而 docker load 会恢复 Image 与 Tag。

而:

text 复制代码
export / import

操作的主要是:

Container Filesystem。

docker import 是把一个 tar 文件系统重新创建成 Filesystem Image,而不是恢复原 Image 的完整 Layer History。

所以如果只记住一句话:

搬镜像,用 docker save + docker load;抢救某个容器当前文件系统,才考虑 docker export + docker import。

如果目标还有:

text 复制代码
AMD64

ARM64

架构差异,

还要进一步关注:

text 复制代码
--platform。

现代 Docker 的 save/load 已经支持指定 Platform,而完整 Multi-Platform Archive 能否被本地 Image Store 正确处理,还需要考虑是否使用支持 Image Index 的 Containerd Image Store。

而当规模从:

text 复制代码
1~5 台服务器

变成:

text 复制代码
几十台
几百台

就不应该继续:

text 复制代码
到处 SCP 5GB tar。

而应该:

text 复制代码
离线包
↓
Internal Harbor / Registry
↓
内网所有机器

把:

文件搬运

升级成:

内部 Artifact Distribution。

对于:

text 复制代码
https://github.com/Rodert/DockerHub

这个项目来说,我觉得非常适合继续增加:

text 复制代码
Compose Image Extractor
+
AMD64 / ARM64 离线包生成器
+
docker save 命令生成
+
SHA256 校验
+
离线 install.sh

这样用户甚至可以:

上传一个 docker-compose.yml,直接生成完整的 Docker 离线部署方案。

项目地址:

text 复制代码
https://github.com/Rodert/DockerHub
相关推荐
EasyGBS9 小时前
摄像头还在线,画面已经不能用了?国标GB28181视频平台EasyGBS视频质量诊断怎么用
服务器·安全·音视频
程序员-Benothing9 小时前
Vim编辑器从入门到精通:模式、快捷键、配置、插件
linux·运维·服务器
m0_6464299710 小时前
Docker 完整核心知识点总结(超通俗易懂版)
运维·docker·容器
wdfk_prog10 小时前
LWIP教程 09:从 `tcp_slowtmr()` 到 Fast Retransmit——TCP 超时重传与重复 ACK
服务器·网络·数据库·网络协议·tcp/ip
‎ദ്ദിᵔ.˛.ᵔ₎10 小时前
linux 进程信号 (上)
linux·服务器
亚川楼宇自控系统数据中心厂家10 小时前
IBMS 集成管理系统:如何打通楼宇自控实现建筑一体化管控
运维
迪康Defender10 小时前
终端安全审批体系设计:如何平衡安全管控与业务连续性
运维·服务器·安全·运维开发·学习方法·业界资讯·远程工作