Docker 与 K8s 原理大纲

这份你不要只背几个名词,而是要真正建立这条主线:

应用为什么要容器化 -> Docker 到底解决了什么 -> 为什么只有 Docker 还不够 -> K8s 为什么会出现 -> 它怎样把大量容器和服务治理起来

如果你之前对这块不熟,这份就按“从零理解到能面试”的节奏来读。


一、总纲

这部分最核心的 10 条主线:

  1. 为什么应用交付会越来越依赖容器化
  2. 镜像、容器、Dockerfile 分别是什么
  3. 容器和虚拟机到底差在哪
  4. Docker 底层为什么能做隔离和资源限制
  5. 为什么只有 Docker 还不够
  6. K8s 的核心思想为什么是期望状态和持续收敛
  7. Pod / Deployment / Service / Ingress 为什么要拆成不同对象
  8. 探针、发布、回滚、扩缩容为什么属于治理能力
  9. 控制面组件各自在做什么
  10. 这整套东西最后怎样服务你的项目和面试表达

二、先别急着背 Docker,先理解它为什么会出现

1. 传统部署最常见的问题是什么

在没有容器化之前,应用部署经常会遇到这些问题:

  • 开发机能跑,测试机跑不起来
  • 测试机能跑,线上依赖版本不一样
  • 不同服务部署方式不统一
  • 回滚很麻烦
  • 环境一多,排查越来越痛苦

所以真正的问题不是“程序能不能跑”,而是:

应用如何被稳定、重复、标准化地交付。

2. Docker 解决的核心问题到底是什么

Docker 解决的不是单纯“打包方便”,而是:

  • 应用和依赖一起交付
  • 运行环境尽量一致
  • 启动方式标准化
  • 服务边界更清晰

你可以把 Docker 理解成:

把“应用怎么跑”收敛成一个标准交付单元。

3. 为什么这件事对工程特别重要

因为服务越来越多之后,你真正痛苦的往往不是:

  • 代码写不出来

而是:

  • 部署怎么统一
  • 依赖怎么控制
  • 发布怎么标准化
  • 回滚怎么简单

Docker 先把这层问题解决掉。


三、Docker 到底是什么

1. 一句话理解

Docker 是一套容器化工具链,用来把应用、依赖、运行方式打包成标准化交付单元,并以容器形式运行。

2. 你面试里更稳的说法

Docker 的重点不是一个命令,而是它让应用交付从“手工配环境”变成“基于镜像的标准化运行”。

3. Docker 里最容易混的几个概念

  • Image
  • Container
  • Dockerfile
  • Registry
  • Volume
  • Network

这几个一定要分清。


四、镜像、容器、Dockerfile 分别是什么

1. 镜像是什么

镜像是静态模板。

你可以理解成:

  • 一份打包好的应用文件快照
  • 加上一套“这个应用该怎么运行”的说明

镜像本身不是真在跑的进程,它更像:

  • 可复制、可分发、可复用的运行模板

2. 容器是什么

容器是镜像运行后的实例。

它更像:

  • 真正在机器上跑起来的进程环境

所以镜像和容器的关系,可以这样记:

  • 镜像像“类”
  • 容器像“对象实例”

或者更通俗点:

  • 镜像像“模具”
  • 容器像“用模具生产出来、正在运行的成品”

3. Dockerfile 是什么

Dockerfile 是构建镜像的脚本。

它定义的是:

  • 基础镜像是什么
  • 要安装什么依赖
  • 代码放到哪里
  • 工作目录是什么
  • 容器启动时执行什么命令

所以 Dockerfile 的本质不是语法题,而是:

定义“这个应用如何被标准化构建成镜像”。

4. Registry 是什么

Registry 是镜像仓库。

比如:

  • 本地构建好镜像
  • 推到仓库
  • 线上再拉下来运行

所以一条完整交付链路通常是:

代码 -> Dockerfile -> 镜像 -> Registry -> 容器运行


五、镜像为什么要分层

这块是很常见的原理追问。

Docker 镜像不是一个黑盒大压缩包,它通常是分层构建的。

1. 分层有什么好处

  • 构建时可以复用缓存
  • 分发时可以减少重复传输
  • 相同基础层能被多个镜像共享
  • 镜像结构更适合工程治理

