Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 14 章 Kubernetes 与 Docker

容器和 Kubernetes 已经成为现代应用交付的默认底座,但它们的价值并不只是“把程序打包起来”。真正重要的是:用统一镜像交付环境,用声明式控制面管理运行状态,用调度、网络和发布机制把单机部署问题变成集群工程问题。

容器化的价值与边界

容器化解决的第一件事是环境一致性。开发、测试、生产使用同一镜像,能够显著降低“我这里能跑”这类问题。第二件事是交付效率,应用启动、回滚、扩缩容都被标准化。第三件事是资源隔离,不同服务在同一台机器上也能有较清晰的 CPU、内存和文件系统边界。

维度容器虚拟机
启动速度秒级分钟级
资源开销更轻更重
隔离粒度进程级,共享内核OS 级,隔离更强
适用场景微服务、CI/CD、弹性部署强隔离、多操作系统环境

但容器化并不是免费午餐。它不会自动解决状态管理、跨机网络、安全基线和故障治理。一个常见误解是“上了 Kubernetes 就天然高可用”,实际上如果应用本身没有做好无状态、健康检查、优雅退出和资源约束,集群只会更快地把问题放大。

Docker 基础模型

Docker 的基础模型可以概括为“镜像 + 容器 + 运行时隔离”。

镜像是分层构建出来的只读模板,容器是在镜像最上层叠加一个可写层后的运行实例。镜像分层的价值在于复用、缓存和分发:基础层不变时,只需要重建变更层;不同应用也可以共享公共基础镜像。

机制作用
Image Layer复用构建结果,提升发布效率
Namespace隔离进程、网络、挂载点等资源视图
Cgroup限制 CPU、内存等资源使用
Union FS把多层镜像叠加成统一文件系统视图

Namespace 负责“看见什么”,例如 PID、Network、Mount、UTS;cgroup 负责“最多能用多少”,例如 CPU 和内存限额。两者结合后,容器在宿主机上仍然是普通进程,只是拥有更独立的资源视图和限制。

工程上几个非常重要的实践是:

  • 镜像尽量精简,减少无关依赖和攻击面。
  • 一个容器优先承载一个主进程,避免职责混乱。
  • 明确设置 CPU/Memory 限额,不要依赖默认无限制。
  • 应用日志输出到标准输出,避免把容器当长期文件服务器。

Kubernetes 核心对象

Kubernetes 的核心不是“帮你起容器”,而是通过声明式资源对象持续逼近期望状态。你提交 YAML 描述目标,控制器不断把实际状态拉回目标状态。

对象作用典型场景
Pod最小调度与运行单元运行一个或多个紧耦合容器
Deployment管理无状态 Pod 副本和发布Web 服务、API 服务
StatefulSet管理有稳定身份的实例数据库、队列、存储节点
DaemonSet每个节点运行一个 Pod日志采集、Node 监控
Job/CronJob一次性或周期性任务数据修复、定时清理
Service为 Pod 提供稳定访问入口集群内服务发现和负载均衡
Ingress七层路由入口域名、路径转发与 TLS
ConfigMap/Secret注入配置与密钥环境差异配置、凭证管理

控制平面里,API Server 是统一入口,Scheduler 决定 Pod 放到哪台 Node,Controller Manager 负责副本收敛,etcd 保存集群期望状态。Node 上的 kubelet 负责本机 Pod 生命周期,kube-proxy 或其他网络组件负责服务转发。

理解这些对象的关键,不是记概念,而是记住它们各自解决的层次:Pod 解决运行单元,Deployment/StatefulSet 解决编排和生命周期,Service/Ingress 解决访问路径。

调度、发布与服务治理

调度本质上是在资源、约束和可用性之间找平衡。Scheduler 会综合节点资源、亲和性、污点容忍、拓扑分布和调度策略来选择 Node。调度失败时最常见的原因不是“集群坏了”,而是请求的资源太大、节点标签不匹配,或者被污点挡住了。

发布层面,Deployment 最常见的能力是滚动更新与回滚。一个稳定的发布链路通常要具备以下元素:

能力作用
Rolling Update分批替换实例,降低整体风险
Readiness Probe只有真正可服务后才接流量
Liveness Probe进程卡死时触发重建
preStop + 优雅终止减少连接被硬切断

服务治理则落在 Service、Ingress 和上层网关策略上。Service 通过虚拟 IP 或 DNS 名把后端 Pod 集合暴露出来,解决 Pod IP 会变化的问题;Ingress 则把域名、路径和 TLS 策略统一收口。面试里如果问“Kubernetes 如何实现服务发现”,核心回答是:Pod 不稳定,Service 提供稳定入口,DNS 再把服务名解析到这个入口。

当业务规模上来后,仅靠“起更多 Pod”还不够,还要关注发布窗口、灰度节奏、连接摘流、依赖超时和跨服务版本兼容,否则发布本身就会成为主要故障源。

