HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 技术面试完全指南

    • 技术面试完全指南
    • 8年面试官告诉你:90%的简历在第一轮就被刷掉了
    • 刷了500道LeetCode,终于明白大厂算法面试到底考什么
    • 高频算法题精讲-双指针与滑动窗口
    • 03-高频算法题精讲-二分查找与排序
    • 04-高频算法题精讲-树与递归
    • 05-高频算法题精讲-图与拓扑排序
    • 06-高频算法题精讲-动态规划
    • Go面试必问:一道GMP问题,干掉90%的候选人
    • 08-数据库面试高频题
    • 09-分布式系统面试题
    • 10-Kubernetes与云原生面试题
    • 11-系统设计面试方法论
    • 前端面试高频题
    • AI 与机器学习面试题
    • 行为面试与软技能

10-Kubernetes与云原生面试题

本章导读

Kubernetes已成为云原生时代的事实标准,是后端工程师必备技能。本章涵盖Pod生命周期、网络模型、调度策略、服务发现等核心概念,包含35+道K8s高频面试题,结合实际运维经验深入剖析容器编排原理。

主要内容:

  • Kubernetes架构与核心组件
  • Pod生命周期与探针机制
  • Service与网络模型
  • 存储与配置管理
  • 调度与资源管理

第一部分:Kubernetes架构基础

1. Kubernetes的架构是怎样的?核心组件有哪些?

考察点: K8s整体架构理解

详细解答:

Kubernetes架构概览:

┌─────────────────────────────────────────────────────┐
│                   Control Plane                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────┐  │
│  │   API    │  │ Scheduler│  │ Controller       │  │
│  │  Server  │  │          │  │ Manager          │  │
│  └──────────┘  └──────────┘  └──────────────────┘  │
│  ┌──────────────────────────────────────────────┐  │
│  │              etcd (分布式存储)                │  │
│  └──────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘
                         │
        ┌────────────────┼────────────────┐
        │                │                │
┌────────────┐  ┌────────────┐  ┌────────────┐
│   Node 1    │  │   Node 2    │  │   Node 3    │
│ ┌─────────┐ │  │ ┌─────────┐ │  │ ┌─────────┐ │
│ │ kubelet │ │  │ │ kubelet │ │  │ │ kubelet │ │
│ ├─────────┤ │  │ ├─────────┤ │  │ ├─────────┤ │
│ │kube-proxy│ │  │ │kube-proxy│ │  │ │kube-proxy│ │
│ ├─────────┤ │  │ ├─────────┤ │  │ ├─────────┤ │
│ │Container│ │  │ │Container│ │  │ │Container│ │
│ │ Runtime │ │  │ │ Runtime │ │  │ │ Runtime │ │
│ └─────────┘ │  │ └─────────┘ │  │ └─────────┘ │
│   Pod Pod   │  │   Pod Pod   │  │   Pod Pod   │
└─────────────┘  └─────────────┘  └─────────────┘

Control Plane组件(主节点):

1. API Server(kube-apiserver)

作用:
- K8s的前端,所有组件通过API Server通信
- RESTful API接口
- 认证、授权、准入控制

特点:
- 无状态(可水平扩展)
- 唯一直接访问etcd的组件

工作流程示例:
用户执行:kubectl create deployment nginx --image=nginx

1. kubectl -> API Server: POST /apis/apps/v1/deployments
2. API Server认证、授权、准入控制
3. API Server -> etcd: 写入Deployment对象
4. API Server通知Controller Manager
5. Controller Manager创建ReplicaSet
6. ReplicaSet Controller创建Pod
7. Scheduler监听到未调度的Pod
8. Scheduler分配Node
9. kubelet监听到Pod分配到本节点
10. kubelet启动容器

2. etcd

作用:
- 分布式键值存储
- 保存K8s所有数据(集群状态、配置)

特点:
- 基于Raft算法保证一致性
- Watch机制(监听变化)

存储的数据类型:
- Pod、Service、Deployment等资源对象
- 配置信息(ConfigMap、Secret)
- 集群状态

示例数据:
/registry/pods/default/nginx-xxx
/registry/services/default/nginx-service
/registry/deployments/default/nginx-deployment

3. Scheduler(kube-scheduler)

作用:
- 为新创建的Pod选择合适的Node

调度流程:
1. 过滤(Predicates):排除不符合条件的Node
   - 资源是否足够(CPU、内存)
   - Node是否有污点(Taint)
   - Pod是否有容忍度(Toleration)
   - 端口是否冲突

2. 打分(Priorities):给剩余Node打分
   - 资源利用率
   - 亲和性/反亲和性
   - 负载均衡

3. 选择:选择分数最高的Node

示例:
Pod请求:CPU=1, Memory=2Gi