2. 为什么面试要知道这个

因为它直接影响:

  • 构建速度
  • 镜像大小
  • CI/CD 效率
  • 安全扫描成本

3. Dockerfile 层顺序为什么很重要

因为变化少的层应该尽量放前面,比如:

  • 基础环境
  • 系统依赖
  • 包依赖

变化快的层尽量放后面,比如:

  • 业务代码

这样缓存更容易命中。

4. 多阶段构建为什么常被推荐

因为构建环境和运行环境往往不是一回事。

比如:

  • 构建阶段需要编译工具链
  • 运行阶段只需要最终产物

多阶段构建可以把:

  • 编译工具
  • 临时文件
  • 构建依赖

留在前一阶段,不带到最终运行镜像里。

这样做的好处是:

  • 镜像更小
  • 分发更快
  • 启动更快
  • 攻击面更小

六、容器和虚拟机到底差在哪

这题特别高频,而且很多人答得太浅。

1. 虚拟机是什么思路

虚拟机更偏硬件虚拟化。

一般会有:

  • 虚拟硬件
  • 独立操作系统
  • 更完整的隔离边界

所以它更像:

  • 每个应用都带一台自己的“小电脑”

2. 容器是什么思路

容器更偏操作系统层隔离。

多个容器通常:

  • 共享宿主机内核
  • 各自有隔离的进程视图、网络视图、挂载视图

所以它更像:

  • 很多应用住在同一台楼里,但每个应用有自己的独立房间

3. 为什么容器通常更轻

因为容器不需要每个实例都带完整 OS。

所以通常会表现为:

  • 启动更快
  • 资源开销更小
  • 交付更轻

4. 为什么容器不等于绝对安全隔离

这点说出来会比较加分。

因为容器本质上共享宿主机内核,它不是完整虚拟机级别的完全隔离。

所以容器更适合:

  • 标准化交付
  • 轻量部署
  • 资源利用率优化

但不要把它理解成:

  • 天然绝对安全沙箱

七、Docker 底层为什么能做容器

你不一定要背源码,但至少要知道这几个关键词:

  • namespace
  • cgroup
  • union filesystem

1. namespace 在干什么

namespace 主要解决的是:

  • 看起来彼此隔离

它可以隔离很多视图,比如:

  • 进程
  • 网络
  • 挂载点
  • 主机名

这也是为什么容器里的进程会感觉自己像独立运行环境。

2. cgroup 在干什么

cgroup 主要解决的是:

  • 资源限制和资源统计

比如:

  • CPU
  • 内存
  • IO

所以它回答的是:

  • 这个容器最多能用多少资源
  • 这个容器现在用了多少资源

3. union filesystem 在干什么

它主要服务镜像分层和文件系统叠加。

简单理解就是:

  • 基础层在下面
  • 业务层叠在上面
  • 容器运行时还有自己的可写层

这也是为什么镜像可以层层复用。

4. 一句话怎么讲 Docker 底层

容器不是魔法,本质上是 Linux 提供的隔离、资源控制和分层文件系统能力,再加上一套镜像和运行时标准。


八、除了镜像和容器,为什么还要关心 Volume 和 Network

1. Volume 在解决什么

容器本身更像临时运行实例。

如果把重要数据只写在容器内部,可重建时很容易丢。

所以像下面这些内容通常要认真设计持久化:

  • 数据库数据
  • 上传文件
  • 部分日志
  • 缓存落盘目录

所以 Volume 的本质是在回答:

  • 容器删了,哪些数据还要保留

2. Network 在解决什么

容器不是只会单独运行,它们往往还要互相通信。

Docker Network 主要解决:

  • 容器间通信
  • 服务名解析
  • 网络隔离

比如:

  • PHP 调 MySQL
  • 应用调 Redis
  • 服务调消息队列

这些通信关系通过容器网络被标准化。


九、为什么只有 Docker 还不够

这一步非常关键。

Docker 解决的是:

  • 一个容器怎么打包
  • 一个容器怎么运行

但当你的服务越来越多,就会出现新的问题:

  • 多副本怎么管理
  • 机器挂了怎么自动恢复
  • 服务之间怎么发现彼此
  • 发布怎么滚动进行
  • 出问题怎么快速回滚
  • 怎么做自动扩缩容
  • 集群资源怎么调度

