· Docker 概述与架构原理

Docker 概述与架构原理

5939 字
30 分钟
Docker 概述与架构原理
StarryLin/Geek · 摘要

Docker镜像交付,容器三级调度运行,推荐构建一次后pull+run部署。

Docker 不是一个”铁板一块”的单一程序,而是一套模块化架构:客户端、守护进程、运行时、镜像、容器、网络、存储、仓库……每个模块各司其职,又通过清晰的接口彼此协作。理解这些模块,是真正掌握 Docker 的钥匙。

本文结构:概念 → 原理 → 动手操作 → 命令行速查,所有架构图均使用 Mermaid 绘制。


目录#

  1. Docker 的模块化设计思想
  2. 平台核心模块:Client / Daemon / containerd / runc / Registry
  3. 镜像模块:分层的只读模板
  4. 容器模块:隔离运行的进程
  5. 网络模块:连接与隔离
  6. 存储模块:数据持久化
  7. 镜像仓库模块:发布与分发
  8. 端到端实战:一条 docker run 背后的故事
  9. 部署工作流:代码是怎么跑到服务器上的
  10. 命令行速查总表
  11. 小结

1. Docker 的模块化设计思想#

传统虚拟机把”应用程序 + 依赖 + 完整操作系统”打包成一个巨大的镜像,由 Hypervisor 模拟整台硬件。Docker 换了一条路:只打包应用和依赖,直接共享宿主机的操作系统内核,再用 Linux 内核自带的隔离技术把进程”圈”起来。

模块化带来的收益:

特性说明
可替换可配置兼容的 OCI 运行时,如 runc、Kata 或 gVisor;containerd 是另一层的生命周期管理器
可组合镜像 + 网络 + 卷可以自由组合成应用
职责单一每个模块只做一件事,边界清晰、易排障
标准化各模块之间用公开规范(OCI、REST API)通信

下面的全景图展示了 Docker 各模块之间的关系:

flowchart LR U[开发者 / 终端用户] -->|"docker build / run / pull / push"| CLI["Docker Client 客户端"] CLI -->|"REST API (HTTP / unix socket)"| D["Docker Daemon 守护进程 dockerd"] D -->|"管理对象"| OBJ["镜像 Image / 容器 Container / 网络 Network / 卷 Volume"] D -->|"containerd API / gRPC"| C["containerd 容器运行时"] C -->|"OCI 规范"| R["runc 低层运行时"] R -->|"namespace + cgroups"| K[("Linux 内核")] D -->|"拉取 / 推送"| REG["Registry 镜像仓库 (Docker Hub)"] style CLI fill:#e3f2fd style D fill:#fff3e0 style C fill:#f3e5f5 style R fill:#f3e5f5 style K fill:#e8f5e9 style REG fill:#fce4ec

从图中可以看到清晰的”三段式”:

  1. 用户层:客户端 CLI,负责接收人的指令;
  2. 管理层:守护进程 dockerd,负责”头脑”工作——调度、编排、对象管理;
  3. 执行层:containerd → runc → 内核,负责真正把进程跑起来。

2. 平台核心模块:Client / Daemon / containerd / runc / Registry#

2.1 Docker Client(客户端 CLI)#

概念:用户与 Docker 交互的命令行程序,例如 docker run 中的 docker 就是客户端。

原理:客户端本身不做任何容器操作,主要把容器管理命令翻译成 Engine API 请求;构建等子命令还会调用相应组件。客户端与守护进程通过本地 unix:///var/run/docker.sock 通信,也可通过 -H 参数连接远程守护进程:

Terminal window
# 连接到远程机器的守护进程
docker -H ssh://user@192.168.1.10 ps
# 查看当前客户端 / 服务端信息
docker version
docker info

2.2 Docker Daemon(守护进程 dockerd)#

概念:常驻后台的服务进程,是 Docker 的”大脑”。

