Skip to content

Kubernetes 核心概念

提出问题

Kubernetes 已经成为容器编排的事实标准,几乎每个微服务面试都会触及。面试官不只是想听你背出 Pod、Deployment、Service 的定义,而是考察你是否理解它们之间的协作关系:控制器模式如何保证声明式状态收敛、Service 如何将流量路由到 Pod、HPA 如何根据指标自动扩缩容。这些概念在面试中频频出现,更在实际生产排障中每天都要打交道。

分析问题

Pod、Deployment 与控制器模式

Pod 是 Kubernetes 的最小调度单元,一个 Pod 可包含一个或多个容器(共享网络栈和存储卷)。但你不会直接创建 Pod——Deployment 是管理 Pod 的声明式控制器,它通过 ReplicaSet 确保指定数量的 Pod 副本始终运行。

控制器模式是 Kubernetes 最核心的设计哲学,理解它比背 YAML 字段重要十倍。一个 Pod 从提交到运行的全流程时序如下:

用户       kubectl           kube-apiserver       etcd          Deployment    ReplicaSet    Scheduler     kubelet       CRI/容器运行时
 |            |                    |                |             Controller   Controller      |            |            |
 |--kubectl apply -f deploy.yaml->|                 |              |             |             |            |            |
 |            |                    |--校验/鉴权------>|              |             |             |            |            |
 |            |                    |<--写入成功-------|              |             |             |            |            |
 |            |<--返回创建成功-----|                 |              |             |             |            |            |
 |            |                    |                 |              |             |             |            |            |
 |            |                    |                 |<--Informer 监听 Deployment 变化--------->|            |            |
 |            |                    |                 |    发现期望副本数=3,当前 ReplicaSet=0      |            |            |
 |            |                    |                 |----创建 ReplicaSet 对象---------------->|            |            |
 |            |                    |                 |              |             |             |            |            |
 |            |                    |                 |              |<--Informer 监听 ReplicaSet 变化--|            |            |
 |            |                    |                 |              |    发现期望 Pod 数=3,当前 Pod=0   |            |            |
 |            |                    |                 |              |-----创建 3 个 Pod 对象---------->|            |            |
 |            |                    |                 |              |             |             |            |            |
 |            |                    |                 |              |             |<--Informer 监听未调度 Pod--|            |
 |            |                    |                 |              |             |    Predicates: 资源足够/端口不冲突/污点容忍 |
 |            |                    |                 |              |             |    Priorities: 资源余量/亲和性/反亲和性 |
 |            |                    |                 |              |             |----绑定 Pod 到 Node A------------->|            |
 |            |                    |                 |              |             |             |            |            |
 |            |                    |                 |              |             |             |<--Watch 分配到本节点的 Pod-----|            |
 |            |                    |                 |              |             |             |   PodSpec → 准备容器环境        |            |
 |            |                    |                 |              |             |             |---拉取镜像---------------------->|            |
 |            |                    |                 |              |             |             |---创建容器(Sandbox)----------->|            |
 |            |                    |                 |              |             |             |---启动 Init 容器(如有)-------->|            |
 |            |                    |                 |              |             |             |---启动主容器------------------>|            |
 |            |                    |                 |              |             |             |---执行 postStart hook------->|            |
 |            |                    |                 |              |             |             |            |            |
 |            |                    |<--Pod 状态更新---|--------------|-------------|-------------|-----状态上报到 API Server----|            |
 |            |                    |     Running     |              |             |             |            |            |

每层都在做同一件事:从 etcd 读当前状态,跟自己的期望对比,有差异就调谐。面试时能画出这个链路,比干巴巴说"控制器模式就是调谐循环"强很多。

Scheduler 的 predicates 和 priorities:调度不是随机选节点。Predicates 做硬过滤(节点资源够不够、端口是否冲突、节点是否被污点标记、Pod 是否容忍污点、Pod 的亲和性/反亲和性约束),过滤完后如果还有多个候选节点,Priorities 做打分(LeastRequestedPriority 按资源余量打分、NodeAffinity 按亲和性权重、TaintToleration 按容忍度)。分数最高的节点中标。如果 Predicates 过滤后一个节点都剩不下,Pod 一直 Pending,kubectl describe pod 的 Events 里会写明原因。

