路线图

面试 · 概念解释型

星辉 2026-07-02 阅读 9 min 1,799 字 路线图
面试 · 概念解释型 封面

1. 概念题#

考察对 K8s 核心概念的准确理解,每题含问题与参考答案(300-500 字)。


题目 1:Pod 是什么?为什么它是 K8s 的最小调度单元?#

问题: 请解释 Pod 的概念,以及为什么 K8s 以 Pod 而非 Container 作为最小调度单元。

参考答案:

Pod 是 Kubernetes 中最小的部署和调度单元,一个 Pod 可以包含一个或多个容器。Pod 内的所有容器共享同一个网络 Namespace(共享 IP 和端口空间)、IPC Namespace,并可以通过挂载共享 Volume 实现文件共享。

K8s 之所以以 Pod 而非容器作为最小调度单元,概括为三点:其一,很多场景需要多个容器强耦合运行(主业务容器 + 日志采集/配置热更新/Service Mesh 代理等 sidecar),需同机部署、经 localhost 通信并共享存储;其二,Pod 层面统一承载更丰富的生命周期管理(Init Container、PostStart/PreStop Hook、Startup/Readiness/Liveness 三种探针);其三,以 Pod 为抽象允许底层容器运行时灵活切换(containerd/CRI-O)而不影响上层调度逻辑。完整设计动因见设计理念篇 题1,"为何 Pod 内多容器共享网络命名空间"见设计理念篇 题7。

Pod 内多个容器通过 localhost 直接通信,不需要服务发现。Pod IP 是易失的——Pod 重建后 IP 会变化,因此不能依赖 Pod IP 做服务发现,应通过 Service 来暴露。


题目 2:Service 的职责是什么?有哪些类型?#

问题: 阐述 K8s Service 的职责,以及 ClusterIP、NodePort、LoadBalancer 三种类型的区别。

参考答案:

Service 是 K8s 中为一组 Pod 提供稳定网络访问入口的抽象。由于 Pod IP 是易失的(Pod 删除重建后 IP 会变),Service 通过固定的虚拟 IP(ClusterIP)和稳定的 DNS 名称将流量负载均衡到后端健康的 Pod,解耦了服务消费者与 Pod 实例的直接绑定。("为何要引入 ClusterIP 这层间接、而非让客户端直连 Pod"的完整设计动因见设计理念篇 题4;三种类型的横向对比见对比篇 题3。)

Service 共有四种类型

  • ClusterIP(默认):分配一个集群内部可访问的虚拟 IP,流量通过 kube-proxy 的 iptables(默认)/IPVS/nftables 规则转发到后端 Pod。仅集群内部可访问。
  • NodePort:在每个 Node 上开放一个固定端口(范围 30000-32767),外部流量通过 NodeIP:NodePort → Service → Pod 的路径访问。实现简单但生产环境一般较少直接用,因为端口管理混乱且需要配合外部 LB。
  • LoadBalancer:在 NodePort 基础上,调用云厂商 API 创建外部负载均衡器(如 AWS NLB、阿里云 SLB),将外部流量分发到各节点的 NodePort,再由 kube-proxy 转发到 Pod。是生产环境暴露服务的标准方式。
  • ExternalName:不做任何代理,仅在 CoreDNS 中把 Service 名映射为一条外部 CNAME 记录(如 db.example.com),用于把集群外部服务"伪装"成集群内 Service。

此外,把 clusterIP 设为 NoneHeadless Service 不分配 ClusterIP、不做负载均衡,DNS 直接返回后端 Pod IP 列表,适用于 StatefulSet 或客户端自选后端的场景(它是 ClusterIP 的一种特殊形态,不算第五种类型)。

后端如何被追踪: Service 只声明 selector,真正把"哪些就绪 Pod 是后端"落地的是 EndpointSlice(自 1.21 起默认取代单一 Endpoints 对象,详见题目 20)。kube-proxy watch 这些后端记录来生成转发规则。

externalTrafficPolicy(NodePort/LoadBalancer 才有意义): 默认 Cluster,流量可被转发到任意节点上的 Pod,但节点间转发会做 SNAT,源 IP 丢失(后端看到的是节点 IP);设为 Local 则只转发到本节点的 Pod,保留客户端真实源 IP,但若本节点没有该 Service 的 Pod,流量会被丢弃(需配合外部 LB 的健康检查剔除无端点节点),且可能造成节点间负载不均。需要真实客户端 IP(如风控、限流、审计)时用 Local


题目 3:Deployment 的核心功能是什么?#

问题: 描述 Deployment 控制器的主要功能和适用场景。

参考答案:

Deployment 是 K8s 中最常用的无状态应用控制器,提供了声明式管理 Pod 副本的核心能力。其主要功能包括:

  1. 副本管理:通过 spec.replicas 声明期望的 Pod 副本数,Controller 持续调谐使实际副本数收敛到期望值。
  2. 滚动更新:支持 RollingUpdate 策略,通过 maxSurge(最多超出期望副本数)和 maxUnavailable(最多不可用副本数)控制更新节奏,逐个替换旧版本 Pod,实现零停机发布。
  3. 版本回滚:每次变更自动生成新的 ReplicaSet,历史版本被保留(数量由 revisionHistoryLimit 控制,默认 10),可通过 kubectl rollout undo 快速回滚。
  4. 扩缩容:可通过修改 replicas 或配合 HPA 实现自动水平扩缩。
  5. 暂停/恢复:支持 kubectl rollout pause/resume,便于在发布过程中执行金丝雀验证。

适用场景:Web 服务、API 服务、所有无状态微服务。需要注意的是,Deployment 下的 Pod 名称是随机生成的(如 myapp-7d8f9c-abc12),Pod 之间完全等价、可任意替换。如果有状态需求(固定网络身份、稳定存储、有序启停),则应使用 StatefulSet。


题目 4:StatefulSet 的特点和适用场景是什么?#

问题: StatefulSet 与 Deployment 有何本质不同?适用于哪些场景?

参考答案:

StatefulSet 专为有状态应用设计,与 Deployment 的核心差异在于它保证 Pod 的固定身份、稳定存储和有序启停

  1. 固定 Pod 名称:Pod 名称为 <statefulset-name>-N(如 mysql-0mysql-1),即使 Pod 被重新调度到其他节点,名称不变。
  2. 有序启停:Pod 按序号从 0 到 N-1 依次启动;缩容时反向从 N-1 到 0 依次终止。更新时也遵循此顺序(除非使用 Parallel 策略)。
  3. 稳定存储:每个 Pod 可绑定独立的 PVC,通过 volumeClaimTemplates 声明。Pod 重建后自动重新绑定到同一 PVC,保证数据不丢失。
  4. 稳定的网络身份:配合 Headless Service(clusterIP: None)使用,每个 Pod 获得固定的 DNS 名称,格式为 <pod-name>.<headless-service>.<namespace>.svc.cluster.local

适用场景:MySQL 集群、Redis Sentinel/Cluster、Kafka/ZooKeeper、Elasticsearch 等需要固定网络身份、持久化存储、有序扩缩容的分布式系统。


题目 5:DaemonSet 是什么?典型用途有哪些?#

问题: 解释 DaemonSet 的工作机制和典型使用场景。

参考答案:

DaemonSet 保证集群中每个(或选定)Node 上运行一个 Pod 副本。当新节点加入集群时,DaemonSet 自动在该节点上创建一个 Pod;节点移除时,对应的 Pod 被垃圾回收。

工作机制:DaemonSet Controller 监听 Node 和 Pod 的变化,确保每个符合条件的 Node 上有且仅有一个目标 Pod。可以通过 nodeSelectornodeAffinity 和 Taint/Toleration 限定只在特定节点上运行。

典型场景:

  • 日志采集:每个节点部署 Fluent Bit/Filebeat DaemonSet,采集该节点上所有容器的 stdout/stderr 日志
  • 监控 Agent:node-exporter、dcgm-exporter(GPU 监控)、datadog-agent 等以 DaemonSet 方式运行
  • 网络组件:Calico node、Cilium agent、kube-proxy 等网络插件通常以 DaemonSet 部署
  • 节点安全:安全扫描 agent、合规检查 agent
  • 存储插件:CSI 驱动的 node plugin 组件

注意事项:早期 DaemonSet Pod 由 DaemonSet Controller 直接指定节点,自 1.12 起改由默认调度器(kube-scheduler)通过 NodeAffinity 调度——DaemonSet 会自动给 Pod 注入指向目标节点的 nodeAffinity,并注入对 node.kubernetes.io/unschedulable 等污点的容忍,因此可用 nodeSelectornodeAffinity、Taint/Toleration 精确控制它落在哪些节点。更新策略 updateStrategy 默认是 RollingUpdate(逐节点滚动,可用 maxUnavailable/maxSurge 控制节奏);OnDelete 才是手动模式——只有手动删掉旧 Pod 后才会用新版本重建,适合需要人工把控每台节点更新时机的场景。


题目 6:ConfigMap 的用途与挂载方式有哪些?#

问题: ConfigMap 解决什么问题?有哪些使用方式?修改 ConfigMap 后 Pod 会自动更新吗?

参考答案:

