14 面试题集
属于 K8s Code 教程 · 收口篇 上一篇:13 故障排查与生产实践
20 道题把前面 13 章收口:对象实操、控制器编程、调度与安全、生产排障,从"会用 kubectl"问到"能手写 Operator"。仓库 S7 的面试题集有 6 道理论题打底,这份是它的超集——多了 client-go、Informer、Reconcile、调度细节这些只有动手写过才答得上来的题。
怎么用这份题集
- 先自答:看题名,闭卷口头回答 1 分钟,能说几句说几句,别翻答案。
- 再对照要点:看"答案要点",把你自己漏掉的点用红笔(或便签)标出来,这往往就是你的盲区。
- 最后练追问链:每题的"追问"是面试官真正会连环问的方向,两人一组互问,或自己对着镜子把"答案 → 追问 → 再追问"走三遍,直到不卡壳。
面试真相:答案人人会背,追问才是分水岭。每题都练到"追两层不倒",这份题集才算吃透。
第一部分:对象实操(第 02-06 章)
Q1:为什么最小调度单位是 Pod,而不是直接调度容器?
考察点: 对"Pod 是什么"的本质理解,以及同 Pod 容器共享什么。
答案要点: 同 Pod 的容器共享网络命名空间(同一个 IP 和端口空间,互访走 localhost)和存储卷,适合"强耦合、同生共死"的组合;调度、扩缩容、健康检查、重启都以 Pod 为整体单位;Pod 是对"一组进程要一起跑"这个需求的抽象,容器本身太细、Node 又太粗。
追问:Pod 里多个容器怎么访问彼此? 直接 localhost:端口,端口不能冲突;什么场景该放一个 Pod? 主服务 + 日志采集 sidecar、主服务 + 本地代理这类强耦合场景,没强耦合就各开 Deployment。
关联: 第 02 章 仓库文档:架构与核心对象
Q2:Deployment 滚动更新是怎么做的?怎么保证不宕机?
考察点: 控制器思维 + 发布策略细节,K8s 面试出现率最高的题之一。
答案要点: 更新时生成新的 ReplicaSet,按 maxSurge(最多超配几个新 Pod)和 maxUnavailable(最多允许几个旧 Pod 不可用)逐步"起新删旧";新 Pod 必须通过 readiness 探针才被 Service 接管流量,所以发布全程可用实例数不低于阈值;回滚用 kubectl rollout undo deployment/<name>,本质是切回旧 ReplicaSet。
追问:readiness 不过会怎样? 新 Pod 不进 Endpoints、发布卡住但不宕机——这正是期望行为;怎么控制发布速度? 调小 maxSurge 或加大 maxUnavailable 能降速,配 progressDeadlineSeconds 超时自动回滚。
关联: 第 03 章 仓库文档:架构与核心对象
Q3:Service 是怎么找到 Pod 的?
考察点: label selector、Endpoints、kube-proxy 三层机制是否打通。
答案要点: Service 用 label selector 选中一组 Pod,把它们的 IP 列表写进 Endpoints;Pod 增删时控制器自动同步 Endpoints,挂掉的 Pod 会被剔除;kube-proxy 把 Service 的虚拟 IP 转成节点上的 iptables/IPVS 规则,流量到任意节点都能转发到目标 Pod。
追问:ClusterIP 的 IP 是真实存在的吗? 不是,是 kube-proxy 维护的虚拟 IP,只有集群内可达;Pod 重建后 Service 会变吗? Service 的 IP 和名字都不变,变的只有 Endpoints——这正是"Pod 随时会死、Service 永远稳定"的稳定性设计。
关联: 第 04 章 仓库文档:网络与存储
Q4:Ingress 和 Service 的区别?
考察点: 四层/七层分层的理解,别把两者混为一谈。
答案要点: Service 是四层(TCP/UDP)负载均衡,在集群内提供稳定的虚拟 IP,类型有 ClusterIP/NodePort/LoadBalancer;Ingress 是七层(HTTP/HTTPS)入口,按域名和路径把请求路由到不同 Service,还能做 TLS 终止;Ingress 本身不干活,背后是 Ingress Controller(如 Nginx)在转发。
追问:访问一个服务有哪几种方式? ClusterIP 集群内、NodePort 节点端口、Ingress 域名七层、LoadBalancer 云厂商四层;什么时候用 Ingress 而不是直接 NodePort? 多服务共享一个入口、要按域名/路径分流、要 HTTPS 时。
关联: 第 04 章 仓库文档:网络与存储
Q5:三种探针分别管什么?有哪些经典坑?
考察点: 探针语义 + 滚动发布的联动,S7 题集的加强版。
答案要点: liveness 管"进程活不活",失败就重启容器;readiness 管"能不能接流量",失败只摘流量不重启;startup 管"慢启动保护",运行期间暂停 liveness,给 JVM/加载大模型这类慢启动应用防误杀。三者实现方式都是 httpGet/tcpSocket/exec 三选一。
追问:只配 liveness 不配 readiness 会出什么事? 滚动更新时新 Pod 还没就绪就被打流量,直接 502;探针卡住不返回会怎样? 会一直等,Pod 可能卡在启动流程里——所以探针接口要快,别在健康检查里查数据库。
关联: 第 02 章 仓库文档:高可用与故障排查
Q6:requests 和 limits 的区别?内存超限会怎样?
考察点: 资源语义 + OOM 机制,答出"调度依据 vs 使用上限"就及格。
答案要点: requests 是最低资源需求,是调度依据(节点得先"够得着"才把 Pod 放上去);limits 是使用上限:CPU 超限被限速(throttle,变慢但活着),内存超限直接被杀(OOMKilled,exit 137);kubelet 重启被杀容器,反复崩就成了 CrashLoopBackOff。
追问:Go 服务怎么避免 OOM? 设 GOMEMLIMIT 为容器 limits 的 70~80%,给 Go 运行时留余量;K8s 怎么给 Pod 分 QoS? 按 requests/limits 的组合分 Guaranteed / Burstable / BestEffort 三档,内存紧张时驱逐顺序 BestEffort 最先。
关联: 第 06 章 仓库文档:高可用与故障排查
Q7:HPA 的原理是什么?
考察点: 控制循环思维,能画出"采集 → 计算 → 调整"的闭环。
答案要点: HPA 是个控制器:周期性地通过 metrics-server 拉取目标指标(默认 CPU 利用率),用"当前用量 / requests"算出期望副本数,再调整 Deployment 的 replicas;副本数有 minReplicas/maxReplicas 上下限,扩缩有冷却时间防止抖动;缩放的是 Deployment,真正干活的是它背后的 ReplicaSet。
追问:HPA 为什么依赖 metrics-server? 它要读指标,metrics-server 挂了 HPA 就退化成"不干活";能按自定义指标扩缩吗? 可以,配 Prometheus Adapter 把业务指标(如队列长度、QPS)接进来。
关联: 第 06 章 仓库文档:调度与控制器
第二部分:控制器编程(第 07-10 章)
Q8:client-go 的分层结构?各层管什么?
考察点: 是否真的写过 client-go,还是只背过名字。
答案要点: 顶层是 typed client(kubernetes.Clientset),按资源类型提供强类型 CRUD,简单场景够用;中间层是 Informer(本地缓存 + Watch 增量更新)和 Lister(读缓存);底层是 RESTClient 与 reflectors,负责跟 API Server 通信。上层依赖下层,Controller 的标准组合是 typed client + informer + workqueue。
追问:为什么 Controller 不直接用 typed client 轮询? 轮询浪费 API Server 资源且不及时,Informer 的 Watch 是"服务端推送",事件驱动更高效;Cache 和 API Server 的数据会不一致吗? 会,Informer 缓存有秒级延迟,所以"读缓存、写 API"是约定。
关联: 第 07 章 仓库文档:S7 无对应篇目(K8s Code 独有编程内容)
Q9:Informer 为什么存在?解决了什么问题?
考察点: 对 Watch 机制和本地缓存的深入理解,09 章手写 Controller 的基石。
答案要点: Informer 解决两个问题:一是免轮询——通过 Watch 监听 API Server 的资源变更推送,增量事件即时到达;二是免重复请求——把全量对象缓存到本地,控制器读 Lister 就行,不用每次都打 API Server。它还有 Relist 兜底:Watch 断线后自动重新 List 全量再续 Watch,保证缓存不错。
追问:Watch 断线了怎么办? Informer 的 Reflector 会自动 relist + 重新 watch,这是它内部机制,对使用者透明;两个 Controller 监听同一资源会怎样? 各自有独立 Informer 和缓存,互不干扰,这也是多控制器共享 API Server 不出错的原因。
关联: 第 08 章 仓库文档:S7 无对应篇目(K8s Code 独有编程内容)
Q10:Workqueue 解决了什么问题?为什么 Controller 不能直接处理事件?
考察点: 事件处理背压、去重、重试机制,client-go 编程的高分题。
答案要点: 直接处理 Watch 事件有三个问题:事件洪峰来了处理不过来、同一对象的连续事件重复处理浪费、处理失败没有重试机制。Workqueue 解决了:去重(同一 key 排队中不重复入队)、限速(指数退避重试,避免打爆 API Server)、背压(队列自然积压,处理方按自己的速度消费)。
追问:Workqueue 里存的是什么? key(namespace/name),不是对象本身——处理时再去 Lister 取最新对象,保证"处理的是最新状态";为什么要指数退避? 失败重试如果立刻打回去,可能把 API Server 打挂,退避是保护控制面。
关联: 第 08 章 仓库文档:S7 无对应篇目(K8s Code 独有编程内容)
Q11:Reconcile 为什么必须幂等?控制器和事件驱动开发有什么区别?
考察点: 控制器"期望状态 vs 实际状态"的核心理念,会写 Controller 的试金石。
答案要点: Reconcile 是"以期望状态为准、把实际状态拉齐"的纯函数,K8s 不保证它只被调用一次——事件会重复触发、重试会重复执行,所以函数必须幂等:同一输入反复执行结果一致;实现上"声明式"而非"命令式":只检查当前状态缺什么、补什么,而不是"我要求加一个"。
追问:Reconcile 怎么避免重复创建资源? 先查再建(Get 不到才 Create),创建时带 ownerReference 保证级联;为什么要看对象是否被删除(DeletionTimestamp)? 删除中对象不能重建,否则永远删不掉。
关联: 第 09 章 仓库文档:调度与控制器
Q12:CRD 和 Operator 是什么关系?
考察点: 扩展 K8s 的完整心智:先有自定义资源,再有人"管"它。
答案要点: CRD(CustomResourceDefinition)只是"声明了一种新资源类型",它让 API Server 认识并存储这种对象,但没有任何行为;Operator = CRD + 控制该 CRD 的 Controller,把运维经验(部署、备份、扩缩容)编码成自动化逻辑;所以"定义 CRD 不算 Operator,写了控制器才是"。
追问:什么场景值得写 Operator? 有状态应用、需要运维动作自动化的场景(数据库、消息队列、模型服务);controller-runtime 帮你做了什么? 封装了 Manager、Informer、Workqueue、leader 选举,你只需实现 Reconcile 一个方法。
关联: 第 10 章 仓库文档:S7 无对应篇目(K8s Code 独有编程内容)
第三部分:调度、网络与安全(第 11-12 章)
Q13:调度器的两阶段是什么?
考察点: 过滤 → 打分 的两步思维,能解释"为什么 Pod 去了那台机器"。
答案要点: 调度分两阶段:**过滤(Predicates)**先筛掉不合格节点——资源不够 requests、端口冲突、污点不容忍、亲和性不满足的直接出局;**打分(Priorities)**再给剩余节点打分——资源余量、Pod 分布均衡度等,选最高分的落子。过滤是"能不能",打分的"好不好"。
追问:没有节点通过过滤会怎样? Pod 留在 Pending,调度器持续重试,describe 里能看到具体失败原因;requests 和调度什么关系? 过滤阶段按 requests(不是实际用量)判断节点够不够,所以 requests 虚高会浪费调度空间。
关联: 第 11 章 仓库文档:调度与控制器
Q14:污点(Taint)和容忍(Toleration)是什么?
考察点: 节点侧"拒绝"与 Pod 侧"申请入场"的配合机制,和亲和性是反过来的。
答案要点: 污点打在节点上,声明"这台机器有特殊限制,默认不接收 Pod";容忍打在 Pod 上,声明"我能接受这个污点,请让我调度上来";两者配对才放行。典型用途:专用节点(GPU 机器只给 AI 任务)、控制面节点不跑业务 Pod(master 自带 NoSchedule 污点)。
追问:污点有三种效果? NoSchedule(不调度新 Pod)、PreferNoSchedule(尽量不调度)、NoExecute(不调度且驱逐已在跑的不容忍 Pod);怎么把某个 Pod 固定到专属节点? 节点打污点 + 目标 Pod 加容忍,比 nodeSelector 更"干净"。
关联: 第 11 章 仓库文档:调度与控制器
Q15:NetworkPolicy 管什么?怎么用?
考察点: 默认全通 vs 白名单的模型,以及"谁来实现它"。
答案要点: K8s 默认 Pod 间全互通,NetworkPolicy 是白名单:用 label selector 选中一组 Pod,声明"允许谁从哪来、访问哪个端口";规则分 ingress(入站)和 egress(出站)两个方向。它本身只是声明,需要 CNI 插件(如 Calico)来真正执行规则。
追问:不声明 NetworkPolicy 的 Pod 会怎样? 默认不受限,流量全通——想安全必须显式声明;Namespace 之间默认通吗? 通,加一条"拒绝所有跨 namespace 入站"的策略才能隔离。
关联: 第 12 章 仓库文档:网络与存储
Q16:RBAC 三件套是什么?怎么给 Pod 授权?
考察点: 主体 → 角色 → 绑定 的授权模型,最小权限原则。
答案要点: 三件套是:Subject(谁,User/Group/ServiceAccount)、Role/ClusterRole(能干什么,一组 rules:资源 + 操作 verb)、RoleBinding/ClusterRoleBinding(把谁绑到哪个角色上);Pod 里跑的程序通过 spec.serviceAccountName 指定 ServiceAccount,它决定了 Pod 内的 client-go 能对 API Server 干什么。
追问:Role 和 ClusterRole 什么区别? Role 限定在某个 namespace,ClusterRole 集群级(还能授权 ClusterRole 资源本身);为什么默认 SA 权限要最小化? 容器被攻破后,SA 的权限就是攻击者的权限——生产必须显式建最小权限 SA,别用 default。
关联: 第 12 章 仓库文档:S7 无对应篇目(K8s Code 独有编程内容)
第四部分:生产与收口(第 13 章)
Q17:etcd 和 API Server 各自是什么角色?
考察点: 控制面两大件分工:状态存储 vs 唯一入口。
答案要点: etcd 是集群的"账本",存所有资源的最终状态,用 Raft 保证一致性;API Server 是唯一入口:所有 kubectl、控制器、调度器的读写都经过它,它负责鉴权(RBAC)、校验、把写操作落到 etcd、把变更通过 Watch 推给订阅者。其他组件谁也不直接碰 etcd,全走 API Server。
追问:etcd 挂了会怎样? 集群"失忆"——API Server 读不到状态,控制器没法自愈,存量 Pod 照跑但一切变更和自愈停摆;为什么控制器不直连 etcd? 直连会导致写冲突和鉴权失控,全部收敛到 API Server 一个入口才能统一管。
关联: 第 01/13 章 仓库文档:架构与核心对象 高可用与故障排查
Q18:容器被删除时发生了什么?怎么实现优雅退出?
考察点: SIGTERM/SIGKILL 机制 + terminationGracePeriodSeconds,Go 服务实战高频题。
答案要点: 删除/重启容器时,kubelet 先发 SIGTERM,应用应借此停止接新请求、处理完存量请求、释放资源,然后退出;K8s 等 terminationGracePeriodSeconds(默认 30 秒)后仍不退就发 SIGKILL 强杀;Go 服务标准实现是 signal.NotifyContext 监听 SIGTERM + http.Server.Shutdown 带超时。
追问:不处理 SIGTERM 会怎样? 白等 30 秒被强杀,存量请求被掐断、滚动更新被拖慢;grace 期设多大合适? 比应用"清完存量请求的最坏时间"略大即可,别设成 10 分钟——K8s 要批量删 Pod,每个都磨蹭整个发布就卡死。
关联: 第 13 章 仓库文档:高可用与故障排查
Q19:集群高可用是怎么做的?
考察点: 控制面 vs 数据面的可用性分层,多数派与 leader 选举。
答案要点: 数据面(Node)挂 = 业务挂,靠多副本 + 控制器补齐;控制面要高可用:多个 API Server 挂 LB,请求打哪个都行;etcd 跑 3/5 节点 Raft 多数派写(3 节点容忍挂 1 个,5 节点容忍挂 2 个);Controller Manager 和 Scheduler 多副本 + leader 选举,同时只有一个在干活。控制面短暂不可用 = 存量业务照跑,但无法变更、无法自愈。
追问:etcd 挂超过半数会怎样? 无法达成多数派,集群只读不写,等于"失忆且冻结";为什么 etcd 要奇数节点? 偶数节点不提高容错(4 节点还是只能挂 1 个),还多花钱、多同步开销。
关联: 第 13 章 仓库文档:高可用与故障排查
Q20:故障排查的口诀是什么?分别对应什么命令?
考察点: 实战排障流程的完整度,能说出每个状态的第一排查命令。
答案要点: 口诀是 get 看状态、describe 看事件、logs 看日志,必要时 exec 进容器复现。细化:Pending 看 describe 的调度事件;ImagePullBackOff 看 describe 的拉取事件 + 核对镜像名;CrashLoopBackOff 用 logs --previous 看上次崩溃日志;OOMKilled 看 exit 137 + Limits;Evicted 用 kubectl top node 看节点压力;NodeNotReady 看节点 Conditions 和 kubelet。
追问:kubectl get events 怎么排障? 用 --sort-by='.count' 一眼看出高频失败事件,用 field-selector 只看目标对象;describe 和 logs 哪个信息更关键? 各管一摊:describe 说"K8s 视角发生了什么"(调度、探针、驱逐),logs 说"应用自己说了什么",两者要合起来看。
关联: 第 13 章 仓库文档:高可用与故障排查
自测清单
逐题自问,全部答上才算过关(追问能再追一层算优秀):
- [ ] Q1 Pod 与容器关系 - [ ] Q2 滚动更新 - [ ] Q3 Service 原理 - [ ] Q4 Ingress vs Service
- [ ] Q5 三种探针 - [ ] Q6 requests vs limits - [ ] Q7 HPA 原理 - [ ] Q8 client-go 分层
- [ ] Q9 Informer 为什么存在 - [ ] Q10 Workqueue 模式 - [ ] Q11 Reconcile 幂等 - [ ] Q12 CRD 与 Operator
- [ ] Q13 调度两阶段 - [ ] Q14 污点容忍 - [ ] Q15 NetworkPolicy - [ ] Q16 RBAC 三件套
- [ ] Q17 etcd 与 API Server - [ ] Q18 优雅退出 - [ ] Q19 集群高可用 - [ ] Q20 故障排查口诀
20 题 + 追问链全通,K8s Code 教程收口。回头看这份题集你会发现:Q1-Q7 是"会用 kubectl",Q8-Q12 是"会写控制器",Q13-Q20 是"能上生产"——三个阶段,你都已经走完了。