Node1: CPU=2/4, Memory=3/8 (剩余CPU=2, Memory=5) → 分数80
Node2: CPU=3/4, Memory=4/8 (剩余CPU=1, Memory=4) → 分数50
Node3: CPU=1/4, Memory=2/8 (剩余CPU=3, Memory=6) → 分数100

选择Node3

4. Controller Manager(kube-controller-manager)

作用:
- 运行各种控制器,维护集群的期望状态

常见控制器:
1. Deployment Controller:管理Deployment
2. ReplicaSet Controller:维护Pod副本数
3. Node Controller:监控Node状态
4. Service Controller:创建LoadBalancer
5. Endpoints Controller:维护Service的Endpoints
6. Namespace Controller:管理命名空间

工作原理(控制循环):
loop {
    实际状态 = 从API Server获取当前状态
    期望状态 = 从API Server获取spec
    if (实际状态 != 期望状态) {
        执行操作使实际状态 -> 期望状态
    }
    sleep(一段时间)
}

示例:ReplicaSet Controller
期望副本数:3
实际副本数:2
操作:创建1个Pod

5. Cloud Controller Manager

作用:
- 与云平台交互(AWS、Azure、GCP)

控制器:
1. Node Controller:检测云平台删除的Node
2. Route Controller:配置云平台的路由
3. Service Controller:创建云平台的LoadBalancer
4. Volume Controller:创建云平台的存储卷

Node组件(工作节点):

1. kubelet

作用:
- 每个Node上的代理
- 负责Pod的生命周期管理

主要功能:
1. Pod管理:创建、启动、停止、删除Pod
2. 健康检查:执行Liveness/Readiness Probe
3. 资源监控:采集Node和Pod的资源使用情况
4. 容器运行时管理:通过CRI与容器运行时通信

工作流程:
1. 监听API Server分配到本节点的Pod
2. 调用容器运行时启动容器
3. 定期报告Pod状态到API Server
4. 执行健康检查探针
5. 清理已终止的容器

示例:
API Server -> kubelet: 创建Pod nginx
kubelet -> Container Runtime: 拉取镜像nginx
Container Runtime -> Docker: docker pull nginx
Docker -> Container Runtime: 镜像拉取完成
Container Runtime -> kubelet: 镜像就绪
kubelet -> Container Runtime: 启动容器
Container Runtime -> Docker: docker run nginx
kubelet -> API Server: Pod状态Running

2. kube-proxy

作用:
- 实现Service的网络代理
- 维护网络规则(iptables/ipvs)

工作模式:
1. iptables模式(默认):
   - 使用iptables规则转发流量
   - 每个Service对应一组iptables规则

2. ipvs模式:
   - 使用IPVS实现负载均衡
   - 性能更好,支持更多负载均衡算法

3. userspace模式(已废弃):
   - kube-proxy作为用户态代理

示例(iptables模式):
Service: nginx-service (ClusterIP: 10.96.0.1, Port: 80)
Backend Pods: 10.244.1.2:80, 10.244.2.3:80

生成的iptables规则:
# 拦截目标地址为10.96.0.1:80的流量
-A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m tcp --dport 80 -j KUBE-SVC-NGINX

# 负载均衡到Pod(50%概率)
-A KUBE-SVC-NGINX -m statistic --mode random --probability 0.5 -j KUBE-SEP-POD1
-A KUBE-SVC-NGINX -j KUBE-SEP-POD2

# 转发到Pod1
-A KUBE-SEP-POD1 -p tcp -m tcp -j DNAT --to-destination 10.244.1.2:80

# 转发到Pod2
-A KUBE-SEP-POD2 -p tcp -m tcp -j DNAT --to-destination 10.244.2.3:80

3. Container Runtime

作用:
- 负责运行容器

常见运行时:
1. Docker(通过dockershim,K8s 1.24+已移除)
2. containerd(推荐)
3. CRI-O

CRI(Container Runtime Interface):
- K8s与容器运行时的标准接口
- 包括ImageService和RuntimeService

示例(containerd):
kubelet -> CRI -> containerd -> runc
                                 └─> 启动容器

附加组件(Add-ons):

1. DNS(CoreDNS):
   - 集群内部的DNS服务
   - 服务发现(Service -> ClusterIP)

2. Dashboard:
   - Web UI管理界面

3. Ingress Controller:
   - HTTP/HTTPS路由
   - 七层负载均衡

4. Metrics Server:
   - 资源监控(CPU、内存)
   - kubectl top命令

5. Network Plugin(CNI):
   - Flannel、Calico、Weave等
   - 实现Pod网络

组件通信流程示例:

场景:创建一个Deployment

1. 用户 -> API Server:
   kubectl create deployment nginx --image=nginx

2. API Server -> etcd:
   写入Deployment对象

3. Deployment Controller监听到新Deployment:
   创建ReplicaSet对象