生产里踩过的坑:

  • revisionHistoryLimit 不设导致 etcd 暴涨:默认保留 10 个 ReplicaSet 历史版本,如果你滚动更新 100 次,就有 100 个历史 ReplicaSet 对象躺在 etcd 里。etcd 默认 2GB 存储上限(--quota-backend-bytes),你只跑 3 个 Deployment 不觉得,跑 200 个微服务、每个每两周更新一次,半年后 etcd 容量告警。建议显式设 revisionHistoryLimit: 2
  • maxSurge/maxUnavailable 组合错了导致滚动更新卡死maxSurge: 0 + maxUnavailable: 0 是不合法的,因为滚动更新既不能超量也不能缺量,死锁。生产至少配 maxSurge: 1, maxUnavailable: 0maxSurge: 0, maxUnavailable: 1
  • Pod 资源 request/limit 配了 0 或不配:不配 request 的 Pod 会被调度到任何节点,但节点资源可能被其他 Pod 挤占。我们踩过 Java 应用的 Pod 不配 memory request,结果两个 Pod 被调度到同一台 4GB 的节点上,各自 JVM 堆 2GB,加上操作系统和 sidecar 直接 OOM。必须配 request 让 scheduler 做资源预留。
  • livenessProbe 和 readinessProbe 配置不当:initialDelaySeconds 设得太短,容器还没启动就被 kill 重启循环。Spring Boot 应用启动要 30 秒,liveness 的 initialDelaySeconds 设了 5 秒,结果 Pod 永远起不来。
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  revisionHistoryLimit: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi
        livenessProbe:
          httpGet:
            path: /healthz
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 5

Pod 网络模型与 CNI

Kubernetes 的网络模型要求:每个 Pod 都有自己的 IP,Pod 之间可以直接通信(不需要 NAT),Pod 与 Node 之间也可以直接通信。这个模型由 CNI(Container Network Interface)插件实现。

Pod 内通信:一个 Pod 里的多个容器共享同一个 network namespace(通过 pause 容器先创建 Sandbox),所以它们通过 localhost 互相访问,端口不能冲突。

跨节点 Pod 通信:CNI 插件负责跨节点网络连通。主流方案对比:

方案数据面封装方式吞吐损耗典型场景
Flannel (VXLAN)内核UDP 封装~5-10%小规模、快速上手
Calico (BGP)内核无封装,纯路由<1%大规模、性能敏感
Cilium (eBPF)内核 eBPF无封装或 Geneve<1%大规模 + 安全策略 + 可观测性
Weave用户态/内核UDP 封装~5-10%已边缘化,不推荐新项目

Cilium 为什么是趋势:Cilium 用 eBPF 直接在内核态处理网络包,绕过了 iptables 的 O(n) 开销。在 1000 个 Service 的集群里,iptables 规则可能有 1 万条,每条连接都要逐条匹配,CPU 飙升。Cilium 用 eBPF Map 做哈希查找,O(1) 复杂度,延迟和吞吐都稳定。我们实践迁移后,Service 间 P99 延迟从 8ms 降到了 2ms。

Service 与 Ingress 流量入口

Pod 的 IP 是不稳定的——每次重启或被调度到其他节点都会变化。Service 提供了一个稳定的虚拟 IP(ClusterIP)和 DNS 名称,通过标签选择器(Label Selector)匹配后端 Pod,实现负载均衡。

Service 的完整网络路径

客户端请求 → Service ClusterIP:Port

Node 内核收到包,目标 IP = ClusterIP

kube-proxy 写入的 iptables/IPVS 规则匹配到 ClusterIP

DNAT 将目标 IP 改为选中的 Pod IP(iptables 的 DNAT 或 IPVS 的 NAT 模式)

包转发到具体的 Pod 所在 Node(跨节点时走 Node 路由)

Pod 内的容器收到请求,回复包走反向 SNAT 回到客户端(iptables conntrack 记录原始连接)

kube-proxy 模式对比

模式实现方式路由复杂度连接量 1000 下 CPU 开销连接量 10000 下 CPU 开销
userspace用户态代理慢,已废弃极高
iptables内核 netfilterO(n) 链式匹配5%40%+
IPVS内核 LVSO(1) 哈希2%5%
eBPF (Cilium)内核 eBPFO(1) Map1%2%