网络、配置与资源管理

Kubernetes 网络的基本假设是:每个 Pod 都有独立 IP,Pod 之间默认可互通。不同网络插件会用不同实现方式,但对应用开发者暴露出来的语义尽量统一。

层次关注点
Pod 网络Pod 到 Pod 的直接通信
Service 网络稳定虚拟入口与四层转发
Ingress 网络七层路由、TLS、外部暴露

这套模型带来了两个直接要求。第一,应用不要依赖 Pod IP 稳定不变;第二,网络排障必须区分是容器内监听、Pod 间连通、Service 转发还是 Ingress 配置出了问题。

配置管理上,ConfigMap 适合普通配置,Secret 适合敏感信息,但 Secret 也不是“天然绝对安全”,它解决的是分发与引用,不等于完成密钥全生命周期治理。实践里更重要的是:

  • 配置和镜像分离,避免每次改配置都重做镜像。
  • 敏感信息不要硬编码进镜像和仓库。
  • 关键配置变更要有灰度和回滚路径。

资源管理上,要区分 requestslimitsrequests 决定调度时为 Pod 预留多少资源,limits 决定运行时的上限。如果没有合理设置:

  • requests 太低,会导致节点过度超卖,运行时争抢严重。
  • limits 太低,容易触发 CPU 限流或 OOMKilled。
  • 两者都不设,排障和容量评估都会失真。

集群运维与常见故障

Kubernetes 运维的核心不是背命令,而是建立一套从“控制面健康”到“业务 Pod 状态”的排障路径。最常见的故障状态包括:

状态/现象常见原因优先排查点
Pending调度失败、资源不足、PVC 未绑定describe pod、节点资源、调度事件
ImagePullBackOff镜像地址错误、仓库鉴权失败、网络不通镜像名、Secret、拉取事件
CrashLoopBackOff应用启动即退出、配置错误、依赖未就绪容器日志、启动参数、配置挂载
OOMKilled内存 limit 过低或程序泄漏容器内存曲线、limit 设置、GC/缓存行为
Service 不通selector 错误、端口不匹配、探针未就绪Endpoint、端口映射、readiness 状态

除了业务 Pod,控制平面和节点本身也要监控:

  • 控制面:API Server 延迟、etcd 健康、调度失败率。
  • 节点层:CPU、内存、磁盘、inode、网络丢包。
  • 工作负载层:Pod 重启次数、探针失败、发布耗时。

集群治理中非常高频的几个工程动作是:

  • 清理无效镜像和历史 ReplicaSet,避免节点磁盘被打满。
  • 统一探针、资源、日志格式和标签规范,降低维护成本。
  • 对核心服务做多副本、跨节点分布和 PodDisruptionBudget,减少运维操作带来的抖动。

本章小结

Docker 解决的是标准化打包与隔离运行,Kubernetes 解决的是在集群里持续管理这些运行实例。两者串起来,才构成现代应用交付与运维的基础设施底座。

可以把本章收束为四点:

  • 容器化优先解决环境一致性和交付效率,但不会自动修复应用设计问题。
  • Docker 的关键模型是镜像分层、namespace 和 cgroup。
  • Kubernetes 的关键模型是声明式对象、调度控制和稳定服务入口。
  • 线上稳定性很大程度上取决于探针、资源、发布和排障体系是否健全。

本章面试题与追问

  1. Docker 和虚拟机最大的差异是什么? 追问:为什么说容器更轻,但隔离边界通常弱于虚拟机?

  2. Docker 镜像为什么要做分层? 追问:分层机制如何同时影响构建速度和镜像分发效率?

  3. namespace 和 cgroup 分别解决什么问题? 追问:为什么只做隔离不做资源限制,线上仍然会互相拖垮?

  4. Kubernetes 为什么引入 Pod,而不是直接调度单个容器? 追问:什么场景下一个 Pod 里会放多个容器?

  5. Deployment、StatefulSet、DaemonSet 各自适合什么场景? 追问:为什么数据库类组件通常不建议直接用 Deployment?

  6. Service 和 Ingress 的职责分别是什么? 追问:如果域名能访问到 Ingress,但后端始终 502,你会先查哪一层?

  7. Readiness Probe 和 Liveness Probe 有什么区别? 追问:为什么把启动慢的问题交给 liveness 处理,反而容易造成反复重启?

  8. requestslimits 分别代表什么? 追问:为什么很多 OOMKilled 不是简单“加内存”就能真正解决?

  9. Pod 长时间处于 Pending,通常从哪些方向排查? 追问:如果集群 CPU 看起来还有空闲,但 Pod 仍然调度失败,可能是什么原因?

  10. Kubernetes 线上最常见的故障模式有哪些? 追问:CrashLoopBackOff、ImagePullBackOff、OOMKilled 这三类故障的排查路径有什么不同?