4. ReplicaSet Controller监听到新ReplicaSet:
   创建3个Pod对象(假设replicas=3)

5. Scheduler监听到未调度的Pod:
   为每个Pod选择Node
   更新Pod的nodeName字段

6. kubelet监听到分配到本节点的Pod:
   调用容器运行时启动容器

7. kubelet定期报告Pod状态:
   kubelet -> API Server: Pod状态Running

8. 用户查询状态:
   kubectl get pods
   kubectl -> API Server -> etcd -> 返回Pod列表

2. Kubernetes的网络模型是怎样的?

考察点: K8s网络架构理解

详细解答:

Kubernetes网络三大要求:

1. 所有Pod可以不通过NAT与其他所有Pod通信
2. 所有Node可以不通过NAT与所有Pod通信
3. Pod看到的自己的IP和其他Pod看到它的IP是同一个

网络层次:

1. 容器间通信(同一个Pod内)
   - 共享Network Namespace
   - 通过localhost通信

2. Pod间通信(同一个Node)
   - 通过虚拟网桥(cbr0、cni0)

3. Pod间通信(跨Node)
   - 通过CNI插件(Flannel、Calico等)

4. Pod与Service通信
   - 通过kube-proxy(iptables/ipvs)

5. 集群外部访问Service
   - NodePort、LoadBalancer、Ingress

详细解析:

1. 容器间通信(同一个Pod)

Pod内部网络结构:

┌─────────────────────────────────────┐
│              Pod: nginx-app         │
│  ┌──────────────────────────────┐  │
│  │   Pause Container            │  │
│  │   (Network Namespace)        │  │
│  │   eth0: 10.244.1.2           │  │
│  └──────────────────────────────┘  │
│                                   │
│            │          │             │
│  ┌─────────┴───┐   ┌─┴───────────┐ │
│  │  nginx      │   │  sidecar    │ │
│  │  localhost  │   │  localhost  │ │
│  └─────────────┘   └─────────────┘ │
└─────────────────────────────────────┘

通信方式:
- nginx容器访问sidecar: localhost:8080
- sidecar访问nginx: localhost:80
- 共享同一个IP地址:10.244.1.2

2. Pod间通信(同一个Node)

Node网络结构:

┌─────────────────────────────────────────┐
│              Node: node1                │
│                                         │
│  ┌────────┐  ┌────────┐  ┌────────┐   │
│  │ Pod A  │  │ Pod B  │  │ Pod C  │   │
│  │10.244  │  │10.244  │  │10.244  │   │
│  │.1.2    │  │.1.3    │  │.1.4    │   │
│  └────┬───┘  └───┬────┘  └───┬────┘   │
│       │          │            │        │
│       └──────────┼────────────┘        │
│                  │                     │
│          ┌──────────────┐            │
│          │  cni0 (bridge) │            │
│          │  10.244.1.1    │            │
│          └───────┬────────┘            │
│                  │                     │
│          ┌───────────────┐           │
│          │  eth0          │           │
│          │  192.168.1.10  │           │
│          └────────────────┘           │
└─────────────────────────────────────────┘

通信流程:
Pod A (10.244.1.2) -> Pod B (10.244.1.3)

1. Pod A发送数据包:
   Source: 10.244.1.2
   Dest: 10.244.1.3

2. 数据包通过veth pair到达cni0网桥

3. cni0网桥查找ARP表,发现Pod B的MAC地址

4. cni0网桥转发数据包到Pod B的veth

3. Pod间通信(跨Node)

方案1:Flannel(Overlay网络)

网络拓扑:

┌──────────────────┐        ┌──────────────────┐
│    Node 1        │        │    Node 2        │
│  ┌────────┐      │        │      ┌────────┐  │
│  │ Pod A  │      │        │      │ Pod B  │  │
│  │10.244  │      │        │      │10.244  │  │
│  │.1.2    │      │        │      │.2.3    │  │
│  └───┬────┘      │        │      └───┬────┘  │
│      │           │        │          │       │
│  ┌───────┐      │        │      ┌───────┐  │
│  │ cni0   │      │        │      │ cni0   │  │
│  └───┬────┘      │        │      └───┬────┘  │
│      │           │        │          │       │
│  ┌───────────┐  │        │  ┌───────────┐  │
│  │ flannel.1  │  │        │  │ flannel.1  │  │
│  │ (VXLAN)    │  │        │  │ (VXLAN)    │  │
│  └───┬────────┘  │        │  └───────┬────┘  │
│      │           │        │          │       │
│  ┌───────┐      │        │      ┌───────┐  │
│  │  eth0  │      │        │      │  eth0  │  │
│  │192.168 │◄─────┼────────┼─────►│192.168 │  │
│  │.1.10   │      │        │      │.1.11   │  │
│  └────────┘      │        │      └────────┘  │
└──────────────────┘        └──────────────────┘