大集群(>500 Service)建议用 IPVS 或 Cilium eBPF 模式。iptables 模式在规则数超过 1000 条时,每次连接匹配的 CPU 开销会直线上升。

Service 的类型决定了暴露范围:

类型访问方式典型场景
ClusterIP集群内 DNS 解析微服务间通信默认模式,外部无法直接访问
NodePortNodeIP:NodePort测试环境、本地调试端口范围 30000-32767,不能冲突
LoadBalancer云厂商 LB生产环境对外暴露每个 Service 一个 LB,成本高

Service 的 Session Affinity:如果你需要同一个客户端的请求始终打到同一个 Pod(比如 WebSocket 或本地缓存),设置 sessionAffinity: ClientIP,默认基于 iptables 的随机转发会导致请求漂移。生产上我们遇到过 WebSocket 连接频繁断开,排查发现是 kube-proxy 的随机转发把同一个客户端的不同请求发到了不同 Pod,而 Pod 上的 WebSocket 状态是本地内存存储的。

集群外部流量更常用 Ingress——一个七层路由规则,将 HTTP/HTTPS 请求按域名和路径转发到不同的 Service。Ingress 需要安装 Ingress Controller(如 Nginx Ingress、Traefik)才能真正生效。

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
      - path: /v2
        pathType: Prefix
        backend:
          service:
            name: api-v2-service
            port:
              number: 8080

Ingress 的坑pathType: Prefix 匹配 /v1 会匹配到 /v1/user,但也可能匹配到 /v1abc,因为 Prefix 是按字符串前缀匹配,不是按路径段。如果你需要精确段匹配,用 pathType: Exact。Nginx Ingress Controller 默认用 / 后缀做路径段匹配,但标准 Kubernetes API 的 Prefix 行为就是按字符串前缀,这个差异踩过的人不少。

健康检查与自动扩缩容

Kubernetes 提供三种探针(Probe),面试时能说出区别和适用场景才算真懂:

探针失败后果典型使用场景翻车案例
livenessProbe重启容器检测死锁、内存泄漏配置不当导致 Pod 反复重启
readinessProbe从 Service 端点移除应用启动慢、依赖未就绪数据库未就绪时接收流量,返回 500
startupProbe禁用 liveness/readiness启动慢的 Java 应用没有它,Spring Boot 启动 60s 期间被 liveness 杀死

启动慢的 Java 应用为什么需要 startupProbe:Spring Boot 应用启动要 30-60 秒,如果 livenessProbe 的 initialDelaySeconds 设 10 秒,容器启动 10 秒后开始检查,还没准备好就连续失败,kubelet 认为 Pod 不健康就重启,陷入死循环。startupProbe 在启动期间覆盖 liveness/readiness,等启动完成后再切换回正常探针。

yaml
# 适合 Spring Boot 的配置
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 30   # 等 Spring Boot 启动完
  periodSeconds: 15
  timeoutSeconds: 3
  failureThreshold: 3

HPA(Horizontal Pod Autoscaler)根据 CPU/内存使用率或自定义指标自动调整 Pod 副本数。HPA 通过 Metrics Server 获取指标,不断计算所需副本数:

desiredReplicas = ceil(currentReplicas × currentMetricValue / targetMetricValue)

例如当前 2 个 Pod,CPU 平均使用率 90%,目标是 70%,则:

desiredReplicas = ceil(2 × 90 / 70) = ceil(2.57) = 3
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 缩容冷却窗口,防止流量抖动缩了又涨
    scaleUp:
      stabilizationWindowSeconds: 0    # 扩容不冷却,快速响应
      policies:
      - type: Pods
        value: 4
        periodSeconds: 15              # 15 秒内最多扩容 4 个 Pod

HPA 与 VPA 对比

维度HPAVPA
调整对象Pod 副本数Pod 的 request/limit
适用场景无状态应用、流量波动大有状态应用、资源利用率优化
缩容时间5-15 分钟(冷却窗口)需要重建 Pod
限制与 VPA 不能同时作用于 CPU/内存不能独立工作,需要配合 Cluster Autoscaler
典型配合HPA + CA 全自动扩缩VPA + CA 控制资源浪费

