DOCKER RUNTIME LAB
架构图 ↗
From zero to PID 1 · 动态讲解

Docker怎么跑起来的?

不要先把 Container 想成“小电脑”。抓住一条主线:Docker 把程序文件和启动方式做成 Image,再把 Image 启动成受隔离的 Linux 进程。

贯穿全文的虚构案例|Maple Shop
一家小型在线商店,由 web(React 页面)、api(Java 服务)、db(PostgreSQL)、files(对象存储)和 worker(后台任务)组成。所有名称与数据均为教学别名,与真实项目无关。
01

从代码到运行进程

点击步骤或自动播放。build 只负责制作 Image;create/start 才把 Image 变成 Container。

docker-engine / guided-runSTEP 01 / 07
01 / INPUT

准备代码与 Dockerfile

Dockerfile 只是一份配方,描述基础环境、复制哪些文件,以及以后如何启动程序。

Docker 从源代码到容器的流程 源代码和 Dockerfile 交给 BuildKit,生成 Image,再创建 Container,并连接网络与数据卷。
build context项目代码app.jar
config/
recipeDockerfileFROM java:21
COPY app.jar
builderBuildKit执行指令 · 复用缓存
read-only templateImagemaple-api:1.0
runtime instanceContainerwritable layer + isolation
PID 1 · java -jar app.jar
private networkService DNSdb:5432
persistent storageVolume/var/lib/postgresql/data
DOCKER DESKTOP / LINUX VM / RUNTIME FLOOR

ls app.jar Dockerfile

找到程序文件和构建配方。此时还没有 Image,也没有 Container。

02

三个对象,不要混在一起

用“菜谱 → 预制餐包 → 正在营业的餐车”区分制作模板和启动实例。

RECIPE

Dockerfile

文本配方。指定基础环境、复制什么、执行什么,以及容器默认运行哪条命令。

简单例子菜谱:写清楚原料与制作步骤。
FROM java:21 · COPY app.jar · ENTRYPOINT
TEMPLATE

Image

构建完成的只读模板。由文件层和启动元数据组成,可以打标签、推送、复用。

简单例子密封餐包:内容已准备好,但还没有营业。
maple-api:1.0 · immutable layers
INSTANCE

Container

Image 的运行实例。拥有可写层、进程视图和网络;主进程退出,Container 就停止。

简单例子营业中的餐车:同一餐包能开出多辆。
PID 1 + writable layer + network
03

Build 在“制作模板”

点击 Dockerfile 每一行。上游没变化时,下次 build 可以直接复用只读层缓存。

Layer Cache Lab

示例后端镜像:Java 环境 + 工作目录 + 业务 JAR + 启动命令。

01 / BASE LAYERJava 21 用户空间来自基础镜像;它不包含 Linux 内核,运行时共享宿主 Linux 内核。
maple-api:1.0content-addressed / read-only
L4
ENTRYPOINT启动元数据
CACHED
L3
app.jar业务代码变化通常从这里失效
12 MB
L2
/app工作目录元数据
CACHED
L1
Java 21 Runtime基础文件系统
CACHED
04

Container 是隔离进程,不是完整 VM

namespaces 隔离“看见什么”,cgroups 约束“能用多少”;容器通常不启动独立内核。

Container Ajava · 独立 PID / FS / Network
Container Bnginx · 独立 PID / FS / Network
Docker Runtimecontainerd → runc
共享 Linux Kernelnamespaces · cgroups · overlay filesystem
Docker Desktop Linux VM因为 macOS 本身没有 Linux 内核
05

两个小实验:数据与网络

亲手删一次容器,再试一次 localhost,两个最常见误区会立即变得直观。

EXPERIMENT A / STORAGE

删除 Container 后,什么留下?

写入数据后删除并重建:可写层消失,Named Volume 留存。

C1Container 可写层empty
VOLNamed Volumeempty
$ 等待操作:先写入两类数据。
EXPERIMENT B / NETWORK

API 怎样找 PostgreSQL?

Maple Shop 的 Compose 网络提供服务名 DNS;容器里的 localhost 指向它自己。

apiJava service :8080
dbPostgreSQL :5432
filesObject storage :9000
请选择 api Container 内部使用的数据库地址。
宿主 localhost:8080 → api:8080
06

Compose 一次编排整套服务

Maple Shop 需要构建 web、api、worker 三个自有 Image,并复用 PostgreSQL 与对象存储的现成 Image,最后启动 5 个 Container。

docker compose up --build
·Image maple-worker:1.0Built
·Image maple-api:1.0Built
·Image maple-web:1.0Built
·Container maple-dbHealthy
·Container maple-filesHealthy
·Container maple-workerHealthy
·Container maple-apiHealthy
·Container maple-webStarted
07

把命令放回正确阶段

判断命令是在“制作模板”还是“管理实例”,Docker 命令体系就不会乱。

docker build -t demo:1.0 .Dockerfile → Image:构建并打标签。
docker pull postgres:16Registry → 本地:下载现成 Image。
docker create demo:1.0Image → 停止状态的 Container。
docker run demo:1.0create + start;缺 Image 时会 pull,但不会读取 Dockerfile build。
docker compose up --build构建自有 Images,再创建或重建并启动整套 Containers。
docker compose down删除 Compose Containers 与网络;默认保留 Named Volumes。
最后检查:同一个 Image 能启动几个 Container?Image 是模板,因此答案与“模板能复印几次”类似。
08

再深入一层:谁做了什么

平时只操作 Docker CLI;下面是它通向 Linux 内核的内部链路。

Docker CLI / Compose

读取命令与 compose.yml,通过 API 请求 Docker Engine。

docker compose up
Engine / BuildKit

管理 Images、Containers、Networks、Volumes;BuildKit 负责构建与缓存。

dockerd + buildkit
containerd / runc

准备 root filesystem 和运行配置,最终创建容器主进程。

OCI image + runtime
Linux Kernel

提供 namespaces、cgroups、网络和联合文件系统,执行隔离后的进程。

PID 1 starts here
已复制