通信流程:
Pod A (10.244.1.2) -> Pod B (10.244.2.3)

1. Pod A发送数据包:
   Source: 10.244.1.2
   Dest: 10.244.2.3

2. 路由规则匹配(查询etcd中的路由表):
   10.244.2.0/24 -> Node2 (192.168.1.11)

3. Flannel VXLAN封装:
   外层IP包:
     Source: 192.168.1.10 (Node1)
     Dest: 192.168.1.11 (Node2)
   内层IP包:
     Source: 10.244.1.2 (Pod A)
     Dest: 10.244.2.3 (Pod B)

4. 通过物理网络传输到Node2

5. Node2的Flannel解封装,提取内层IP包

6. 路由到cni0网桥,转发到Pod B

方案2:Calico(BGP路由)

原理:
- 不使用Overlay,直接使用三层路由
- 通过BGP协议同步路由信息
- 性能更好(无封装开销)

路由表示例(Node1):
10.244.1.0/24 via 192.168.1.10 dev eth0  # 本节点Pod
10.244.2.0/24 via 192.168.1.11 dev eth0  # Node2的Pod
10.244.3.0/24 via 192.168.1.12 dev eth0  # Node3的Pod

通信流程:
Pod A (10.244.1.2) -> Pod B (10.244.2.3)

1. Pod A发送数据包到cni0

2. Node1查询路由表:10.244.2.0/24 via 192.168.1.11

3. 直接转发到Node2(无封装)

4. Node2查询路由表,转发到Pod B

优势:
- 性能高(无隧道开销)
- 网络策略(NetworkPolicy)支持好

劣势:
- 需要物理网络支持BGP
- 配置相对复杂

4. Service网络

ClusterIP:

Service YAML:
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 8080

创建后:
- ClusterIP: 10.96.0.1(虚拟IP,仅集群内可访问)
- Endpoints: 10.244.1.2:8080, 10.244.2.3:8080(Pod IP)

kube-proxy生成iptables规则:
-A KUBE-SERVICES -d 10.96.0.1/32 -p tcp --dport 80 -j KUBE-SVC-NGINX

# 负载均衡到Pod
-A KUBE-SVC-NGINX -m statistic --mode random --probability 0.5 -j KUBE-SEP-1
-A KUBE-SVC-NGINX -j KUBE-SEP-2

-A KUBE-SEP-1 -j DNAT --to-destination 10.244.1.2:8080
-A KUBE-SEP-2 -j DNAT --to-destination 10.244.2.3:8080

访问流程:
Client Pod -> 10.96.0.1:80 -> iptables DNAT -> 10.244.1.2:8080 (Pod)

NodePort:

Service YAML:
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080

效果:
- ClusterIP: 10.96.0.1
- NodePort: 30080(所有Node的30080端口)

iptables规则:
# 拦截Node IP的30080端口
-A KUBE-NODEPORTS -p tcp --dport 30080 -j KUBE-SVC-NGINX

访问方式:
外部客户端 -> Node1:30080 -> iptables -> Pod
外部客户端 -> Node2:30080 -> iptables -> Pod

LoadBalancer:

Service YAML:
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 8080

效果(云平台):
- ClusterIP: 10.96.0.1
- NodePort: 30080
- External IP: 1.2.3.4(云平台分配的公网IP)

访问流程:
外部客户端 -> LB (1.2.3.4:80) -> Node:30080 -> Pod

5. Ingress(七层负载均衡)

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

架构:

                Internet
                    │
            ┌───────────────┐
            │  Ingress LB    │
            │  (1.2.3.4)     │
            └───────┬────────┘
                    │
        ┌───────────┼───────────┐
        │           │           │
┌────────────┐ ┌─────────┐ ┌───────────┐
│Ingress Ctrl │ │Ingress   │ │Ingress     │
│  (Node1)    │ │Ctrl(Node2)│ │Ctrl(Node3) │
└───────┬─────┘ └──┬───────┘ └─┬──────────┘
        │          │            │
        └──────────┼────────────┘
                   │
        ┌────────────────────┐
        │  nginx-service      │
        │  (ClusterIP)        │
        └──────────┬──────────┘
                   │
        ┌──────────┼──────────┐
        │          │          │
    ┌──────┐  ┌──────┐  ┌──────┐
    │Pod A  │  │Pod B  │  │Pod C  │
    └───────┘  └───────┘  └───────┘

访问流程:
1. DNS解析:www.example.com -> 1.2.3.4
2. 客户端 -> Ingress LB (1.2.3.4)
3. Ingress LB -> Ingress Controller (任一Node)
4. Ingress Controller解析Host、Path,转发到nginx-service
5. nginx-service -> Pod

