第3章:Docker核心概念——镜像、容器、仓库与架构

搞空间分析的人,第一次接触 Docker 时,最头疼的就是那堆新名词。镜像是什么?容器又是什么?跟虚拟机有啥区别?我当年刚上手时,也被这些概念绕晕过。这一章咱们就把这些东西彻底说透。

3.1 镜像——只读的打包模板

你可以把镜像理解成一个只读的压缩包。里面装了你应用运行所需的一切:操作系统根文件系统、Python 解释器、GDAL 库、PostGIS 驱动,甚至是你写好的空间分析脚本。

镜像有个特点:分层构建。每一层都是只读的,修改时只记录差异。这有什么好处?你想想看,下载一个 2GB 的 GIS 基础镜像,下次再拉一个新镜像,如果底层相同,只需要下载新增的几十 MB 差异层。我维护过一套遥感数据处理流水线,每天都要发布新版本,依赖层几乎不动,每次推送就几百 KB,快得很。

查看本地已有镜像,用这个命令:

docker images

输出大概长这样:

REPOSITORY          TAG       IMAGE ID       CREATED       SIZE
postgis            15-3.4    abc123def456   2 weeks ago   1.2GB
python             3.11-slim def789ghi012   1 month ago   125MB

关键点:镜像是静态的、只读的、可分享的。你可以在笔记本上构建好,推到仓库,再到服务器上拉下来跑,结果完全一致。这在部署空间分析流程时太重要了——告别“在我机器上能跑”的尴尬。

3.2 容器——镜像的运行实例

镜像再大,不运行就是一堆文件。容器就是镜像活起来的样子。说白了,容器是镜像的运行态,它拥有自己的文件系统、网络栈、进程空间。

打个比方:

  • 镜像 = 菜谱 + 所有食材(静态)
  • 容器 = 正在锅里翻炒的菜(动态)

启动一个容器的命令:

docker run -it --name my-analysis ubuntu:22.04 bash

进入容器后,你可以安装软件、修改文件、跑代码。但要注意,容器默认是临时的。你退出后,容器就停了。如果没做持久化,里面的修改会丢失。

避坑提醒:千万不要在运行中的容器里保存重要数据!我曾经在容器里跑了一整天的矢量数据合并,结果手滑 exit 退出了,再启动时发现所有中间结果都没了……后来老老实实学会了挂载卷(volume)。咱们后面章节会专门讲数据持久化。

3.3 仓库——镜像的集中存储与分发

仓库就相当于一个镜像的 GitHub。你在本地构建好镜像,推上去,别人就能拉下来用。Docker 官方提供了 Docker Hub,上面有海量公共镜像。

拉取一个镜像:

docker pull postgis/postgis:15-3.4

推送自己构建的镜像:

docker tag my-analysis:1.0 yourdockerhub/my-analysis:1.0
docker push yourdockerhub/my-analysis:1.0

如果你是做空间分析项目的,我强烈建议你搭建私有仓库。公司内部的遥感底图、行政区划矢量、DEM 数据,不适合放到公网上。搭建方式很简单:

docker run -d -p 5000:5000 --name registry registry:2

推送时指定仓库地址就行:

docker tag my-analysis:1.0 localhost:5000/my-analysis:1.0
docker push localhost:5000/my-analysis:1.0

个人经验:国内访问 Docker Hub 经常慢得让人抓狂。我通常会配置镜像加速器,或者直接把常用 GIS 镜像缓存到内网私有仓库。团队里 20 多号人,每天拉上百次镜像,缓存一次能省几个小时。

配置镜像加速器很简单,编辑 Docker 配置文件:

# /etc/docker/daemon.json
{
  "registry-mirrors": ["https://your-mirror.example.com"]
}

改完后重启 Docker 服务:

systemctl restart docker

3.4 Docker 架构——客户端-守护进程模式

Docker 采用C/S(客户端-服务端)架构。整个体系由三个核心组件构成:

组件 角色 空间分析场景中的实际角色
Docker 客户端 你敲命令的那个终端 你在笔记本上执行 docker run
Docker 守护进程 后台常驻的核心引擎 管理容器生命周期、镜像层缓存
镜像仓库 存储和分发镜像 拉取 PostGIS、推送分析流程镜像

你敲的每一条 docker 命令,客户端都会通过 REST API 发给守护进程,由它来调度容器、管理镜像。可以跨机器操作:本地客户端控制远程服务器上的守护进程。

我曾经用这个特性在实验室的 8 卡 GPU 服务器上跑遥感影像推理:开发机上敲命令,计算节点上跑容器,调试和生产环境完全隔离。

3.5 核心工作原理——写时复制与命名空间

Docker 之所以能秒级启动、资源占用小,靠的是两项底层技术:

写时复制(Copy-on-Write):多个容器共享同一份只读镜像层,各自只记录自己的写入内容。你创建 10 个基于同一个 PostGIS 镜像的容器,磁盘上只有一份镜像数据。

命名空间(Namespace):每个容器看到自己独立的进程树、网络栈、文件系统。但实际上都运行在宿主机内核上。

这个模型和虚拟机有本质区别:

对比维度 Docker 容器 虚拟机
启动时间 秒级 分钟级
资源开销 极低,共享宿主机内核 高,每个 VM 有独立 OS
隔离级别 进程级 硬件级
磁盘占用 很小(复用镜像层) 很大(完整 OS 镜像)
适合场景 微服务、批量数据处理 多租户强隔离、需要不同内核

空间分析任务,尤其是批量栅格处理、矢量数据 ETL、模型推理,用容器再合适不过。一个任务一个容器,跑完就删,宿主机干干净净。你想想看,几百个任务同时跑,如果用虚拟机,光启动操作系统就得等半小时。

总结一下:

  • 镜像 = 静态打包模板,只读分层存储
  • 容器 = 镜像的运行实例,临时可写层
  • 仓库 = 镜像的集中存储与分发中心
  • 架构 = 客户端 -> 守护进程 -> 仓库的三层模型
  • 核心原理 = 写时复制 + 命名空间,提供轻量级隔离