这时候问题已经不再是“容器能不能跑”,而是:

很多容器、很多服务、很多实例,怎么稳定治理。

这就是 K8s 出现的原因。


十、K8s 到底是什么

1. 一句话理解

Kubernetes 是容器编排和治理平台。

2. 更稳的说法

Docker 解决单个容器交付,K8s 解决大量容器实例在集群里的调度、发布、服务发现、故障恢复和扩缩容。

3. 为什么它不是“更高级的 Docker”

这个区分很重要。

Docker 更偏:

  • 镜像构建
  • 容器运行
  • 单机交付

K8s 更偏:

  • 集群管理
  • 多实例治理
  • 声明式运维
  • 持续收敛

所以它们解决的问题层次不同。


十一、K8s 的核心思想为什么是“期望状态”

这句话一定要真正听懂:

你告诉它想要什么状态,它持续把实际状态往期望状态拉齐。

1. 这是什么意思

比如你声明:

  • 我要 3 个副本
  • 镜像版本是 v2
  • 对外暴露成一个 Service
  • 健康探针通过后才能接流量

K8s 不会只是执行一次命令然后结束,而是会持续盯着:

  • 是不是真的有 3 个副本
  • 版本是不是 v2
  • 挂掉的实例有没有被补起来
  • 流量是不是只打到健康实例

2. 为什么这很重要

因为集群环境天然不稳定:

  • 节点会挂
  • Pod 会崩
  • 发布会失败
  • 资源会紧张

如果没有“持续收敛”,系统很快就会偏离你原本想要的状态。

3. 这就是 K8s 和“只会起容器”的根本区别

它不是一次性执行工具,而是持续治理系统。


十二、K8s 核心对象到底为什么这样拆

这块别只背名词,要理解职责边界。

1. Pod

Pod 是 K8s 的最小调度单元。

它不是简单等于一个容器,而是:

  • 一组协同运行的容器单元

它们通常会:

  • 共享网络
  • 共享部分存储
  • 生命周期绑定

2. 为什么 Pod 不直接等于容器

因为现实里很多时候,一个业务单元不一定只有一个容器。

比如:

  • 主业务容器
  • sidecar 代理
  • 日志采集容器

这些放在同一个 Pod 里更合理。

所以 K8s 管的是:

  • 协同运行单元

而不是单纯的容器进程列表。

3. Deployment

Deployment 管的是:

  • 我要多少副本
  • 用哪个版本
  • 怎么滚动更新
  • 出问题怎么回滚

它关心的不是“某一个 Pod”,而是:

  • 这组无状态服务的期望运行形态

4. Service

Service 主要解决:

  • 服务发现
  • 稳定访问入口
  • 集群内部负载均衡

因为 Pod 自己的 IP 并不稳定。

所以 Service 的意义就是:

  • 给一组动态变化的 Pod 一个相对稳定的访问方式

5. Ingress

Ingress 更偏集群外部入口。

主要解决:

  • 域名入口
  • URL 路由
  • TLS
  • 外部统一流量入口

你可以把它理解成:

  • Service 是内部稳定门牌号
  • Ingress 是外部入口总闸

6. ConfigMap / Secret

它们解决的是:

  • 配置和镜像解耦

也就是说:

  • 镜像只负责应用本体
  • 配置在运行时注入

这样才能做到:

  • 同一镜像多环境复用
  • 改配置不一定重打镜像
  • 敏感信息和普通配置分开治理

7. Namespace

Namespace 主要做逻辑隔离。

它常用来区分:

  • 团队
  • 环境
  • 业务域

所以 Namespace 更像:

  • 集群里的逻辑分区

十三、为什么 Deployment、探针、发布、回滚这么重要

线上不是“跑起来就结束”,而是:

  • 怎么平滑更新
  • 怎么避免中断
  • 出问题怎么退回
  • 怎么判断实例能不能接流量

1. readinessProbe 在解决什么

readiness 负责回答:

  • 这个实例现在能不能安全接流量

如果没准备好,就不应该把请求打过去。

2. livenessProbe 在解决什么