第二部分:Pod生命周期管理

3. Pod的生命周期是怎样的?

考察点: Pod核心机制理解

详细解答:

Pod生命周期阶段:

┌─────────┐
│ Pending │ ← Pod已创建,等待调度或拉取镜像
└────┬────┘
     │
     
┌─────────┐
│ Running │ ← 至少一个容器正在运行
└────┬────┘
     │
     ├─────────────┐
                  
┌──────────┐  ┌──────────┐
│Succeeded │  │  Failed  │ ← 所有容器失败
└──────────┘  └──────────┘
    
    │
┌───┴────┐
│Unknown │ ← 无法获取Pod状态
└────────┘

详细流程:

1. Pending阶段
   触发条件:
   - Pod刚创建,等待Scheduler调度
   - 调度完成,等待拉取镜像
   - 等待Volume挂载

   示例:
   kubectl create -f pod.yaml

   Pod状态:
   NAME    READY   STATUS    RESTARTS   AGE
   nginx   0/1     Pending   0          5s

   原因(kubectl describe pod nginx):
   - Waiting for scheduler
   - PullImageBackOff (镜像拉取失败)
   - PersistentVolumeClaim not bound

2. Running阶段
   触发条件:
   - 至少一个容器正在运行
   - 或容器正在启动/重启

   示例:
   Pod状态:
   NAME    READY   STATUS    RESTARTS   AGE
   nginx   1/1     Running   0          10s

   容器状态(kubectl describe pod nginx):
   Containers:
     nginx:
       State:          Running
       Started:        Mon, 01 Jan 2024 10:00:00 +0000

3. Succeeded阶段
   触发条件:
   - 所有容器成功执行并终止
   - 不会重启(RestartPolicy: Never/OnFailure)

   示例(Job):
   Pod状态:
   NAME          READY   STATUS      RESTARTS   AGE
   job-pod-123   0/1     Completed   0          1m

4. Failed阶段
   触发条件:
   - 所有容器已终止
   - 至少一个容器失败终止(退出码非0)

   示例:
   Pod状态:
   NAME    READY   STATUS   RESTARTS   AGE
   nginx   0/1     Error    0          30s

   容器状态:
   State:      Terminated
   Reason:     Error
   Exit Code:  1

5. Unknown阶段
   触发条件:
   - 无法获取Pod状态(通常是Node失联)

   示例:
   Pod状态:
   NAME    READY   STATUS    RESTARTS   AGE
   nginx   1/1     Unknown   0          5m

   事件:
   Node node1 is unreachable

Pod生命周期钩子(Lifecycle Hooks):

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: nginx
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo 'Container started' > /tmp/started"]
      preStop:
        exec:
          command: ["/bin/sh", "-c", "nginx -s quit; while killall -0 nginx; do sleep 1; done"]

钩子说明:

1. PostStart钩子
   - 容器启动后立即执行
   - 不保证在容器ENTRYPOINT之前执行
   - 如果钩子失败,容器会被杀死并重启

   使用场景:
   - 初始化配置
   - 通知外部系统(容器已启动)
   - 预热应用

2. PreStop钩子
   - 容器终止前执行
   - 阻塞式,钩子执行完成后才发送SIGTERM
   - 有超时时间(terminationGracePeriodSeconds,默认30秒)

   使用场景:
   - 优雅关闭(graceful shutdown)
   - 保存状态
   - 通知外部系统(容器即将停止)

完整终止流程:
1. Pod删除请求
2. Pod状态变为Terminating
3. 执行PreStop钩子(如果有)
4. 发送SIGTERM信号给容器主进程
5. 等待terminationGracePeriodSeconds(默认30秒)
6. 如果容器仍在运行,发送SIGKILL强制杀死

容器重启策略(RestartPolicy):

apiVersion: v1
kind: Pod
metadata:
  name: restart-demo
spec:
  restartPolicy: Always  # Always / OnFailure / Never
  containers:
  - name: nginx
    image: nginx

重启策略:

1. Always(默认)
   - 容器退出后总是重启
   - 适用:Deployment、StatefulSet、DaemonSet

   示例:
   容器退出码=0 -> 重启
   容器退出码=1 -> 重启

2. OnFailure
   - 容器失败时(退出码非0)重启
   - 适用:Job

   示例:
   容器退出码=0 -> 不重启
   容器退出码=1 -> 重启

3. Never
   - 容器退出后不重启
   - 适用:一次性任务

   示例:
   容器退出码=0 -> 不重启
   容器退出码=1 -> 不重启

重启间隔(Backoff):
- 第1次重启:立即
- 第2次重启:10秒后
- 第3次重启:20秒后
- 第4次重启:40秒后
- 最大间隔:5分钟

示例:
Pod状态:
NAME    READY   STATUS             RESTARTS   AGE
nginx   0/1     CrashLoopBackOff   5          5m