ConfigMap 是 K8s 中保存非敏感配置数据的资源对象,用于将配置与应用镜像解耦。典型配置包括环境变量、配置文件、命令行参数等。

四种使用方式:

  1. 环境变量注入:将 ConfigMap 中的 key-value 注入为容器的环境变量。修改 ConfigMap 后,已运行的 Pod 不会自动更新环境变量,必须滚动重启 Pod。
  2. Volume 挂载:将 ConfigMap 中的 key 作为文件挂载到容器目录。kubelet 会周期性同步 ConfigMap 到挂载目录(默认约 1 分钟),容器内文件会更新,但应用是否热加载取决于应用本身是否监听文件变化(inotify)。
  3. 命令行参数:通过 env 注入后作为容器启动参数。
  4. subPath 挂载:只挂载 ConfigMap 中的单个 key,但这种方式不支持热更新

最佳实践:对于需要热更新的配置(如业务开关),使用 Volume 挂载 + 应用内文件监听;对于静态配置(如数据库连接参数),可使用环境变量或 immutable ConfigMap(不可变,提升性能)。生产环境中推荐"不可变 ConfigMap + 版本化命名"模式,每次配置变更创建新的 ConfigMap(如 app-config-v2),更新 Deployment 引用,触发滚动更新,保证所有 Pod 使用一致配置。


题目 7:Secret 的作用是什么?默认安全吗?#

问题: 解释 Secret 的用途、类型,以及默认存储的安全性限制。

参考答案:

Secret 用于保存敏感信息(密码、Token、API Key、TLS 证书等),将敏感数据与 Pod 定义和容器镜像解耦。支持的类型包括 Opaque(通用键值对)、kubernetes.io/tls(TLS 证书)、kubernetes.io/dockerconfigjson(镜像仓库认证)、kubernetes.io/service-account-token(ServiceAccount Token)等。

安全性分析:

  • Secret 默认以 base64 编码存储,不是加密。任何人只要能访问 Secret 对象或 etcd 数据,都可以解码获取原文。
  • Secret 只能被引用它的 Namespace 内的 Pod 使用,配合 RBAC 控制访问。
  • 以 Volume 挂载的 Secret,kubelet 会在 tmpfs(内存文件系统)上创建文件,不落盘。

生产环境加固措施:

  1. 启用 etcd 静态加密(--encryption-provider-config),让 Secret 在 etcd 中以密文存储
  2. 配合外部密钥管理服务(Vault、AWS Secrets Manager、External Secrets Operator)
  3. 严格的 RBAC 最小权限,限制谁能 get/list Secret
  4. 使用 Sealed Secrets 或 SOPS 加密后存入 Git
  5. 集群审计日志记录 Secret 访问事件

题目 8:PV、PVC、StorageClass 的关系是什么?#

问题: 阐述 PV、PVC、StorageClass 三者之间的抽象层次和工作流程。

参考答案:

K8s 通过三层抽象来管理持久化存储,将"存储供应"和"存储使用"解耦:

  • PersistentVolume(PV):集群管理员创建(或由 StorageClass 动态创建)的存储资源,描述实际存储的位置和属性(NFS 路径、云磁盘 ID、容量、访问模式等)。PV 是集群级别的资源,独立于任何 Namespace。
  • PersistentVolumeClaim(PVC):用户对存储的"申请单",声明需要的容量和访问模式(如 10Gi、ReadWriteOnce)。PVC 属于特定 Namespace。
  • StorageClass:存储的"类别",定义动态创建 PV 的 provisioner(如 ebs.csi.aws.com)、参数(磁盘类型、IOPS)、回收策略等。

绑定流程:

  1. 用户创建 PVC,声明需要 10Gi RWO 存储
  2. 如果已有匹配的 PV(静态分配),Controller 将 PVC 与 PV 一对一绑定
  3. 如果 PVC 指定了 StorageClass,Controller 调用对应的 provisioner 动态创建 PV,然后绑定
  4. Pod 引用 PVC,将 PV 挂载到容器指定路径

AccessMode 说明: RWO(单节点读写)、ROX(多节点只读)、RWX(多节点读写)。PV 有回收策略(Retain 保留/Delete 删除),PVC 被删除后的行为由此决定。


题目 9:Namespace 的作用和限制是什么?#

问题: 解释 Namespace 在 K8s 中的隔离能力和局限性。

参考答案:

Namespace 是 K8s 中逻辑隔离资源的机制,用于在同一个物理集群中划分多个虚拟集群。其主要作用包括:

  • 资源分组:按团队、项目、环境(开发/测试/生产)划分工作空间
  • 访问控制:配合 RBAC(Role → RoleBinding)限定用户/ServiceAccount 的操作范围
  • 资源配额:通过 ResourceQuota 和 LimitRange 限制 Namespace 内的资源使用
  • 网络策略:NetworkPolicy 以 Namespace 为边界进行流量隔离
  • 命名隔离:同一 Namespace 内资源名必须唯一,跨 Namespace 可以同名

