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