原理:它监听 REST API 请求,负责管理所有 Docker 对象(镜像、容器、网络、卷),并在需要时调用 containerd 执行真正的容器操作。containerd 通过 shim 进程管理容器进程。Docker 默认会在守护进程退出时停止容器;需要在符合限制的环境中启用 live-restore,才能在 daemon 不可用时保留容器运行。官方说明

Terminal window
# 查看守护进程与运行环境信息
docker info
# 在容器内查看(了解它跑在哪个内核上)
docker run --rm alpine uname -r

2.3 containerd(容器运行时管理器)#

概念:一个工业级容器运行时管理器,CNCF 毕业项目,同时被 Kubernetes(通过 CRI)和 Docker 使用。

原理:containerd 负责镜像的下载与解包、容器存储、以及调用低层运行时启动容器。它实现了 OCI(Open Container Initiative)规范中的镜像与运行时标准,把”如何管理容器生命周期”与”具体怎么启动进程”两层分离。

2.4 runc(低层运行时)#

概念:真正与内核打交道的程序,目前 Docker 默认的低层运行时。

原理:runc 根据 OCI 运行时规范,调用 Linux 内核的两个关键能力创建隔离环境:

  • namespaces(命名空间):让进程拥有独立的 PID、Network、Mount、UTS、IPC、User 视图——容器里看到的”自己是 1 号进程""自己有网卡”,都是命名空间制造的幻觉;
  • cgroups(控制组):限制并统计容器可用的 CPU、内存、磁盘 IO 等资源。
Terminal window
# 查看默认低层运行时(一般是 runc)
docker info | grep -i runtime
# 查看容器实际使用的 cgroup
docker run -d --name demo --memory 128m alpine sleep 3600
docker inspect demo --format '{{.HostConfig.Memory}}'

小结:dockerd(管理)→ containerd(生命周期管理)→ runc(执行)→ 内核(隔离)。各层按接口分工,替换运行时需要满足兼容性和部署条件,并非任意组件都能直接互换。

2.5 Registry(镜像仓库)#

概念:存放和分发镜像的服务,公开的有 Docker Hub,私有常见 Harbor、AWS ECR 等。

Terminal window
docker pull nginx # 从默认仓库 Docker Hub 拉取
docker login # 登录(访问私有仓库需要)
docker push myname/app:v1 # 推送本地镜像到仓库

3. 镜像模块:分层的只读模板#

3.1 概念#

镜像是只读的模板,包含运行一个应用所需的全部内容:代码、运行时、库、环境变量、配置。镜像是”类”,容器是”实例”。

3.2 原理:分层与联合文件系统#

镜像由多层只读层堆叠而成。RUN、COPY、ADD 等会形成文件系统层;CMD、ENTRYPOINT 等记录配置元数据,不新增文件系统层:

  • 层之间用 UnionFS(联合文件系统) 叠加,对外表现为一个完整文件系统;
  • 层是可共享、可缓存的:多个镜像共用同一基础层时只存一份;
  • 容器启动时,Docker 在最上层再加一层可写层;修改文件采用 Copy-on-Write(写时复制)——先复制再修改,绝不动下层。
graph TB subgraph IMG["镜像 Image(多层只读层叠加)"] direction BT L4["镜像配置 CMD / ENTRYPOINT(非文件系统层)"] L3["Layer 3 COPY . /app"] L2["Layer 2 RUN npm install"] L1["Layer 1 FROM node:20-alpine"] L1 --> L2 --> L3 --> L4 end subgraph CTN["容器 Container(运行实例)"] RW["可写层 Writable Layer<br/>(写入、删除、修改都发生在这里)"] end IMG --> RW REG["Registry 仓库"] -.docker pull.-> IMG style L1 fill:#e8eaf6 style L2 fill:#e8eaf6 style L3 fill:#e8eaf6 style L4 fill:#e8eaf6 style RW fill:#c8e6c9

3.3 构建上下文(Build Context):docker build 到底在哪执行?#

先回答一个高频疑问:是不是必须在 Dockerfile 所在的文件夹里执行 docker build?

准确答案是:可以在任意目录执行,只要正确指定构建上下文路径和 Dockerfile 路径。 看这条命令:

Terminal window
docker build -t myapp:v1 .
# ↑ 这个 . 是"构建上下文路径",不是"Dockerfile 的位置"

它背后发生的事是:

  1. 构建器根据 . 确定本地构建上下文,并应用 .dockerignore;
  2. 默认使用的 BuildKit 按需传输和处理构建所需文件;旧式构建器才通常把整个上下文打包传给 daemon;
  3. 普通 COPY / ADD 的本地源以这个上下文为根,不能通过 ../ 读取其外部文件;COPY --from 则可读取其他构建阶段、镜像或命名上下文。

三种典型用法

Terminal window
# ① 最常用:Dockerfile 在当前目录,上下文 = 当前目录
cd /home/user/myapp
docker build -t myapp:v1 .
# ② Dockerfile 放在子目录,上下文仍是项目根目录(推荐的工程组织方式)
docker build -f docker/Dockerfile -t myapp:v1 .
# ③ 无上下文,从标准输入读 Dockerfile(此时只能用 ADD 远程 URL,不能 COPY 本地文件)
docker build -t myapp:v1 - < Dockerfile

三个必踩的坑

Terminal window
# ❌ 1. 不要把系统根目录当构建上下文,避免暴露无关文件并增加扫描成本
cd / && docker build -t x .
# ❌ 2. COPY 不能跳出上下文
# 不能借 ../ 读取上下文外文件;报错或路径规范化行为依构建器而异
COPY ../config.yml /app/
Terminal window
# ❌ 3. 不写 .dockerignore,COPY . . 可能带入 node_modules、.git 等无关文件

.dockerignore 放在上下文根目录,语法类似 .gitignore:

.git
node_modules
dist
*.log
Dockerfile
.dockerignore

它既缩小传输体积,又避免本地依赖覆盖镜像内的依赖、导致构建缓存失效。

3.4 操作:用 Dockerfile 构建镜像#

# 示例 Dockerfile:构建一个极简 Node.js 应用镜像
# 基础镜像层
FROM node:20-alpine
# 设置工作目录
WORKDIR /app
# 先只拷贝依赖清单,利于缓存
COPY package*.json ./
# 安装依赖
RUN npm install
# 拷贝应用源码
COPY . .
# 声明端口(仅文档作用)
EXPOSE 3000
# 启动命令
CMD ["node", "server.js"]
Terminal window
docker build -t myapp:v1 . # 构建,-t 指定名称:标签
docker images # 查看本地镜像
docker history myapp:v1 # 查看构建历史(含不产生文件系统层的元数据指令)
docker inspect myapp:v1 # 查看镜像元数据
docker rmi myapp:v1 # 删除镜像
docker image prune # 清理悬空镜像

镜像命名格式:[仓库地址/]仓库名/镜像名:标签,缺省时仓库为 docker.io/library。

Terminal window
docker tag myapp:v1 myname/myapp:latest # 打新标签
docker save -o myapp.tar myapp:v1 # 导出镜像为 tar 包
docker load -i myapp.tar # 导入 tar 包

4. 容器模块:隔离运行的进程#

4.1 概念#

容器是镜像的运行实例。它在宿主机上就是一个普通进程(带着一堆隔离),被命名空间、cgroup 包裹,拥有独立的文件系统、网络栈与进程视图。

4.2 原理:生命周期状态机#

stateDiagram-v2 [*] --> Created : docker create Created --> Running : docker start Running --> Paused : docker pause Paused --> Running : docker unpause Running --> Stopped : docker stop Stopped --> Running : docker start Stopped --> [*] : docker rm Running --> [*] : docker rm -f

几个易混的细节:

  • docker stop 先发 SIGTERM 优雅退出,超时后才 SIGKILL(默认 10 秒,可用 -t 调整);
  • docker restart 先停止再启动;强制删除运行中容器用的是 docker rm -f;
  • 前台运行(不 -d)时,按 Ctrl-C 相当于给 PID 1 发送 SIGINT。

4.3 操作与命令行#