局限性(Namespace 不是真正的安全边界):

  1. 集群级资源(Node、PV、StorageClass、CRD)不受 Namespace 限制
  2. ClusterRole 和 ClusterRoleBinding 作用于全集群
  3. 默认情况下,不同 Namespace 的 Pod 可以通过 Service DNS 互相访问(<svc>.<ns>.svc.cluster.local
  4. DNS 全局解析,没有跨 Namespace 的域名隔离

因此,真正的多租户隔离不仅需要 Namespace,还需配合 ResourceQuota、NetworkPolicy、RBAC、节点亲和性、专用节点池等多层手段。


题目 10:Ingress 是什么?与 Ingress Controller 有何关系?#

问题: 阐述 Ingress 资源的作用,以及它依赖 Ingress Controller 的原因。

参考答案:

Ingress 是 K8s 中定义七层(HTTP/HTTPS)流量路由规则的 API 资源,用于将外部 HTTP 请求按域名和路径转发到集群内部 Service。典型的 Ingress 规则包括基于 Host 的虚拟主机路由(api.example.com → api-service)、基于 Path 的路径路由(/api → backend-service)、TLS 终止等。

Ingress 与 Ingress Controller 的关系:

  • Ingress 是规则定义("什么请求转发到哪个 Service"),是一组声明式的 YAML 配置
  • Ingress Controller 是规则执行者,是一个实际运行的反向代理程序,监听 Ingress 资源变化,动态更新代理配置

最常见的 Ingress Controller 是 Nginx Ingress Controller,其他包括 Traefik、HAProxy、Kong、Istio Gateway、AWS ALB Ingress Controller 等。

用户请求链路:外部用户 → LB → Ingress Controller Pod → 根据 Ingress 规则匹配 → Service → Pod

常见故障点:Ingress 配置规则错误(Host/Path 写错)、Service selector 不匹配 Pod label、后端 Pod Readiness 失败、TLS 证书过期、Ingress Controller 自身资源不足。

演进现状(2026): Ingress API 已进入维护冻结状态——不再新增功能,其表达力局限(TCP/UDP、跨 Namespace、细粒度流量拆分只能靠各家 annotation 硬塞,缺乏可移植性)催生了 Gateway API 作为官方继任者(详见对比篇 Gateway API vs Ingress)。存量集群仍可继续用 Ingress,新项目建议直接评估 Gateway API。


题目 11:RBAC 的工作原理是什么?#

问题: 描述 K8s RBAC 的四类核心对象及其关系。

参考答案:

K8s RBAC(Role-Based Access Control)通过四个核心对象实现"谁对什么资源做什么操作"的权限管控:

  • Role:定义一组权限规则(对哪些资源做哪些操作),作用于单个 Namespace
  • ClusterRole:与 Role 相同但作用于全集群,可授权访问 Node、PV、Namespace 等集群级资源
  • RoleBinding:将 Role 绑定到主体(User/Group/ServiceAccount),限定在特定 Namespace
  • ClusterRoleBinding:将 ClusterRole 绑定到主体,作用于全集群

权限规则由 apiGroupsresourcesverbs 三个字段定义:verbs 包含 get、list、watch、create、update、patch、delete 等。

最小权限原则: 只给业务必要的权限。例如监控系统只需 get/list/watch Pod(不需要 delete),CI 系统只需在目标 Namespace 拥有 Deployment 的 create/patch 权限。

ServiceAccount 是 Pod 访问 K8s API 的身份凭证。每个 Pod 默认挂载所在 Namespace 的 default ServiceAccount 的 Token。注意 1.24 的重要变化: 创建 ServiceAccount 不再自动生成一个长期有效的 Secret Token;Pod 通过 projected volume 由 kubelet 调用 TokenRequest API 获取短期、自动轮转、带 audience 绑定的 Token(默认 1 小时轮转、Pod 删除即失效),安全性远高于旧的永久 Secret Token。如果确实需要一个静态 Token(如给外部 CI 用),才手动创建带 kubernetes.io/service-account.name 注解的 Secret。最佳实践是为每个需要访问 API 的应用创建专用 ServiceAccount 并绑定最小权限 Role,而非使用 default ServiceAccount 或直接给 cluster-admin。


题目 12:HPA 扩缩容的计算原理是什么?#

问题: 解释 HPA 期望副本数的计算公式,以及为什么必须设置 resources.requests

参考答案:

HPA(Horizontal Pod Autoscaler)通过 Metrics Server 定期获取 Pod 的资源使用指标,根据公式计算期望副本数:

text
期望副本数 = ceil(当前副本数 × (当前指标值 / 目标指标值))

例如:当前 2 个 Pod,平均 CPU 利用率 80%,目标 50%,则 ceil(2 × 80/50) = ceil(3.2) = 4,HPA 将扩容至 4 个副本。

必须设置 resources.requests 的原因: HPA 计算利用率时,分子是"实际用量",分母是 Pod 声明的 resources.requests。如果不设置 requests,利用率无法计算,HPA 的 TARGETS 列显示 <unknown>,扩缩容不会触发。此外,requests 也是 Scheduler 调度的依据。

关键参数:

  • stabilizationWindowSeconds:缩容稳定窗口(默认 300s),防止流量波动时频繁扩缩
  • behavior:可分别定义 scaleUp 和 scaleDown 的策略(Percent/Pods + periodSeconds)
  • 指标类型:Resource(CPU/内存)、Pods(自定义指标)、Object(服务级别指标)、External(外部系统指标)

内存指标 不建议单独用于 HPA,因为 Java/Go 等语言的 GC 机制导致内存释放缓慢,容易造成只扩不缩的假象。最佳实践是"CPU + 自定义 QPS 指标"组合使用。

本题聚焦概念与公式。 完整调谐流程(指标 API 链路 metrics.k8s.io/custom.metrics.k8s.io/external.metrics.k8s.io、防抖机制、执行与排查)见原理篇 题10;缩容到 0 的事件驱动扩缩见对比篇 题27(KEDA)。


题目 13:etcd 在 K8s 中的角色是什么?#

问题: 阐述 etcd 在 K8s 架构中的角色,以及为什么 etcd 的健康直接影响集群可用性。

参考答案:

etcd 是 K8s 的分布式键值存储,保存集群所有元数据和状态信息。可以将其理解为 K8s 的"数据库"——所有资源对象(Pod、Service、Deployment、ConfigMap 等)的定义和当前状态都存储在 etcd 中。

职责范围:

  • 存储所有资源对象(spec 和 status)
  • 提供 Watch 机制——各 Controller 和 Scheduler 通过监听 etcd 变化触发调谐
  • 支持 Leader Election——Controller Manager 和 Scheduler 通过 etcd 实现高可用

为什么 etcd 的健康至关重要:

  • API Server 是唯一能直接读写 etcd 的组件,如果 etcd 不可用,API Server 无法响应任何请求(包括 kubectl get、kubectl apply)
  • 已运行的 Pod 不受影响(数据面与控制面分离),但无法创建、更新、删除任何资源
  • 所有 Watch 连接断开,Controller 停止调谐

运维关键点:

  • etcd 使用 Raft 共识算法保证一致性,奇数节点部署(3 或 5 个)
  • 磁盘必须是 SSD(NVMe 最好),高磁盘延迟会导致 Raft 心跳超时
  • 定期备份:etcdctl snapshot save,灾难恢复用 snapshot restore
  • etcd 数据增长需要定期 compaction 和 defrag,否则性能下降

题目 14:kube-proxy 的职责和工作模式有哪些?#

问题: kube-proxy 在 K8s 网络中承担什么角色?iptables 和 IPVS 两种模式有何区别?

参考答案:

kube-proxy 是运行在每个 Node 上的网络代理,负责实现 Service 的负载均衡转发。它监听 API Server 中 Service 和 Endpoints 的变化,在节点上维护转发规则,将对 ClusterIP 的访问分发到后端健康的 Pod。

iptables 模式(默认):

  • 每个 Service 对应一批 iptables NAT 规则,通过 DNAT 将 ClusterIP 替换为 Pod IP
  • 流量分发通过 statistic probability 随机选择后端 Pod
  • 缺点:规则数量随 Service 数量线性增长,查找复杂度 O(n)。当集群有 1000+ Service 时,iptables 规则可达数万条,新连接建立延迟可达数百毫秒

IPVS 模式:

  • 用内核级哈希表替代 iptables 链式查找,转发复杂度 O(1)
  • 支持多种负载均衡算法:rr(轮询)、lc(最小连接数)、sh(源地址哈希,会话保持)
  • 大规模集群(>500 Service)必须使用 IPVS 模式,否则 iptables 规则更新会导致明显的连接延迟

nftables 模式(1.33 GA,但仍非默认):

  • 用 nftables 替代老旧的 iptables 后端,规则用 map/verdict 表达,控制面增量更新、数据面查找接近 O(1),解决了 iptables 大规模下规则同步慢、O(n) 查找的历史顽疾
  • 定位是"iptables 的现代化替代",长期看会取代 iptables 成为默认;但当前(1.33/1.34)默认仍是 iptables,需显式设置 mode: nftables 且节点内核/nft 版本要足够新

已移除的模式: 最早的 userspace 模式(kube-proxy 自己在用户态做 TCP 代理)因性能太差已在 1.26 彻底移除,面试若提到它务必说明"已废弃"。

选择建议: 集群 Service 数量超过 200 个就应考虑切换到 IPVS(或条件允许时用 nftables);追求极致可用 Cilium 通过 eBPF 完全绕过 kube-proxy。

相关题目(本题是各模式定义的出处): iptables/IPVS/nftables 三模式的横向对比见对比篇 题14;流量转发的链路机制(iptables 链、conntrack、验证命令)见原理篇 题2;"为何从 userspace 演进到内核级代理"的设计动因见设计理念篇 题6。


题目 15:Pod 的 QoS 等级有哪些?#

问题: 解释 K8s 中 QoS 的三个等级及其对 Pod 驱逐优先级的影响。

参考答案:

K8s 为 Pod 定义了三个 QoS(Quality of Service)等级,由资源声明自动推导,影响节点资源紧张时的存活优先级:

  1. Guaranteed(最高优先级):

    • 条件:Pod 内每个容器的 CPU 和内存都同时设了 requests 和 limits,且 requests == limits
    • 最不容易被回收,内核 oom_score_adj 最低(-997)
  2. Burstable(中等优先级):

    • 条件:至少一个容器设了 CPU 或内存的 requests/limits,但不满足 Guaranteed 的全部条件
    • oom_score_adj 在中间区间(按 request 占节点内存比例动态计算,2~999)
  3. BestEffort(最低优先级):

    • 条件:Pod 内所有容器都没设任何 requests/limits
    • 最先被牺牲,oom_score_adj 最高(1000)

必须分清两套"杀 Pod"机制(面试高频混淆点):

  • kubelet 驱逐(node-pressure eviction):当节点整体资源触及驱逐阈值(memory.available、磁盘 nodefs/imagefs 等低于门槛)时,kubelet 主动、优雅地驱逐整个 Pod。排序规则并非单纯按 QoS:先看 Pod 的资源用量是否超过其 requests,再按 Pod Priority,最后按超出 requests 的量排序——直观效果通常是 BestEffort → Burstable → Guaranteed 依次被驱逐。被驱逐的 Pod 状态为 Evicted
  • 内核 OOMKill(cgroup 级):当单个容器自身内存用量触到它的 memory limit 时,是 Linux 内核的 OOM Killer(不是 kubelet)直接杀掉该容器 cgroup 内的进程。此时只是容器被杀并按 restartPolicy 重启(Pod 不重建),容器 lastState 显示 OOMKilled退出码 137(128+SIGKILL 9)。节点级内存被瞬间打爆、kubelet 来不及驱逐时,也会由内核 system OOM Killer 依据各进程 oom_score_adj(由 QoS 推导)挑受害者。

记忆锚点:limit 超限 = 内核按 cgroup OOMKill 单个容器(137)节点压力 = kubelet 按 QoS/Priority 优雅驱逐整个 Pod(Evicted)。相关退出码:137=OOM/SIGKILL、143=SIGTERM(128+15,优雅停止)、139=SIGSEGV(128+11,段错误)。

生产建议: 核心服务至少 Burstable、关键有状态组件建议 Guaranteed。CPU 是否设 limit 有争议——设了会在超限时被 CFS 限流(throttle)拉高 P99,很多团队 CPU 只设 requests;memory 则必须同时设 requests 和 limits(防止单容器内存泄漏拖垮整个节点),limits 一般设为 requests 的 1.5~2 倍。


题目 16:NetworkPolicy 解决什么问题?#

问题: NetworkPolicy 的用途和基本工作原理是什么?

参考答案:

NetworkPolicy 是 K8s 中控制 Pod 间网络访问的资源,相当于 Pod 级别的"防火墙规则"。它通过 label selector 精确控制哪些 Pod 可以访问哪些 Pod 的哪些端口。

核心能力:

  • Ingress 策略:控制哪些来源可以访问匹配的 Pod
  • Egress 策略:控制匹配的 Pod 可以访问哪些目标
  • 来源/目标可按 Pod Selector、Namespace Selector、IP Block 组合定义

工作原理: NetworkPolicy 本身只是"规则声明",需要 CNI 插件的实际执行。Calico 通过 iptables/eBPF 实现,Cilium 通过 eBPF 实现,Flannel 默认不支持(需额外配置)。云厂商托管 K8s 中需确认 CNI 是否支持(如 AWS EKS 默认 VPC CNI 不支持,需启用 Calico)。

零信任策略最佳实践:

  1. 先创建默认拒绝所有入站流量的策略(podSelector: {}
  2. 再按需白名单放行:允许同 Namespace、允许监控抓取、允许 DNS 查询(UDP/TCP 53)
  3. 打开 default-deny-egress 时务必先放行 DNS,否则所有服务 DNS 解析失败

题目 17:PersistentVolume 的回收策略有哪些?#

问题: 解释 PV 的 Retain、Delete、Recycle 三种回收策略及其适用场景。

参考答案:

PV 的回收策略决定了 PVC 被删除后关联 PV 的处理方式:

  1. Retain(保留)

    • PVC 删除后,PV 变为 Released 状态,不会被删除
    • 底层存储资源(云磁盘/NFS)不会被自动删除
    • 管理员需要手动清理 PV 和后端存储数据后,才能让该 PV 重新可用
    • 适用场景:需要数据审计或手动处理的生产关键数据
  2. Delete(删除)

    • PVC 删除后,PV 和底层存储资源一并自动删除
    • 行为由具体的 StorageClass 和 provisioner 决定(如 AWS EBS 会删除对应卷)
    • 适用场景:开发/测试环境、临时存储、允许数据丢失的非关键场景
  3. Recycle(回收,已废弃)

    • PVC 删除后,K8s 执行 rm -rf /thevolume/*,然后 PV 恢复可用
    • 已被动态 provisioning 方案取代,新版 K8s 不推荐使用

生产环境通常使用 Retain + 人工确认 的策略处理核心数据,使用 Delete 策略处理可重建的缓存/临时数据。PVC 被 Pod 使用时是受保护的(处于 Terminating 状态),直到 Pod 不再使用才会回收。


题目 18:什么是 Headless Service?适用场景是什么?#

问题: 解释 Headless Service 与普通 Service 的区别及使用场景。

参考答案:

Headless Service 是将 spec.clusterIP 设为 None 的特殊 Service 类型。与普通 Service 的关键区别在于它不分配 ClusterIP,不提供负载均衡,DNS 查询直接返回后端 Pod 的 IP 列表而非单个虚拟 IP。

DNS 解析差异:

  • 普通 Service:myapp.ns.svc.cluster.local10.96.1.5(ClusterIP)
  • Headless Service:myapp.ns.svc.cluster.local[10.0.1.5, 10.0.2.6, 10.0.3.7](Pod IP 列表)

(集群 DNS 的完整解析链路——/etc/resolv.confndots:5、search domain 拼接、SRV 记录——见原理篇 题7;本题聚焦 Headless 的概念与使用场景。)

核心使用场景:

  1. StatefulSet 固定网络身份:配合 serviceName 字段,每个 Pod 获得独立的 DNS 记录:<pod-name>.<service>.<ns>.svc.cluster.local。如 MySQL 集群中 mysql-0.mysql.svc.cluster.local 始终指向同一 Pod,即使被重新调度。
  2. 客户端侧负载均衡:服务发现框架(如 gRPC name resolver)直接获取所有 Pod IP,由客户端自己做负载均衡策略。
  3. 去中心化集群发现:如 Kafka、Elasticsearch、Cassandra 集群,节点间需要对等通信而非经 Service 代理。

题目 19:ResourceQuota 和 LimitRange 的作用是什么?#

问题: 解释 ResourceQuota 和 LimitRange 的职责区别。

参考答案:

两者都是 Namespace 级别的资源管控手段,但职责不同:

ResourceQuota:限制 Namespace 的总量,包括计算资源(CPU/内存 requests/limits 总和)、存储资源(PV 总容量和数量)、对象数量(Pod/Service/ConfigMap/Secret 等)的上限。防止某个团队独占集群资源。

LimitRange:约束 Namespace 内单个 Pod/容器的资源范围,包括默认的 requests/limits(未设置时自动注入)、最小值/最大值、requests 和 limits 的比例上限等。防止个别 Pod 设置过大 requests 导致浪费。

配合使用示例: 一个开发 Namespace 设置 ResourceQuota requests.cpu: 20, requests.memory: 40Gi, pods: 100,同时通过 LimitRange 设置默认 requests 为 100m CPU / 128Mi memory,确保每个 Pod 都有合理的资源请求。

需要注意的是,ResourceQuota 既能限制 requests 总和(requests.cpu/requests.memory)也能限制 limits 总和(limits.cpu/limits.memory)。关键陷阱:一旦某 Namespace 配了针对 requests/limits 维度的 quota,该 Namespace 内每个容器就必须显式声明对应的 requests/limits,否则 Pod 会被 quota 准入直接拒绝——这正是通常要搭配 LimitRange 自动注入默认值的原因。


题目 20:EndpointSlice 是什么?为什么用它取代 Endpoints?#

问题: EndpointSlice 解决了 Endpoints 的什么问题?它和 Service、kube-proxy 是什么关系?

参考答案:

EndpointSlice 是记录"某个 Service 后端有哪些就绪 Pod 的 IP/端口"的对象,自 1.21 起默认取代了老的 Endpoints 对象

为什么要取代 Endpoints: 一个 Service 的所有后端端点原本塞在单个 Endpoints 对象里。当后端有几千个 Pod、且频繁滚动时,任何一个 Pod 的增删都要重写并全量推送这个巨大对象给所有 watch 它的 kube-proxy,带来严重的 API Server 传输和 CPU 开销(历史上是大规模集群的著名瓶颈)。

EndpointSlice 的改进:

  1. 分片:把端点切成多个 slice,默认每片最多 100 个端点,变更只影响所在的那一片,实现增量更新
  2. 可扩展信息:每个端点携带 topology(拓扑/zone,支持拓扑感知路由)、nodeName、多端口、多地址族(IPv4/IPv6 双栈)等 Endpoints 表达不了的信息
  3. kube-proxy 和 Ingress Controller 现在直接 watch EndpointSlice 来生成转发规则

与其它对象的关系: Service 定义"选谁"(selector)→ EndpointSlice 控制器筛出通过 Readiness 探针的 Pod IP 写入 slice → kube-proxy watch slice 生成 iptables/IPVS/nftables 规则。所以 Pod not ready 时会被移出 slice、自动摘流量,就是这一环在起作用。


题目 21:PodDisruptionBudget(PDB)解决什么问题?#

问题: PDB 是什么?它对哪类"中断"生效、对哪类无效?不配 PDB 会怎样?

参考答案:

PodDisruptionBudget 用于在**主动中断(voluntary disruption)**期间保证一个应用至少有 N 个(或至多缺 N 个)Pod 可用,避免因运维操作把副本一次性打空导致服务不可用。通过 minAvailable(如 280%)或 maxUnavailable 指定,配合 selector 选中目标 Pod。

核心区分:PDB 只约束"主动中断",不管"被动中断"。

  • 生效(主动中断)kubectl drain 排空节点、集群升级、Cluster Autoscaler 缩容节点等——这些操作会调用 Eviction API,而 Eviction API 会检查 PDB,若驱逐会突破预算就阻塞/等待
  • 不生效(被动中断):节点硬件宕机、内核 OOMKill、Pod 崩溃——这些是"意外",PDB 完全管不了(它不是高可用保证,而是"运维操作护栏")。

不配 PDB 的后果: 一次 drain 或滚动升级可能瞬间干掉某服务的全部副本造成短暂全挂。典型坑:PDB 设 minAvailable 过严(如单副本 Deployment 设 minAvailable: 1)会让 drain 永远卡住,因为无论如何驱逐都会破坏预算——所以 PDB 要和足够的副本数、反亲和一起用才有意义。


题目 22:什么是 Operator / CRD?它体现了 K8s 的什么设计思想?#

问题: 解释 CRD 和 Operator 的概念,以及 Operator 相比裸 Deployment 部署有状态应用的价值。

参考答案:

  • CRD(CustomResourceDefinition):向 K8s API Server 注册一种自定义资源类型(如 PostgresClusterKafka),之后就能像操作内置资源一样 kubectl apply 这种对象。CRD 只是"声明了一种新对象",本身不带任何行为。
  • Operator:CRD + 自定义控制器的组合。控制器 watch 该 CRD,运行调谐循环,把运维专家的领域知识(如何扩容、备份、故障切换、版本升级)代码化,持续把实际状态收敛到 CR 里声明的期望状态。

为什么有价值(对比裸 Deployment): 有状态中间件(数据库、Kafka、etcd)光靠 StatefulSet 远远不够——主从切换、备份恢复、扩缩容时的数据再平衡、滚动升级的顺序编排,都是"活的运维逻辑"。Operator 把这些封装进控制器,用户只需声明 replicas: 5 / version: 16 / backup: daily,剩下的由 Operator 自动完成。这正是 K8s 声明式 API + 控制器模式思想的自然延伸——把"人肉 SRE 流程"变成"可复用、可审计、7×24 自动执行的控制器"。

关键点: Operator 的能力边界完全取决于其控制器代码的成熟度;生产选型要看 Operator 是否经过大规模验证(如 CloudNativePG、Strimzi、Zalando postgres-operator)。CRD 也可脱离 Operator 单独使用(如仅作配置载体,由 ArgoCD/其他控制器消费)。