HPA 生产踩坑

  • Metrics Server 未安装:HPA 不工作,查不到指标。很多新手搭集群只装 kubeadm 没装 Metrics Server,HPA 永远不扩缩。kubectl top nodes 能跑才能确认 Metrics Server 正常。
  • 只配 CPU 不配内存:内存密集型应用(如 Java 堆内存 4GB),CPU 负载不高但内存快爆了,HPA 不会触发扩容。建议 CPU + 内存双指标,或对接 Prometheus 自定义指标。
  • 扩缩容震荡:minReplicas=2, maxReplicas=100, CPU 目标 70%,流量波动 10 秒一个周期,HPA 每 15 秒评估一次,Pod 频繁创建销毁。解决方案:配 behavior.scaleDown.stabilizationWindowSeconds: 300 缩容冷却窗口,防止流量抖动导致频繁缩容再扩容。我们一个电商业务在双十一前踩过:凌晨流量低谷缩到 2 个 Pod,早上 8 点流量突然涨了 5 倍,HPA 从 2 扩到 10 个 Pod 花了 5 分钟,期间大量请求超时。后来我们把 minReplicas 提到 5,配合 PDB 和 CA 预热,扩缩更平滑。

ConfigMap 与 Secret:配置管理

ConfigMap 存储非敏感配置(如环境变量、配置文件),Secret 存储敏感数据(如密码、Token)。两者都以 Volume 挂载或环境变量的方式注入到 Pod 中。

Secret 的误解:Secret 值只做 Base64 编码,不是加密。任何有 etcd 访问权限的人都可以直接解码看明文。生产环境必须配合:

  • sealed-secrets:在 GitOps 流程中加密存储 Secret 的 YAML
  • sops + age:在 Git 仓库里加密 secret 文件
  • 云厂商 KMS(AWS KMS / GCP KMS):Kubernetes 1.24+ 支持 KMS v2 加密 etcd 中的 Secret

ConfigMap 的挂载行为:如果 ConfigMap 是 Volume 挂载,更新 ConfigMap 后 Pod 内的文件也会更新(几秒延迟),但不会触发 Pod 重启。很多用户以为改了 ConfigMap 应用会自动重载配置,实际上应用的 hot reload 机制需要自己实现。Spring Boot 可以用 spring-cloud-kubernetes 的 ConfigMap 刷新,或者用 Reloader 组件监听 ConfigMap 变更自动重启 Pod。

生产排障速查表

现象排查思路命令
Pod 一直 Pending资源不足、PVC 未就绪、节点污点kubectl describe pod <pod>
Pod 反复 CrashLoopBackOff启动失败、探针失败kubectl logs <pod> --previous
Service 不通标签选择器不匹配、端口不对kubectl describe svc <svc> | grep Endpoints
Ingress 返回 404路径不匹配、Ingress Controller 未部署kubectl describe ingress <ingress>
HPA 不扩缩Metrics Server 未安装、指标未上报kubectl get hpa -o yaml 看 conditions
节点 NotReadykubelet 挂了、磁盘满、网络不通kubectl get nodes 看状态
DNS 解析失败CoreDNS 未部署、Pod DNS 策略不对kubectl -n kube-system logs -l k8s-app=kube-dns

总结

面试官面 k8s,最想听到的不是你背 Pod 的定义,而是你能说出控制器模式的全链路(用户 → API Server → etcd → Controller → Scheduler → kubelet → CRI),以及实践中踩过的坑(revisionHistoryLimit 撑爆 etcd、liveness 配置不当导致重启循环、HPA 只配 CPU 导致内存爆满、Service 的 IPVS vs iptables 性能差异)。Kubernetes 核心概念围绕声明式 API + 控制器模式展开:Pod 是最小单元,Deployment 保证副本数,Service 提供稳定网络入口,Ingress 处理七层路由,HPA 实现自动伸缩,CNI 插件解决跨节点网络。

参考

参考:Kubernetes 官方文档 - Concepts;《Kubernetes in Action》第二版;Kubernetes Design Proposals - Controller Pattern

手撕 → 框架 → 生产化,一步步把 AI Agent 工程化搞透。