liveness 负责回答:

  • 这个实例是不是已经坏掉,需要被拉起

3. 为什么这两个不能混

因为:

  • readiness 关注的是“能不能接流量”
  • liveness 关注的是“要不要重启”

如果混用,很容易出现:

  • 服务还没准备好就接请求
  • 服务假死却没人拉起
  • 发布时流量被打到不稳定实例

4. Deployment 为什么是治理核心之一

它能把:

  • 副本数
  • 新旧版本替换
  • 滚动发布
  • 回滚

统一起来。

所以它的价值不在于“多一个 YAML 对象”,而在于:

把发布从手工动作变成持续可控的治理动作。


十四、资源请求、限制和调度到底在解决什么

1. requests 是什么

你可以把 requests 理解成:

  • 调度时至少需要多少资源

调度器会看:

  • 哪个节点有足够资源容纳它

2. limits 是什么

limits 更像:

  • 运行时最多允许吃到多少资源

3. 为什么这不是“随便填两个数字”

因为这会直接影响:

  • 调度结果
  • 节点资源利用率
  • 服务稳定性

如果 requests 配太大:

  • 调度会更困难
  • 资源利用率可能变差

如果 limits 太松:

  • 服务可能把机器吃爆

如果 requests 太小:

  • 真实流量一上来就不稳

4. Scheduler 为什么重要

调度器的核心问题其实是:

  • 这堆 Pod 到底放到哪台机器更合适

它要考虑的不是一个单点配置,而是:

  • 资源是否足够
  • 节点约束
  • 污点容忍
  • 亲和 / 反亲和
  • 负载分布

所以 K8s 的调度本质上也是治理能力的一部分。


十五、扩缩容为什么不只是“副本数加一减一”

1. 手动扩缩容

更适合:

  • 明确可控场景
  • 运维人工介入

2. 自动扩缩容

比如 HPA,适合:

  • 负载波动明显
  • 指标可观测
  • 服务相对无状态

3. 为什么自动扩缩容不是万能药

因为扩出来的不只是副本数,而是一整条链路压力。

还要考虑:

  • 下游数据库扛不扛得住
  • Redis、MQ、第三方接口会不会成为瓶颈
  • 限流和熔断是否到位

所以扩缩容不是“魔法按钮”,而是:

  • 在指标、资源和系统瓶颈之间做平衡

十六、K8s 控制面组件怎么理解

你不一定要背源码,但至少要知道这些名字是干什么的。

1. apiserver

它是集群控制入口。

你可以把它理解成:

  • 所有声明、查询、变更请求的总入口

2. etcd

它负责保存集群状态数据。

简单理解就是:

  • 集群的状态数据库

3. scheduler

它负责决定:

  • 新 Pod 应该调度到哪个节点

4. controller-manager

它负责:

  • 持续让实际状态逼近期望状态

所以它和“持续收敛”这件事高度相关。

5. kubelet

它是节点上的执行代理。

它负责:

  • 接收控制面下发的任务
  • 在节点上把 Pod 真正跑起来
  • 汇报运行状态

6. kube-proxy

它主要和 Service 的网络转发相关。

简单理解就是:

  • 帮 Service 把流量导到后端 Pod

7. 一句话串起来

可以这样记:

  • apiserver:入口
  • etcd:状态存储
  • scheduler:决定放哪
  • controller-manager:持续收敛
  • kubelet:节点执行
  • kube-proxy:服务网络转发

十七、从代码到线上 Pod 的完整链路

这块很适合你面试时讲成一条线。

一条典型链路

  1. 开发写代码
  2. 用 Dockerfile 构建镜像
  3. 镜像推到 Registry
  4. 发布系统更新 Deployment 的镜像版本
  5. apiserver 接收这次变更
  6. controller-manager 发现期望状态变了
  7. scheduler 给新的 Pod 选择节点
  8. 节点上的 kubelet 拉镜像并启动容器
  9. readinessProbe 通过后,Pod 才开始接流量
  10. Service / Ingress 把流量转发过来
  11. 如果新版本异常,Deployment 可以暂停、回滚

如果你能把这条链讲顺,Docker 和 K8s 这块就已经不像“只会背名词”了。


十八、常见误区

