FROM ZERO · 把名词一次讲明白

Docker 不是虚拟机,
它是给应用打包的「集装箱」

这是一份讲义,不是题库。我们按"每个东西到底解决什么问题"把 Docker 拆成 10 个模块,每块都先用大白话和类比讲清楚,配上流程图与对比表。遇到容易考、容易混的地方,会用一个橙色的「考点」小框单独点一下,帮你记牢。建议从上往下读一遍。

镜像 image容器 containerDockerfileVolumenetworkregistrycompose
01

Docker 到底是什么

一句话:Docker 让你把"应用 + 它需要的整套运行环境"打包成一个标准盒子,在任何机器上都能原样跑起来。理解它最快的方式,是和虚拟机对比。

Docker vs 虚拟机:核心差异在"内核"

类比:虚拟机像在你家盖一整栋独立的房子——自带地基、水电、操作系统,笨重但彻底隔离;Docker 容器像在同一栋楼里隔出一个个房间,大家共用一套地基和水电(宿主机内核),只是各自上锁。所以容器更轻、启动更快,但隔离没有虚拟机那么彻底。
  • 虚拟机:每台 VM 有自己独立的操作系统内核,靠 Hypervisor 虚拟出一套硬件 → 重、慢、隔离强。
  • 容器:所有容器共享宿主机的同一个 Linux 内核,只是把进程、文件系统、网络隔离开 → 轻、秒级启动、性能损耗极小。
考点
容器既然共享内核,就没有"独立内核"。所以凡是说容器优势是"完全隔离的内核"的,都是错的。容器相对虚拟机的真优势是:启动快、占资源少、性能损耗小。

三大件的关系:镜像 → 容器 → 仓库

整个 Docker 世界就围绕三个东西转,先记住这张流程图,后面所有模块都是在补充它的细节:

📜
Dockerfile
构建脚本
一份"配方",写明用什么底座、装什么、怎么启动
build
📦
Image
镜像(只读模板)
打包好的"集装箱蓝图",只读、可复制、分层
run
🚢
Container
容器(运行实例)
镜像跑起来后的活进程,可读写、可启停删
📡 仓库 Registry(如 Docker Hub)是存放镜像的"码头仓库":用 docker push 上传镜像,用 docker pull 下载别人的镜像。镜像 ⇄ 仓库,容器从不直接进仓库。
记忆钩子:镜像 = 菜谱+食材打包好的速冻盒(只读、可无限复制);容器 = 把盒子加热端上桌的那一份饭(吃了就少了,可以再热一份);仓库 = 超市冷柜(存放和取用速冻盒的地方)。
考点
镜像是"只读模板";可读写的、跑起来的那个是"容器"。两者别说反:镜像不是运行实例,容器才是。
02

镜像 Image:怎么造、怎么管

镜像是 Docker 里最核心的一块。搞懂三件事就行:它由 Dockerfile 构建、采用分层存储、并有一整套造/搬/存/删的命令。

Dockerfile造镜像的"配方"

Dockerfile 是一行行指令,从底座开始一层层往上叠。常见指令:

  • FROM — 指定基础镜像(底座,如 alpinejava:11)。
  • RUN — 构建时执行命令(装软件等)。每条 RUN 都会生成一个新层,所以习惯把多条命令合并、顺手清缓存,镜像才小。
  • COPY / ADD — 把文件放进镜像(区别见下表)。
  • CMD / ENTRYPOINT — 指定容器启动时跑什么(区别见下表)。
对比COPYADD
基本复制复制本地文件/目录复制本地文件/目录
自动解压本地 tar不支持支持
从 URL 下载不支持支持
建议能用 COPY 就用 COPY(行为更明确)仅在确需解压/下载时用
对比CMDENTRYPOINT
角色默认命令/默认参数固定入口(主程序)
能否被 run 覆盖能被 docker run 后的参数覆盖默认不被覆盖(需 --entrypoint)
两者同时存在CMD 充当 ENTRYPOINT 的默认参数(最终命令 = ENTRYPOINT + CMD)
考点
① ADD 比 COPY 多了"自动解压 + URL 下载";② CMD 被 run 覆盖、ENTRYPOINT 不易被覆盖,二者同时存在时 CMD 当默认参数;③ 指定镜像入口点的指令是 ENTRYPOINT(填空常考)。

分层 / 多阶段镜像为什么是一层层的

类比:镜像像 PS 里的图层叠加。底层(系统)很多镜像都一样,就只存一份、大家共享(写时复制 CoW);你改动时只新增/改写最上面薄薄一层。
  • 分层的好处:省存储(共享底层)、加速构建(命中缓存的层不重建)、便于分发共享。
  • 多阶段构建(multi-stage):先在"编译阶段"用大镜像编译,再把成品拷进一个干净的小镜像,显著减小最终体积。
  • digest(摘要):对镜像内容算出的 SHA256,内容一变就变,用来精确锁定不可变的镜像(image@sha256:...);而 tag 只是版本标签、可移动、可重复。
考点
① 分层好处不包括"提高安全性";② 多阶段构建的目的是减小最终镜像体积;③ tag 区分版本,digest 才唯一标识内容,别搞反。

命令镜像的造、搬、存、删

docker build -t myapp:1.0 . # 按 Dockerfile 构建镜像
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。
03

容器运行:docker run 与进容器

镜像跑起来就是容器。核心是把 docker run 的常用参数记牢,以及"怎么进到一个正在跑的容器里看一看"。

docker run启动容器的常用参数

docker run -d # 后台运行(detached)
  --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。
docker exec -it 容器ID bash # 进入运行中的容器,开一个交互 shell

其中 -i 保持输入打开、-t 分配伪终端,通常一起用。