4. Pod的探针(Probe)有哪些类型?如何配置?

考察点: Pod健康检查机制

详细解答:

三种探针类型:

1. Liveness Probe(存活探针)
   作用:检测容器是否存活
   失败操作:重启容器

2. Readiness Probe(就绪探针)
   作用:检测容器是否准备好接受流量
   失败操作:从Service的Endpoints中移除Pod

3. Startup Probe(启动探针,K8s 1.16+)
   作用:检测容器是否启动完成
   失败操作:重启容器
   优势:适合启动慢的应用(避免Liveness Probe过早杀死容器)

探针检测方式:

1. Exec探针(执行命令)

apiVersion: v1
kind: Pod
metadata:
  name: exec-probe
spec:
  containers:
  - name: nginx
    image: nginx
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5  # 容器启动后5秒开始探测
      periodSeconds: 5        # 每5秒探测一次
      timeoutSeconds: 1       # 探测超时1秒
      successThreshold: 1     # 连续1次成功视为成功
      failureThreshold: 3     # 连续3次失败视为失败

工作原理:
1. kubelet在容器内执行命令:cat /tmp/healthy
2. 如果命令退出码=0,探测成功
3. 如果命令退出码!=0,探测失败
4. 连续3次失败,重启容器

使用场景:
- 检查文件是否存在
- 检查进程是否存在
- 自定义健康检查脚本

2. HTTP探针(HTTP GET请求)

apiVersion: v1
kind: Pod
metadata:
  name: http-probe
spec:
  containers:
  - name: web
    image: myapp:v1
    ports:
    - containerPort: 8080
    livenessProbe:
      httpGet:
        path: /healthz      # 健康检查端点
        port: 8080          # 端口
        httpHeaders:        # 自定义HTTP头(可选)
        - name: Custom-Header
          value: Awesome
        scheme: HTTP        # HTTP或HTTPS
      initialDelaySeconds: 10
      periodSeconds: 10
      timeoutSeconds: 3
      successThreshold: 1
      failureThreshold: 3

工作原理:
1. kubelet发送HTTP GET请求:GET http://Pod_IP:8080/healthz
2. 如果响应码 200 <= status < 400,探测成功
3. 否则,探测失败

应用端实现(Go示例):
func healthzHandler(w http.ResponseWriter, r *http.Request) {
    // 检查数据库连接
    if err := db.Ping(); err != nil {
        w.WriteHeader(http.StatusServiceUnavailable)
        w.Write([]byte("Database unavailable"))
        return
    }

    // 检查缓存连接
    if err := redis.Ping(); err != nil {
        w.WriteHeader(http.StatusServiceUnavailable)
        w.Write([]byte("Redis unavailable"))
        return
    }

    // 所有检查通过
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
}

http.HandleFunc("/healthz", healthzHandler)
http.ListenAndServe(":8080", nil)

使用场景:
- Web应用健康检查
- 微服务健康检查
- 依赖服务检查(数据库、缓存等)

3. TCP探针(TCP连接)

apiVersion: v1
kind: Pod
metadata:
  name: tcp-probe
spec:
  containers:
  - name: mysql
    image: mysql:5.7
    ports:
    - containerPort: 3306
    livenessProbe:
      tcpSocket:
        port: 3306
      initialDelaySeconds: 15
      periodSeconds: 10
      timeoutSeconds: 3
      failureThreshold: 3

工作原理:
1. kubelet尝试连接Pod的3306端口
2. 如果连接成功,探测成功
3. 如果连接失败,探测失败

使用场景:
- 数据库健康检查
- TCP服务健康检查
- 不支持HTTP的服务

探针配置参数详解:

livenessProbe:
  exec:
    command: ["/bin/sh", "-c", "check.sh"]
  initialDelaySeconds: 30  # 容器启动后等待30秒开始探测(避免应用启动慢)
  periodSeconds: 10        # 每10秒探测一次
  timeoutSeconds: 5        # 探测超时5秒(超过5秒视为失败)
  successThreshold: 1      # 连续1次成功视为成功(仅Liveness/Startup有效,Readiness固定1)
  failureThreshold: 3      # 连续3次失败视为失败

参数选择建议:

1. initialDelaySeconds:
   - 设置为应用启动时间 + 5秒缓冲
   - 太小:应用未启动完成就探测,导致频繁重启
   - 太大:应用启动失败无法及时发现

2. periodSeconds:
   - Liveness: 10-30秒(不宜太频繁)
   - Readiness: 5-10秒(可以频繁一些)

3. timeoutSeconds:
   - 根据应用响应时间设置
   - 网络较慢时可适当增大

4. failureThreshold:
   - Liveness: 3-5次(避免偶尔的网络抖动导致重启)
   - Readiness: 1-3次(快速摘除异常Pod)