Terminal window
# 创建并启动容器:-d 后台、--name 命名、-p 端口映射
docker run -d --name myapp -p 3000:3000 myapp:v1
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器(含已停止)
docker logs -f myapp # 跟随查看日志
docker exec -it myapp sh # 进入容器执行命令(排障利器)
docker top myapp # 查看容器内进程
docker stats # 实时查看资源占用(依赖 cgroups)
docker cp myapp:/app/log.txt ./ # 与容器互拷文件
docker pause myapp # 暂停(冻结)
docker unpause myapp # 恢复
docker restart myapp
docker stop myapp
docker start myapp
docker rm -f myapp # 删除容器(-f 先杀后删)
docker container prune # 清理所有已停止容器

排障流程口诀:先 logs 看应用,再 exec 进容器查环境,最后 inspect 看配置。


5. 网络模块:连接与隔离#

5.1 概念与原理#

Docker 通过 veth 虚拟网卡 + 网桥 + iptables/NFTables 搭建虚拟网络。主要驱动类型:

驱动适用场景说明
bridge单机多容器互访默认网络 docker0,自动分配 172.17.0.x 地址
host需要极致性能容器直接用宿主机网络栈,无隔离,-p 失效
overlaySwarm 跨主机让跨节点的容器处于同一虚拟子网
macvlan需要容器像物理设备给容器分配 MAC 地址,接入局域网
none网络完全隔离只有 lo 回环接口

要点:普通 bridge 网络中的容器通常可经 NAT 出网,是否可达还受路由和防火墙影响;同一 bridge 内的容器默认可按 IP 互访,不同 bridge 默认隔离;容器间推荐加入同一个自定义 bridge 网络——此时可直接用容器名/服务名通信(内嵌 DNS),而默认 docker0 网络不支持按名字解析。

flowchart LR subgraph Host["宿主机"] subgraph N1["默认网络 bridge docker0"] A["容器 A 172.17.0.2"] B["容器 B 172.17.0.3"] end subgraph N2["自定义网络 app-net"] C["容器 web (web:3000)"] D["容器 db (db:5432)"] end end Internet(("Internet")) -->|"-p 8080:80 端口映射 (DNAT)"| N1 N1 -.默认隔离.-> N2 style N1 fill:#e3f2fd style N2 fill:#fff3e0

5.2 操作与命令行#

Terminal window
# 创建自定义网络,并指定子网
docker network create -d bridge --subnet 172.20.0.0/16 app-net
# 在指定网络中启动容器
docker run -d --name web --network app-net myapp:v1
docker run -d --name db --network app-net -e POSTGRES_PASSWORD=dev-only-change-me postgres:16
# 在 web 容器里直接用名字访问 db(内嵌 DNS)
docker exec web ping -c 2 db
# 管理命令
docker network ls # 列出网络
docker network inspect app-net # 查看网络详情与成员
docker network connect app-net old-container # 动态接入
docker network disconnect app-net old-container
docker network rm app-net # 删除(需先断开成员)
# 端口映射
docker run -d -p 8080:80 nginx # 宿主机8080 -> 容器80
docker run -d -P nginx # -P 随机映射所有 EXPOSE 端口
docker port <container> # 查看端口映射关系

6. 存储模块:数据持久化#

6.1 概念与原理#

容器被删除后,它的可写层随之消失,需要持久化的数据必须放到宿主机侧的挂载上。Docker 提供三种挂载:

类型存储位置典型用途特点
Volume 卷/var/lib/docker/volumes/(由 Docker 管理)数据库数据、应用数据首选;可命名、可备份、可跨容器共享
Bind mount 绑定挂载宿主机任意路径开发时共享源码、挂配置文件直观,但依赖宿主目录结构
tmpfs宿主机内存(可能被换出到 swap)临时数据、高速缓存容器停止后清空;用于 Linux 容器,不保证绝不落盘
flowchart TB subgraph HOST["宿主机"] V["Volume 卷<br/>/var/lib/docker/volumes/myvol"] B["Bind 绑定目录<br/>/home/user/app"] T["tmpfs<br/>内存中(RAM)"] end subgraph C["容器"] M1["挂载点 /data"] M2["挂载点 /code"] M3["挂载点 /cache"] end V -->|"docker run -v myvol:/data"| M1 B -->|"docker run -v /home/user/app:/code"| M2 T -->|"--tmpfs /cache"| M3 style V fill:#e8f5e9 style B fill:#fff3e0 style T fill:#fce4ec