考点
"进入正在运行的容器"标准答案是 docker exec(attach 也能连但语义不同;run 是启动新容器;login 是登录仓库)。

状态容器有哪些状态

官方状态:created(已创建未启动)、runningpaused(暂停)、restartingexited(已退出,口语常叫 stopped)、dead

考点
"suspended" 不是 Docker 容器状态——这是常见的迷惑选项。
04

数据持久化:容器删了数据还在吗

容器是"用完即焚"的,容器内写的数据会随容器删除而消失。要让数据活下去,就把它放到容器之外——这就是卷(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——所以"删容器时卷也会被删"是错误说法。
05

网络:容器怎么通信、怎么被访问

两个问题:① 外面怎么访问到容器(端口映射);② 容器之间、容器和宿主机用什么"网络模式"连接(网络驱动)。

端口映射-p 宿主机端口:容器端口

容器内部端口默认外面访问不到,需要用 -p 映射到宿主机端口,格式恒为 host:container

docker run -p 8080:80 nginx # 访问 宿主机:8080 → 进入 容器:80

网络驱动bridge / host / overlay / macvlan / none

驱动说明
bridge默认,容器接到虚拟网桥、有自己的网段,靠端口映射对外
host容器直接共享宿主机网络栈,无隔离、性能最好,不需端口映射
overlay跨多台主机的容器组网(集群/Swarm 常用)
macvlan给容器分配独立 MAC,像物理机一样接入局域网
none不配置网络
CNM(容器网络模型)三组件:Sandbox(容器的网络隔离环境)、Endpoint(连接点)、Network(一组可互通 Endpoint 的集合)。
考点
vxlan 是底层封装协议,不是 Docker 网络驱动;② host 模式性能最好、共享宿主机网络栈;③ -p 永远是 host:container;④ CNM 三件套是 Sandbox/Endpoint/Network,Bridge 是驱动不是 CNM 组件
06

观测与排错:容器到底在干嘛

出问题时靠这几条命令"看现场":看日志、看资源、看进程、看详细配置。记住每条命令"看什么"就够了。

命令地图各看一个维度

命令看什么
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,不会自动重启容器。
07

仓库 Registry:镜像存哪、从哪取

镜像造好后要分发、要复用,就需要一个集中存放的地方。公共的叫 Docker Hub,公司里常自建私有仓库。

概念Docker Hub 与私有仓库

  • Docker Hub = 官方公共镜像仓库,docker pull nginx 默认就是从这里拉。
  • 私有 Registry 默认监听 5000 端口(自建仓库用 registry 镜像)。
  • 推送流程:docker tag 加上"仓库地址前缀" → docker logindocker push
考点
Registry 默认端口是 5000;别和 daemon 的 2375(非加密)/ 2376(TLS) 管理端口混淆。Docker Hub 的角色是"镜像仓库"。
08

安全与资源限制

容器共享内核 → 隔离不如虚拟机强 → 所以要主动收紧权限、限制资源,别让一个容器拖垮整台机器。

安全能力(Capabilities)与非 root

  • 容器隔离弱于虚拟机(共享内核);默认 Docker 会丢弃一批高危能力,所以容器 root 宿主机完整 root。
  • 可用 --cap-add / --cap-drop 精确增减 Linux Capabilities,按需收紧权限。
  • 应用尽量用非 root 用户运行。

资源限制 CPU 和内存

docker run --cpus=1.5 --memory=512m myapp docker update --memory=1g 容器ID # 运行后还能改
考点
① 正确做法是用 Linux Capabilities 限权;② 默认容器 root 权限不等于宿主机 root(已丢弃高危能力);③ CPU 和内存可同时限制,且运行后能用 docker update 改。
09

编排与生态:单机之外的世界

一个容器好管,几十上百个就需要"编排工具"。先认清三个层级的工具,以及底层是谁在真正跑容器。

分层Compose / Swarm / 容器运行时

  • Docker Compose:用一个 yml 文件定义并运行多容器应用(单机多服务,如 web+db),一条命令全拉起。
  • Docker Swarm:Docker 自带的集群编排(多主机),特性有内置服务发现、滚动更新、overlay 跨主机网络等。
  • 容器运行时(runtime):真正在底层创建并运行容器的组件——containerdrunccri-o
层级类比:runc/containerd 是"发动机"(真正跑容器),Docker 引擎是"整车",Compose 是"一键发动一队车",Swarm/Kubernetes 是"调度整个车队的指挥中心"。
考点
① Compose 的作用 = 定义并运行多容器应用;② "自动容器重启"是单机 Docker 的 --restart 功能,不是 Swarm 特有;③ kube-proxy 是 K8s 组件,不是容器运行时(runtime 是 containerd/runc/cri-o)。
10

底层原理与运维杂项(查漏补缺)

剩下这些是零散但常考的点:命名空间隔离、存储驱动、重启与清理行为。归到一起扫一遍即可。

底层命名空间与存储驱动

  • PID 命名空间让容器有独立的进程编号空间:容器内 PID 与宿主机不同、看不到宿主机进程、容器内第一个进程是 PID 1。容器默认不限制进程数,可用 --pids-limit 设上限。
  • 存储驱动:overlay2 是当前推荐;devicemapper 多用于老 CentOS/RHEL。
  • docker version / info / system info 都能显示 Docker 信息,详略不同。

运维重启与清理

docker restart 容器 # ≈ 先 stop 再 start
docker container prune # 删所有"已停止"容器
docker system prune # 删停止容器+无用网络+悬空镜像+缓存
考点
overlay2 推荐,aufs 不是 Linux 内核原生支持;② system prune 不会删"正在运行"的容器;③ restart ≈ stop+start;④ 容器默认 pid 无限制;⑤ PID 命名空间隔离 → 上面三条同时成立。