Liveness vs Readiness vs Startup:

apiVersion: v1
kind: Pod
metadata:
  name: probe-demo
spec:
  containers:
  - name: app
    image: myapp:v1
    ports:
    - containerPort: 8080

    # Startup Probe(启动探针)
    # 作用:检测应用是否启动完成
    # 适用:启动慢的应用(如Java应用)
    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 0
      periodSeconds: 10
      failureThreshold: 30  # 最多等待300秒(30*10)Startup Probe成功后,才会执行Liveness和Readiness Probe

    # Liveness Probe(存活探针)
    # 作用:检测容器是否存活(是否需要重启)
    # 失败:重启容器
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 10
      failureThreshold: 3

    # Readiness Probe(就绪探针)
    # 作用:检测容器是否准备好接受流量
    # 失败:从Service的Endpoints中移除
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
      failureThreshold: 1

工作流程:

T0: 容器启动

T0-T1: Startup Probe探测
  - 如果成功,进入下一阶段
  - 如果失败超过30次(300秒),重启容器

T1: Startup Probe成功

T1-T2: Liveness和Readiness Probe开始探测
  - Liveness失败 -> 重启容器
  - Readiness失败 -> 从Endpoints移除,不重启

示例场景:

场景1:应用启动慢(Java应用需要60秒启动)
  问题:如果只配置Liveness(initialDelaySeconds=30),启动未完成就探测,导致重启循环
  解决:配置Startup Probe(failureThreshold=30,最多等待300秒)

场景2:应用依赖外部服务(数据库)
  问题:数据库临时不可用,不应该重启容器
  解决:
    - Liveness: 检查应用进程是否存活(不检查数据库)
    - Readiness: 检查数据库连接(数据库不可用时摘除Pod,恢复后自动加入)

场景3:应用滚动更新
  问题:新版本Pod启动后立即接收流量,可能尚未准备好
  解决:配置Readiness Probe,只有Probe成功后才加入Endpoints

最佳实践:

# 推荐配置(Web应用)

apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
  - name: app
    image: myapp:v1

    # Startup Probe:检测应用是否启动完成
    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      periodSeconds: 10
      failureThreshold: 30  # 最多等待5分钟

    # Liveness Probe:检测进程是否存活(简单检查)
    livenessProbe:
      httpGet:
        path: /healthz  # 轻量级检查(不检查依赖)
        port: 8080
      periodSeconds: 10
      failureThreshold: 3
      timeoutSeconds: 5

    # Readiness Probe:检测是否准备好接受流量(完整检查)
    readinessProbe:
      httpGet:
        path: /ready  # 完整检查(包括依赖服务)
        port: 8080
      periodSeconds: 5
      failureThreshold: 1
      timeoutSeconds: 3

应用端实现:

// /healthz:轻量级检查(Liveness)
func healthzHandler(w http.ResponseWriter, r *http.Request) {
    // 只检查进程是否存活
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
}

// /ready:完整检查(Readiness)
func readyHandler(w http.ResponseWriter, r *http.Request) {
    // 检查数据库
    if err := db.Ping(); err != nil {
        http.Error(w, "Database unavailable", http.StatusServiceUnavailable)
        return
    }

    // 检查Redis
    if err := redis.Ping(); err != nil {
        http.Error(w, "Redis unavailable", http.StatusServiceUnavailable)
        return
    }

    // 检查依赖服务
    if !isDownstreamServiceHealthy() {
        http.Error(w, "Downstream service unavailable", http.StatusServiceUnavailable)
        return
    }

    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Ready"))
}

第三部分:调度与资源管理

5. Kubernetes的调度策略有哪些?

考察点: 调度机制理解

详细解答:

调度流程:

1. 过滤(Predicate):排除不满足条件的Node
2. 打分(Priority):给剩余Node打分
3. 选择(Select):选择分数最高的Node

常见调度策略:

1. NodeSelector(节点选择器)

# 给Node打标签
kubectl label nodes node1 disktype=ssd

# Pod配置
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeSelector:
    disktype: ssd  # 只调度到有此标签的Node
  containers:
  - name: nginx
    image: nginx

优点:简单
缺点:不够灵活(只支持精确匹配)

2. Node Affinity(节点亲和性)

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      # 硬亲和性(必须满足)
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
            - nvme

      # 软亲和性(优先满足)
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - zone1

  containers:
  - name: nginx
    image: nginx

操作符:
- In: 标签值在列表中
- NotIn: 标签值不在列表中
- Exists: 标签存在
- DoesNotExist: 标签不存在
- Gt: 标签值大于(数值比较)
- Lt: 标签值小于(数值比较)

示例:
# 调度到SSD或NVMe磁盘的Node,优先zone1