新写法推荐 --mount type=volume,src=myvol,dst=/data 形式,语法更明确,比短写法 -v 更不易出错。

6.2 操作与命令行#

Terminal window
# ---- Volume 卷 ----
docker volume create pgdata # 创建命名卷
docker volume ls # 列出卷
docker volume inspect pgdata # 查看卷(含宿主机路径)
docker volume rm pgdata # 删除卷
docker volume prune # 清理无用卷
# 挂载卷:给 Postgres 持久化数据
docker run -d --name pg \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret postgres:16
# ---- Bind mount:开发时共享源码(改动即时生效)----
docker run -d -p 3000:3000 \
-v "$PWD":/app \
-w /app node:20 node server.js
# ---- tmpfs:内存文件系统 ----
docker run -d --tmpfs /cache alpine sleep 3600
# ---- 查看容器挂载情况 ----
docker inspect pg --format '{{json .Mounts}}'
# ---- 容器间共享同一卷 ----
docker run -d --name writer -v share:/data alpine sh -c "echo hi > /data/f.txt; sleep 3600"
docker run --rm -v share:/data alpine cat /data/f.txt

7. 镜像仓库模块:发布与分发#

7.1 概念#

Registry 是镜像的”GitHub”。本地 Docker 称为缓存,远程仓库才是源头。完整镜像名是 [仓库地址]/[命名空间/]镜像名:标签。

7.2 命令行#

Terminal window
docker search nginx # 搜索官方仓库镜像
docker pull nginx:alpine # 显式拉取 alpine 标签;未写标签时才默认 latest
docker login # 登录 Docker Hub
docker tag myapp:v1 myname/myapp:1.0.0 # 打上自己的仓库标签
docker push myname/myapp:1.0.0 # 推送
docker logout # 退出登录
# 用容器镜像名区分官方与个人镜像
docker pull nginx # docker.io/library/nginx
docker pull myname/myapp:1.0.0 # docker.io/myname/myapp

8. 端到端实战:一条 docker run 背后的故事#

把前面的模块串起来,看一次典型部署中每个模块做了什么。

第一步:动手操作(以第 3 节 Dockerfile 构建的 myapp:v1 为例)

Terminal window
# ① 构建镜像(镜像模块)
docker build -t myapp:v1 .
# ② 建网络、建卷(网络/存储模块)
docker network create app-net
docker volume create pgdata
# ③ 启动数据库与业务容器(容器模块)
docker run -d --name pg --network app-net -v pgdata:/var/lib/postgresql/data postgres:16
docker run -d --name web --network app-net -p 3000:3000 myapp:v1
# ④ 验证
docker ps
curl localhost:3000
docker logs -f web

第二步:内部原理——docker run -d -p 80:80 nginx 的完整时序:

sequenceDiagram participant User as 用户 participant CLI as docker CLI participant D as dockerd participant R as Registry participant CT as containerd participant RC as runc participant K as Linux 内核 User->>CLI: docker run -d -p 80:80 nginx CLI->>D: ① REST API:创建并启动容器 D->>D: ② 检查本地是否存在 nginx 镜像 alt 本地没有该镜像 D->>R: ③ 向 Registry 拉取镜像(分层下载) R-->>D: 返回镜像层 end D->>CT: ④ 把镜像和运行配置交给 containerd CT->>RC: ⑤ 按 OCI 规范请求创建容器 RC->>K: ⑥ 创建 namespaces / cgroups(隔离 + 限资源) K-->>RC: 隔离环境就绪 RC-->>CT: ⑦ 容器进程(PID 1)已启动 CT-->>D: ⑧ 上报容器已运行 D-->>CLI: ⑨ 返回容器 ID CLI-->>User: 输出容器 ID

