Kubernetes¶
面试追问地图¶
| 主问题 | 必讲关键点 | 下一层追问 |
|---|---|---|
| 集群架构 | API Server、etcd、Scheduler、Controller、kubelet | 声明式与调谐循环 |
| 工作负载 | 无状态、有状态、每节点、批任务 | Headless Service、滚动更新 |
| Pod 生命周期 | 调度、拉镜像、容器启动、探针、终止 | Pending/CrashLoopBackOff 排查 |
| 探针 | 启动、流量、存活三种语义 | 重启风暴、优雅摘流量 |
| 调度 | 过滤、打分、亲和性、污点容忍 | 拓扑分散、优先级抢占 |
| 资源 | 调度依据、cgroup 限制、QoS | CPU throttling、OOMKilled |
| 网络 | ClusterIP、服务发现、七层入口 | kube-proxy、EndpointSlice、NetworkPolicy |
| 存储 | 供给、声明、动态制备、访问模式 | StatefulSet、回收策略 |
| 弹性 | 指标、期望副本数、稳定窗口 | 冷启动、突发流量、VPA 冲突 |
| 发布 | readiness、preStop、优雅停机、PDB | 滚动参数、数据库兼容 |
| 排障 | Events、状态、日志、资源、网络 | Pending、OOMKilled、流量不通 |
容器镜像、JVM 容器内存和 CI/CD 入门见Linux与工程化;服务网格见系统设计。
一、架构与工作负载¶
Kubernetes 控制面和节点组件如何协作?¶
频次 ★★★★★ · 难度 🔴 · 高频:字节/阿里
| 组件 | 核心职责 |
|---|---|
| kube-apiserver | 所有状态读写入口,负责认证、鉴权、准入和 API |
| etcd | 保存集群期望状态和元数据 |
| kube-scheduler | 为未绑定节点的 Pod 选择 Node |
| kube-controller-manager | 运行 Deployment、Node 等控制器的调谐循环 |
| kubelet | 让本节点 Pod 的实际状态逼近期望状态 |
| 容器运行时 | 通过 CRI 创建和管理容器 |
| kube-proxy/网络实现 | 实现 Service 转发;部分 eBPF 方案可替代 kube-proxy 数据面 |
创建 Deployment 不是 API Server 直接启动容器:API Server 持久化期望状态,控制器创建 ReplicaSet 和 Pod,Scheduler 绑定节点,目标节点 kubelet 再调用运行时启动容器。每个控制器持续比较 spec 与实际状态并调谐,这就是声明式系统的核心。
常见追问:etcd 为什么重要?→ 它保存控制面状态;业务容器数据通常不在 etcd。etcd 故障会影响控制面变更,但已运行 Pod 不会因此立即停止。
Deployment、StatefulSet、DaemonSet、Job 如何选择?¶
频次 ★★★★★ · 难度 🟡 · 高频:全厂
| 工作负载 | 适用场景 | 关键能力 |
|---|---|---|
| Deployment | 无状态 Web/API | 副本、滚动更新、回滚 |
| StatefulSet | 数据库、注册中心等有状态服务 | 稳定序号、网络身份、持久卷绑定、顺序操作 |
| DaemonSet | 日志/监控/网络 Agent | 每个匹配节点运行一个 Pod |
| Job | 有完成条件的一次性任务 | 失败重试、完成计数 |
| CronJob | 周期性创建 Job | Cron 调度、并发策略、历史保留 |
StatefulSet 只提供稳定身份和编排顺序,不自动让数据库具备复制、一致性和备份能力。把 MySQL 放进 StatefulSet 不等于获得高可用。
Pod 从创建到运行经历什么?¶
- API Server 校验并保存 Pod。
- Scheduler 选择节点并写入绑定结果。
- 节点 kubelet 观察到 Pod,准备 Volume 和网络。
- 运行时拉取镜像,依次运行 init container,再启动应用容器。
- startup/readiness/liveness 探针开始工作。
- Pod 删除时进入 Terminating,执行
preStop,发送终止信号并等待宽限期。
Pod 是可替换对象,不应把本地文件系统当作可靠持久化。容器重启发生在原 Pod 内;Pod 被重建后 UID 和 IP 都可能变化。
二、健康检查与资源¶
startup、readiness、liveness 探针如何配合?¶
频次 ★★★★★ · 难度 🟡 · 高频:全厂
| 探针 | 回答的问题 | 失败动作 |
|---|---|---|
| startup | 应用是否已经完成启动 | 启动成功前不运行另外两类探针,持续失败则重启 |
| readiness | 现在是否适合接流量 | 从 Service 后端移除,不重启 |
| liveness | 进程是否陷入无法自愈状态 | 重启容器 |
下游数据库暂时不可用通常只应影响 readiness,不能直接让 liveness 失败;否则所有实例会同时重启,进一步放大故障。探针接口应轻量,不做深度全链路调用。
常见追问:只配置 liveness 有什么问题?→ 新实例可能尚未预热就接流量;发布摘流量也没有 readiness 状态控制。
requests、limits 和 QoS 如何影响调度与驱逐?¶
频次 ★★★★★ · 难度 🔴 · 高频:字节/美团
requests:调度器预留和选择节点的依据,也是 CPU 份额竞争的重要基础。limits:容器运行上限;CPU 超限通常被节流,内存超限可能触发 cgroup OOM kill。Guaranteed:每个容器 CPU/内存 request 等于 limit,节点压力下最不易被驱逐。Burstable:至少配置了某项 request/limit,但不满足 Guaranteed。BestEffort:未配置 request/limit,最先被驱逐。
JVM 的 -Xmx 不能等于容器 memory limit,还要给 Metaspace、线程栈、直接内存和 native 库留空间。退出码 137 和 OOMKilled 的排查见操作系统。
CPU limit 为什么会让延迟抖动?¶
CPU 是可压缩资源,超过 limit 后进程被 CFS/cgroup 节流而非杀死。平均 CPU 看似不高,短时间突发仍可能耗完配额并等待下个周期,表现为 P99 延迟尖刺。排查应同时看 CPU 使用率与 throttled seconds/periods,不能只看平均值。
三、调度与弹性¶
Scheduler 如何为 Pod 选择节点?¶
频次 ★★★★ · 难度 🟡
调度分为过滤和打分:先排除资源不足、污点不容忍、亲和性不满足的节点,再按资源、亲和性和拓扑等策略打分,选出目标节点。
- nodeSelector/NodeAffinity:把 Pod 放到具有指定标签的节点。
- PodAffinity/AntiAffinity:按其他 Pod 的位置聚合或打散。
- taint/toleration:节点拒绝普通 Pod,只有容忍该污点的 Pod 才有资格调度;容忍不代表一定调度过去。
- topology spread constraints:把副本按可用区/节点均匀分散,降低单故障域风险。
硬反亲和规则过强会让扩容 Pod 长期 Pending。生产中通常优先用拓扑分散和软偏好,再为真正隔离需求使用硬约束。
HPA 如何决定扩缩容?¶
频次 ★★★★ · 难度 🟡
HPA 周期读取资源或自定义指标,按“当前指标 / 目标指标”估算期望副本数,并通过容忍区间和稳定窗口降低抖动。CPU 利用率型指标以 request 为基准,request 未配置时可能无法得到有效利用率。
扩容不是即时容量:新 Pod 还要调度、拉镜像、启动和预热。突发流量需要预留容量、快速指标和限流兜底;只依赖 HPA 会在冷启动窗口内过载。HPA 调副本数,Cluster Autoscaler/节点自动扩缩调节点容量,两者解决不同层次。
四、网络与配置¶
Service、Ingress 和 Gateway API 分别解决什么?¶
频次 ★★★★★ · 难度 🟡 · 高频:全厂
| 对象 | 作用 |
|---|---|
| Service | 为一组动态 Pod 提供稳定虚拟 IP/DNS 和四层访问入口 |
| Ingress | 用规则描述 HTTP/HTTPS 外部入口,需 Ingress Controller 实现 |
| Gateway API | 用 Gateway、HTTPRoute 等角色化资源表达更丰富的流量治理 |
Service 通过 label selector 关联 Pod,并由 EndpointSlice 保存实际后端。请求不通时应沿链路检查:DNS → Service → EndpointSlice → Pod IP/端口 → readiness → NetworkPolicy,而不是先重启 Pod。
ClusterIP、NodePort、LoadBalancer、Headless Service 如何选择?¶
- ClusterIP:集群内部访问的默认类型。
- NodePort:每个节点开放端口,常作为外部负载均衡的底层能力,不宜直接作为复杂生产入口。
- LoadBalancer:请求云平台或实现提供外部负载均衡器。
- Headless(
clusterIP: None):不提供虚拟 IP,DNS 直接返回 Pod 地址,常与 StatefulSet 做节点发现。
ConfigMap 和 Secret 有什么边界?¶
ConfigMap 保存非敏感配置,Secret 表达敏感数据,但默认 base64 只是编码,不是加密。生产应结合 etcd 静态加密、RBAC 最小权限、外部密钥系统和轮换策略。环境变量注入后不会自动刷新;Volume 投影可更新文件,但应用仍要支持重载。
五、存储与发布¶
PV、PVC、StorageClass 如何解耦存储?¶
频次 ★★★★ · 难度 🟡
- PV:集群中的一块存储资源。
- PVC:工作负载对容量、访问模式和 StorageClass 的声明。
- StorageClass:描述动态制备器和参数,PVC 可据此自动创建 PV。
- CSI:存储插件标准接口,把具体存储实现与 Kubernetes 解耦。
删除 PVC 后数据是否保留取决于 PV 回收策略。数据库扩容、快照和跨可用区恢复必须按具体存储能力设计,不能只看 PVC 处于 Bound。
如何做到 Kubernetes 应用无损发布?¶
频次 ★★★★★ · 难度 🔴 · 高频:全厂
- 新 Pod 完成 startup 和 readiness 后才进入后端。
- 旧 Pod 终止时先变为 NotReady,并给 EndpointSlice/负载均衡传播留时间。
preStop触发应用摘流量或短暂等待,进程收到 SIGTERM 后停止接新请求。- 在
terminationGracePeriodSeconds内等待在途请求、MQ 消费和线程池结束。 - 超时后 kubelet 发送 SIGKILL,因此宽限期必须覆盖真实最长收尾时间。
- 用 PDB 限制自愿中断时同时不可用的副本数,并设置合理滚动更新参数。
PDB 不能阻止节点宕机,也不保证应用健康;它只约束驱逐等自愿中断。数据库变更还需遵循“先兼容旧代码、再发布新代码、最后清理旧结构”的扩展/收缩模式。
六、排障¶
Pod 异常时如何建立排障顺序?¶
频次 ★★★★★ · 难度 🔴 · 高频:全厂
kubectl get pod -o wide:看阶段、重启次数、节点和 IP。kubectl describe pod:看 Conditions 和 Events,判断调度、拉镜像、挂载、探针问题。kubectl logs --previous:容器重启时查看上一次日志。- 核对 Deployment/Pod spec、镜像、环境变量、Volume 和 Service EndpointSlice。
- 查节点资源、驱逐、CNI/CSI 和控制面事件。
| 现象 | 优先方向 |
|---|---|
| Pending | 资源不足、污点、亲和性、PVC 未绑定 |
| ImagePullBackOff | 镜像名、凭证、仓库网络、拉取策略 |
| CrashLoopBackOff | 上一次日志、启动命令、配置、探针、退避重启 |
| OOMKilled/137 | limit、JVM 总内存、泄漏、节点压力 |
| Running 但无流量 | readiness、Service selector、EndpointSlice、端口、NetworkPolicy |
| Terminating 卡住 | finalizer、Volume 卸载、preStop 和进程不响应 SIGTERM |
CrashLoopBackOff 是重启退避状态,不是根因;根因通常在容器退出码、上一次日志或 Events 中。