Node1: disktype=ssd, zone=zone1 → 符合硬亲和性,符合软亲和性,分数最高
Node2: disktype=ssd, zone=zone2 → 符合硬亲和性,不符合软亲和性,分数较低
Node3: disktype=hdd, zone=zone1 → 不符合硬亲和性,排除

3. Pod Affinity / Anti-Affinity(Pod亲和性/反亲和性)

apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  affinity:
    # Pod亲和性(靠近某些Pod)
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname  # 同一Node

    # Pod反亲和性(远离某些Pod)
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - web
          topologyKey: kubernetes.io/hostname  # 避免同一Node

  containers:
  - name: web
    image: nginx

示例场景:

场景1:Web应用靠近Cache(亲和性)
  topologyKey: kubernetes.io/hostname → 调度到运行Cache Pod的Node

场景2:多个Web Pod分散部署(反亲和性)
  topologyKey: kubernetes.io/hostname → 避免多个Web Pod在同一Node

topologyKey说明:
- kubernetes.io/hostname: Node级别(同一Node)
- topology.kubernetes.io/zone: 可用区级别(同一可用区)
- topology.kubernetes.io/region: 区域级别(同一区域)

4. Taints and Tolerations(污点与容忍)

# 给Node打污点(阻止Pod调度)
kubectl taint nodes node1 key=value:NoSchedule

# Pod容忍污点
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"

  containers:
  - name: nginx
    image: nginx

污点效果(Effect):
1. NoSchedule: 不调度新Pod(已有Pod不受影响)
2. PreferNoSchedule: 尽量不调度(软限制)
3. NoExecute: 不调度新Pod,且驱逐已有Pod

示例:

# 专用Node(仅特定Pod可调度)
kubectl taint nodes gpu-node1 dedicated=gpu:NoSchedule

# GPU Pod配置容忍
tolerations:
- key: "dedicated"
  operator: "Equal"
  value: "gpu"
  effect: "NoSchedule"

# Node维护(驱逐所有Pod)
kubectl taint nodes node1 maintenance=true:NoExecute

# Pod配置容忍(维护期间不驱逐)
tolerations:
- key: "maintenance"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 3600  # 容忍3600秒后驱逐

资源请求与限制(Resource Requests & Limits):

apiVersion: v1
kind: Pod
metadata:
  name: resource-demo
spec:
  containers:
  - name: app
    image: myapp:v1
    resources:
      requests:      # 请求资源(调度依据)
        cpu: "250m"      # 0.25核
        memory: "512Mi"  # 512MB
      limits:        # 限制资源(运行时限制)
        cpu: "500m"      # 0.5核
        memory: "1Gi"    # 1GB

资源说明:

1. CPU:
   - 单位:m(millicore),1000m = 1核
   - 例如:250m = 0.25核 = 25%的CPU
   - requests: 保证的CPU时间
   - limits: 最大CPU时间(超过会被限流,不会被杀死)

2. Memory:
   - 单位:Ki、Mi、Gi、Ti 或 K、M、G、T
   - requests: 保证的内存
   - limits: 最大内存(超过会被OOMKilled)

调度影响:
Scheduler只看requests(不看limits)

Node资源:CPU=4核,Memory=8Gi

已调度Pod:
  Pod1: requests(CPU=1, Memory=2Gi)
  Pod2: requests(CPU=1, Memory=2Gi)

剩余资源:CPU=2核,Memory=4Gi

新Pod: requests(CPU=1, Memory=3Gi) → 可以调度
新Pod: requests(CPU=3, Memory=1Gi) → 无法调度(CPU不足)

QoS(服务质量等级):

1. Guaranteed(保证级别)
   条件:
   - 所有容器都设置了requests和limits
   - requests = limits

   示例:
   resources:
     requests:
       cpu: "1"
       memory: "1Gi"
     limits:
       cpu: "1"
       memory: "1Gi"

   特点:
   - 优先级最高
   - 资源不足时最后被驱逐
   - 适用:关键业务

2. Burstable(突发级别)
   条件:
   - 至少一个容器设置了requests或limits
   - requests < limits 或只设置其中一个

   示例:
   resources:
     requests:
       cpu: "250m"
       memory: "512Mi"
     limits:
       cpu: "500m"
       memory: "1Gi"

   特点:
   - 优先级中等
   - 资源不足时第二批被驱逐(按内存使用率排序)
   - 适用:一般业务

3. BestEffort(尽力而为)
   条件:
   - 所有容器都未设置requests和limits

   示例:
   resources: {}  # 不设置

   特点:
   - 优先级最低
   - 资源不足时第一批被驱逐
   - 适用:临时任务、测试环境

驱逐顺序(资源不足时):
BestEffort → Burstable(内存使用率高) → Guaranteed

Prev
09-分布式系统面试题
Next
11-系统设计面试方法论