1. “有 Docker 就等于有 K8s”

不对。

Docker 解决交付,K8s 解决集群治理。

2. “K8s 就是起容器的平台”

太浅了。

它更核心的是:

  • 声明式管理
  • 发布治理
  • 服务发现
  • 故障恢复
  • 扩缩容

3. “Pod 就等于容器”

不对。

Pod 是调度单元,容器是运行组件。

4. “探针就是随便配个接口”

不对。

探针直接影响:

  • 流量是否打进来
  • 故障实例是否被拉起
  • 发布过程是否稳定

5. “扩容一定能解决性能问题”

不对。

如果瓶颈在:

  • 数据库
  • 第三方接口
  • 锁竞争
  • 单线程热点

那单纯扩 Pod 不一定有用。


十九、如果你不是平台 owner,面试里怎么讲最稳

很多人会担心:

  • 我不是专门做 K8s 平台的
  • 这块会不会讲不深

其实你不需要装成平台专家。

更稳的说法是:

我不是 K8s 平台侧最深的 owner,但我知道 Docker 解决的是应用交付标准化,K8s 解决的是多服务、多副本、多环境下的部署治理。我能讲清镜像、容器、Pod、Deployment、Service、Ingress、探针、扩缩容这些对象分别在解决什么问题,也理解它们最终是为稳定发布、资源利用率和服务治理服务的。

这样既真实,又够面试。


二十、30 秒版怎么答

Docker 解决的是应用和依赖的标准化交付,把代码、环境和启动方式打包成镜像,再以容器运行;K8s 解决的是大量容器在集群里的调度、服务发现、滚动发布、故障恢复和扩缩容。我的理解重点不是背平台名词,而是知道它们分别在解决交付问题和治理问题。

二十一、1 分钟版怎么答

我会把 Docker 和 K8s 分成两层看。Docker 主要解决的是应用交付标准化,比如镜像、容器、Dockerfile、分层构建、环境一致性;它底层依赖 namespace、cgroup 和分层文件系统来实现隔离和资源控制。K8s 则是在 Docker 之上进一步解决多服务、多实例、多环境的治理问题,比如 Pod、Deployment、Service、Ingress、ConfigMap、Secret、探针、扩缩容和回滚。它最核心的思想是期望状态和持续收敛,也就是你声明想要什么状态,系统持续把实际状态往目标状态拉齐。

二十二、3 分钟版怎么答

我理解 Docker 和 K8s 其实是两层不同的问题。Docker 解决的是单个应用怎么被标准化交付,它把应用、依赖、启动方式打包成镜像,再以容器运行。镜像是静态模板,容器是运行实例,Dockerfile 定义构建过程,底层依赖 namespace 做隔离、cgroup 做资源控制、union filesystem 做镜像分层。这样可以让开发、测试、预发、线上环境尽量一致,也让服务发布和回滚更标准。

但只有 Docker 还不够,因为当服务数量和实例数量变多之后,你会遇到调度、服务发现、滚动发布、故障恢复、配置管理、扩缩容这些问题,这就是 K8s 出现的原因。K8s 的核心思想不是“帮你起容器”,而是声明式管理和持续收敛。比如你声明要 3 个副本、某个镜像版本、某个 Service 暴露方式,K8s 会持续维持这个目标状态。

它为什么拆成 Pod、Deployment、Service、Ingress、ConfigMap、Secret 这些对象,也是因为每个对象在解决不同职责:Pod 是最小调度单元,Deployment 管副本和发布回滚,Service 负责内部服务发现,Ingress 负责外部流量入口,ConfigMap 和 Secret 负责配置解耦。再往下还有 readiness/liveness 探针、requests/limits、HPA、scheduler、controller-manager 这些治理能力。

如果把这套东西挂回项目,我会重点讲它们带来的价值不是“平台名词很多”,而是部署更标准、发布更平滑、回滚更可控、资源治理更清晰。即使我不是平台侧最深的 owner,我也能把这些对象在解决什么问题讲清楚。


二十三、继续深挖建议

如果你想把这块再讲得更像做过的人,可以继续看:

那篇会更偏:

  • 从零理解
  • 从代码到 Pod 的完整链路
  • 常见误区
  • 面试怎么讲得更自然