对应关系:CLI = 客户端模块,dockerd = 管理模块,Registry = 仓库模块,containerd/runc = 运行时模块,namespaces/cgroups = 内核隔离机制。


9. 部署工作流:代码是怎么跑到服务器上的#

学到这里,最容易混淆的问题是:“我写好的代码,到底是推到 Docker Hub 让服务器拉下来 build,还是服务器 git clone 源码再构建?”

先给结论:两个方案都有人用,但生产环境推荐”构建一次、分发镜像”。并且要记住 —— 代码走 git,成品走 Registry,两者不是一回事。

9.1 先分清三个角色#

角色存什么常用服务
代码仓库源码(人类可读的文本)GitHub / GitLab / Gitee
Registry 镜像仓库镜像(已构建好的二进制交付物,含代码 + 依赖 + 运行时)Docker Hub / Harbor / 阿里云 ACR / AWS ECR
服务器只负责运行容器任意装了 Docker 的机器

关键认知:docker build 时 COPY . /app 已经把源码烤进镜像了,所以生产服务器既不需要 git,也不需要 Node/Python/编译器,它只需要 docker pull + docker run。这正是容器化的价值所在。

9.2 两种部署方案对比#

flowchart TB subgraph A["方案 A:构建一次,分发镜像(推荐生产)"] direction TB A1["开发者 git push 源码"] --> A2["CI / 构建机<br/>docker build"] A2 --> A3["docker push → Registry 镜像仓库"] A3 --> A4["生产服务器 docker pull"] A4 --> A5["docker run(服务器上不 build)"] end subgraph B["方案 B:服务器拉代码后再构建"] direction TB B1["服务器 git pull 源码"] --> B2["服务器 docker build"] B2 --> B3["docker run"] end style A2 fill:#e3f2fd style B2 fill:#fff3e0
对比项方案 A(分发镜像)方案 B(服务器构建)
服务器需要工具链吗通常只需容器运行环境与部署配置需要源码获取工具和构建器;语言工具链可以放在 Dockerfile 的构建阶段中
部署速度快(只 pull 镜像层,有缓存)慢(每次可能重新 build)
回滚重新部署旧镜像;耗时取决于拉取、启动及健康检查,数据库迁移另行处理可重建旧提交;如果保留旧镜像,也可直接重新部署
环境一致性强(构建环境固定)弱(依赖服务器当时的环境)
适合场景生产、团队协作、K8s个人小项目、内网单机、快速验证

9.3 方案 A 命令:构建一次,到处运行#

Terminal window
# ===== 本地开发机 或 CI(GitHub Actions / GitLab CI):只在这里 build 一次 =====
docker build -t myrepo/myapp:1.0.0 .
docker push myrepo/myapp:1.0.0
# ===== 生产服务器:只 pull 和 run,绝不 build =====
docker pull myrepo/myapp:1.0.0
docker run -d -p 3000:3000 --name app myrepo/myapp:1.0.0
# 回滚:把 tag 换成上个版本,重启容器即可
docker pull myrepo/myapp:0.9.0
docker rm -f app
docker run -d -p 3000:3000 --name app myrepo/myapp:0.9.0

9.4 方案 B 命令:服务器上拉代码构建#

Terminal window
# ===== 服务器上 =====
git pull origin main # 先更新源码
docker compose up -d --build # 然后构建并创建/更新服务容器
# 等价的手动写法
docker build -t myapp:latest .
docker run -d -p 3000:3000 --name app myapp:latest

简单直接,适合个人项目和内网机器;代价是服务器要承担构建资源消耗,并维护构建器及源码;语言依赖可以安装在构建容器中。

9.5 bind mount 在”开发”与”生产”中的定位#

很多人会把上一节的挂载方式和部署流程搞混。bind mount 是运行时行为,和 build、Registry 没有任何关系——它不打包、不上传、不构建,只是把宿主机的目录”借”给容器读写。

