Docker 不是虚拟机,
它是给应用打包的「集装箱」
这是一份讲义,不是题库。我们按"每个东西到底解决什么问题"把 Docker 拆成 10 个模块,每块都先用大白话和类比讲清楚,配上流程图与对比表。遇到容易考、容易混的地方,会用一个橙色的「考点」小框单独点一下,帮你记牢。建议从上往下读一遍。
Docker 到底是什么
一句话:Docker 让你把"应用 + 它需要的整套运行环境"打包成一个标准盒子,在任何机器上都能原样跑起来。理解它最快的方式,是和虚拟机对比。
Docker vs 虚拟机:核心差异在"内核"
- 虚拟机:每台 VM 有自己独立的操作系统内核,靠 Hypervisor 虚拟出一套硬件 → 重、慢、隔离强。
- 容器:所有容器共享宿主机的同一个 Linux 内核,只是把进程、文件系统、网络隔离开 → 轻、秒级启动、性能损耗极小。
三大件的关系:镜像 → 容器 → 仓库
整个 Docker 世界就围绕三个东西转,先记住这张流程图,后面所有模块都是在补充它的细节:
docker push 上传镜像,用 docker pull 下载别人的镜像。镜像 ⇄ 仓库,容器从不直接进仓库。镜像 Image:怎么造、怎么管
镜像是 Docker 里最核心的一块。搞懂三件事就行:它由 Dockerfile 构建、采用分层存储、并有一整套造/搬/存/删的命令。
Dockerfile造镜像的"配方"
Dockerfile 是一行行指令,从底座开始一层层往上叠。常见指令:
FROM— 指定基础镜像(底座,如alpine、java:11)。RUN— 构建时执行命令(装软件等)。每条 RUN 都会生成一个新层,所以习惯把多条命令合并、顺手清缓存,镜像才小。COPY/ADD— 把文件放进镜像(区别见下表)。CMD/ENTRYPOINT— 指定容器启动时跑什么(区别见下表)。
| 对比 | COPY | ADD |
|---|---|---|
| 基本复制 | 复制本地文件/目录 | 复制本地文件/目录 |
| 自动解压本地 tar | 不支持 | 支持 |
| 从 URL 下载 | 不支持 | 支持 |
| 建议 | 能用 COPY 就用 COPY(行为更明确) | 仅在确需解压/下载时用 |
| 对比 | CMD | ENTRYPOINT |
|---|---|---|
| 角色 | 默认命令/默认参数 | 固定入口(主程序) |
| 能否被 run 覆盖 | 能被 docker run 后的参数覆盖 | 默认不被覆盖(需 --entrypoint) |
| 两者同时存在 | CMD 充当 ENTRYPOINT 的默认参数(最终命令 = ENTRYPOINT + CMD) | |
分层 / 多阶段镜像为什么是一层层的
- 分层的好处:省存储(共享底层)、加速构建(命中缓存的层不重建)、便于分发共享。
- 多阶段构建(multi-stage):先在"编译阶段"用大镜像编译,再把成品拷进一个干净的小镜像,显著减小最终体积。
- digest(摘要):对镜像内容算出的 SHA256,内容一变就变,用来精确锁定不可变的镜像(
image@sha256:...);而tag只是版本标签、可移动、可重复。
命令镜像的造、搬、存、删
docker tag myapp:1.0 myapp:latest # 打标签(区分版本)
docker pull nginx # 拉取;不带 tag 默认 :latest
docker commit 容器ID new:1.0 # 把"运行中容器"固化成新镜像
docker save myapp:1.0 -o app.tar # save = 导出"镜像"(含分层)
docker export 容器ID -o snap.tar # export = 导出"容器快照"(扁平)
docker rmi myapp:1.0 # rmi = remove image,删镜像
.dockerignore:列出构建时不打包进上下文的文件(如 node_modules、.git),只在 build 时生效,用来加快构建、减小体积。- 镜像最佳实践:用官方基础镜像、合并 RUN 清缓存、用非 root 用户运行、用 .dockerignore。
save 存镜像、export 存容器快照(最常混);② pull 默认拉 :latest;③ 删镜像是 rmi(rm 是删容器);④ "以 root 运行应用"是错误实践,应用非 root。容器运行:docker run 与进容器
镜像跑起来就是容器。核心是把 docker run 的常用参数记牢,以及"怎么进到一个正在跑的容器里看一看"。
docker run启动容器的常用参数
--name web # 给容器起名
-p 8080:80 # 端口映射:宿主机:容器
-v /data/html:/usr/share/nginx/html # 挂载目录
-e ENV=prod # 设置环境变量
--restart=always # 随 Docker 服务自动启动
--rm # 退出后自动删除容器(临时调试用)
nginx
记忆口诀:d 后台、name 起名、p 端口、v 挂载、e 变量、restart 自启、rm 用完即焚。
-e 设环境变量(Dockerfile 里用 ENV);② --rm = 退出后自动删容器;③ 自动随服务启动用 --restart=always(没有 --auto-start / --respawn 这些)。进容器attach 与 exec 的区别
attach 像把屏幕接到容器"正在跑的主程序"上,看到的是它的输出,一不小心退出会把主程序(容器)停掉;exec 像在容器里另开一个新窗口/新终端,你进去敲命令,退出也不影响主程序。所以"进容器看看"几乎都用 exec。其中 -i 保持输入打开、-t 分配伪终端,通常一起用。
状态容器有哪些状态
官方状态:created(已创建未启动)、running、paused(暂停)、restarting、exited(已退出,口语常叫 stopped)、dead。
数据持久化:容器删了数据还在吗
容器是"用完即焚"的,容器内写的数据会随容器删除而消失。要让数据活下去,就把它放到容器之外——这就是卷(Volume)和绑定挂载(Bind Mount)。
两种挂载Volume vs Bind Mount
| 对比 | Volume(卷) | Bind Mount(绑定挂载) |
|---|---|---|
| 写法 | -v 卷名:/容器路径 | -v /宿主机路径:/容器路径 |
| 由谁管理 | Docker 管理(放在 Docker 目录下) | 你指定宿主机上的具体目录 |
| 典型用途 | 数据库数据等,跨容器共享、更可移植 | 开发时挂源码、配置文件 |
| 相关命令 | docker volume create/ls/rm | 无需创建,直接给路径 |
-v 冒号左边是路径就是 Bind Mount,是卷名就是 Volume;② 删容器时命名卷默认不会被删,需手动 docker volume rm——所以"删容器时卷也会被删"是错误说法。网络:容器怎么通信、怎么被访问
两个问题:① 外面怎么访问到容器(端口映射);② 容器之间、容器和宿主机用什么"网络模式"连接(网络驱动)。
端口映射-p 宿主机端口:容器端口
容器内部端口默认外面访问不到,需要用 -p 映射到宿主机端口,格式恒为 host:container。
网络驱动bridge / host / overlay / macvlan / none
| 驱动 | 说明 |
|---|---|
| bridge | 默认,容器接到虚拟网桥、有自己的网段,靠端口映射对外 |
| host | 容器直接共享宿主机网络栈,无隔离、性能最好,不需端口映射 |
| overlay | 跨多台主机的容器组网(集群/Swarm 常用) |
| macvlan | 给容器分配独立 MAC,像物理机一样接入局域网 |
| none | 不配置网络 |
-p 永远是 host:container;④ CNM 三件套是 Sandbox/Endpoint/Network,Bridge 是驱动不是 CNM 组件。观测与排错:容器到底在干嘛
出问题时靠这几条命令"看现场":看日志、看资源、看进程、看详细配置。记住每条命令"看什么"就够了。
命令地图各看一个维度
| 命令 | 看什么 |
|---|---|
| docker logs | 容器的日志输出 |
| docker stats | 实时资源占用(CPU/内存/网络/IO) |
| docker top | 容器内运行的进程列表 |
| docker inspect | 容器/镜像的详细配置(返回 JSON) |
| docker ps | 容器列表与状态(概览) |
| docker system df | 磁盘占用(镜像/容器/卷) |
- 日志最佳实践:应用把日志输出到 stdout/stderr,由 Docker 日志驱动统一收集;默认日志驱动是
json-file。 - HEALTHCHECK:定期探测容器是否健康,失败时状态变
unhealthy,可用docker inspect查看健康状态。
inspect 返回 JSON;② 看资源用 stats、看进程用 top、看日志用 logs、看磁盘用 system df——别张冠李戴;③ 默认日志驱动是 json-file;④ HEALTHCHECK 失败只标 unhealthy,不会自动重启容器。仓库 Registry:镜像存哪、从哪取
镜像造好后要分发、要复用,就需要一个集中存放的地方。公共的叫 Docker Hub,公司里常自建私有仓库。
概念Docker Hub 与私有仓库
- Docker Hub = 官方公共镜像仓库,
docker pull nginx默认就是从这里拉。 - 私有 Registry 默认监听 5000 端口(自建仓库用
registry镜像)。 - 推送流程:
docker tag加上"仓库地址前缀" →docker login→docker push。
安全与资源限制
容器共享内核 → 隔离不如虚拟机强 → 所以要主动收紧权限、限制资源,别让一个容器拖垮整台机器。
安全能力(Capabilities)与非 root
- 容器隔离弱于虚拟机(共享内核);默认 Docker 会丢弃一批高危能力,所以容器 root ≠ 宿主机完整 root。
- 可用
--cap-add/--cap-drop精确增减 Linux Capabilities,按需收紧权限。 - 应用尽量用非 root 用户运行。
资源限制 CPU 和内存
docker update 改。编排与生态:单机之外的世界
一个容器好管,几十上百个就需要"编排工具"。先认清三个层级的工具,以及底层是谁在真正跑容器。
分层Compose / Swarm / 容器运行时
- Docker Compose:用一个 yml 文件定义并运行多容器应用(单机多服务,如 web+db),一条命令全拉起。
- Docker Swarm:Docker 自带的集群编排(多主机),特性有内置服务发现、滚动更新、overlay 跨主机网络等。
- 容器运行时(runtime):真正在底层创建并运行容器的组件——
containerd、runc、cri-o。
--restart 功能,不是 Swarm 特有;③ kube-proxy 是 K8s 组件,不是容器运行时(runtime 是 containerd/runc/cri-o)。底层原理与运维杂项(查漏补缺)
剩下这些是零散但常考的点:命名空间隔离、存储驱动、重启与清理行为。归到一起扫一遍即可。
底层命名空间与存储驱动
- PID 命名空间让容器有独立的进程编号空间:容器内 PID 与宿主机不同、看不到宿主机进程、容器内第一个进程是 PID 1。容器默认不限制进程数,可用
--pids-limit设上限。 - 存储驱动:
overlay2是当前推荐;devicemapper多用于老 CentOS/RHEL。 docker version/info/system info都能显示 Docker 信息,详略不同。
运维重启与清理
docker container prune # 删所有"已停止"容器
docker system prune # 删停止容器+无用网络+悬空镜像+缓存
overlay2 推荐,aufs 不是 Linux 内核原生支持;② system prune 不会删"正在运行"的容器;③ restart ≈ stop+start;④ 容器默认 pid 无限制;⑤ PID 命名空间隔离 → 上面三条同时成立。