flowchart LR subgraph HOST["宿主机"] SRC["源码目录 /home/u/app"] CFG["配置文件 nginx.conf"] DATA["数据目录 /var/lib/..."] end subgraph C["容器"] APP["/app"] CONF["/etc/nginx/nginx.conf"] DB["/var/lib/postgresql/data"] end SRC -.->|"bind mount:仅开发环境<br/>改代码即时生效,热重载"| APP CFG -.->|"bind mount:生产也常用<br/>改配置不必重新 build"| CONF DATA -.->|"volume:生产持久化首选<br/>容器删了数据还在"| DB style APP fill:#e8f5e9 style CONF fill:#fff3e0 style DB fill:#e3f2fd

三条实践准则:

  1. 生产环境不要 bind mount 代码:镜像里已经有代码了,再挂宿主机目录会覆盖镜像内容,“镜像版本”就失去意义了——这是常见反模式;
  2. 生产用 volume 挂数据:数据库文件、用户上传、日志等(见第 6 节),因为容器删除后可写层会一起消失;
  3. 开发用 bind mount 挂源码:配合 nodemon、vite 等热重载工具,改一行代码立即生效,不用反复 build。
Terminal window
# 开发环境典型写法:挂源码 + 热重载
docker run -d -p 3000:3000 -v "$PWD":/app -w /app node:20 npm run dev
# 生产环境典型写法:代码在镜像里,只挂数据卷
docker run -d -p 3000:3000 -v pgdata:/var/lib/postgresql/data myrepo/myapp:1.0.0

9.6 一句话总结#

代码走 git,成品走镜像仓库;build 只做一次(本地或 CI),服务器只 pull + run;bind mount 是”运行时把宿主机目录借给容器”,不参与构建和分发。


10. 命令行速查总表#

容器#

命令作用
docker run -d --name n -p 80:80 img创建并后台启动容器
docker ps / -a查看运行中 / 全部容器
docker start / stop / restart启 / 停 / 重启容器
docker pause / unpause暂停(冻结)/ 恢复
docker rm [-f]删除容器(-f 强制删运行中)
docker exec -it n sh进入容器执行命令
docker logs -f n查看并跟随日志
docker cp n:/path ./容器与宿主机互拷文件
docker top / stats / inspect n进程 / 资源 / 配置详情
docker port n查看端口映射

镜像#

命令作用
docker build -t name:tag .构建镜像
docker images列出本地镜像
docker pull / push拉取 / 推送镜像
docker tag打标签
docker history img查看分层历史
docker rmi / docker image prune删除镜像 / 清理悬空镜像
docker save / load导出 / 导入镜像为 tar
docker commit把容器保存为新镜像(少用)

网络与存储#

命令作用
docker network ls / create / rm网络列表 / 创建 / 删除
docker network connect / disconnect动态接入 / 断开网络
docker volume ls / create / rm / prune卷列表 / 创建 / 删除 / 清理
docker system df查看镜像、容器、卷占用

11. 小结#

把 Docker 拆成模块来理解,你会发现它的设计其实非常优雅:

  • 镜像是”交付物”,容器是”运行态”,两者通过分层与 CoW 紧密关联;
  • 构建上下文决定了 COPY 能看到什么,docker build 要正确指定上下文路径,并配好 .dockerignore;
  • dockerd → containerd → runc 是”管理 → 编排 → 执行”三级流水线,每层都可替换;
  • namespace / cgroups 是内核提供的隔离地基,Docker 只是它的”友好的前端”;
  • 网络、存储、仓库是三个横向支撑模块,分别解决”连通、持久、分发”问题;
  • 部署流程上,代码走 git、成品走 Registry,服务器只 pull + run,build 只在本地或 CI 做一次。

核对资料#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Docker 概述与架构原理
https://mjzy.tech/posts/docker/01-概述与架构原理/
作者
JIA
发布于
2026-09-03
许可协议
CC BY-NC-SA 4.0

评论区

正在加载 GitHub 评论…

Tips · 随手记
仅自己可见 · 每篇文章单独保存

文章目录