K8S八股自筛选总结
Kubernetes网络策略(NetworkPolicy)如何实现Pod间通信控制?
NetworkPolicy通过label选择Pod,基于Ingress/Egress规则定义允许或拒绝Pod间网络访问,配合网络插件(如Fannel、Calico)实现网络隔离策略。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
如何排查Pod无法启动的问题?
- 资源不足:节点CPU、内存或临时存储不足。
- 节点选择问题:nodeSelector或nodeAffinity配置不匹配。
- 持久卷未绑定:PVC未找到可用PV。
- 污点与容忍不匹配:节点有排斥性污点,Pod未配置容忍。
- 资源配额超限:Namespace的ResourceQuota耗尽。
验证标签与选择器:
# 节点标签
kubectl get nodes --show-labels
# Pod选择器
kubectl get pod <pod-name> -o yaml | grep nodeSelector
检查污点与容忍:
# 节点污点
kubectl describe node <node-name> | grep Taints
# Pod容忍
kubectl get pod <pod-name> -o yaml | grep tolerations
为什么要设置PodDisruptionBudget?
用于保护应用高可用,避免维护或升级时服务中断。
- PDB 是一种保险策略,用于防止自愿性干扰(如节点维护)导致应用停机。
- 它通过 Eviction API 工作,确保集群中始终有最小数量的应用实例在运行。
- 它不能防止硬件故障等非自愿性干扰。
- 它不会阻止
kubectl delete pod或 Deployment 的滚动更新,但会与这些操作并发考虑,以提供更高级别的稳定性。
Kubernetes容器探针(Probe)的三种探测方式是什么?
- Exec:执行命令,成功返回0则探测成功。
- HTTPGet:通过HTTP请求健康检查。
- TCPSocket:通过TCP端口检查容器是否正常运行。
说一下Deployment、StatefulSet、DaemonSet的区别,以及和pod之间的关系
- Deployment:主要用于无状态应用,Pod可任意扩展、缩减,无严格顺序要求。
- StatefulSet:主要用于有状态的服务,Pod具有稳定的标识(网络、存储),Pod启动和销毁严格按照顺序进行(如数据库)。
- DaemonSet:主要部署监控软件、收集日志、网络插件(核心特性:确保每个符合条件的节点运行一个Pod副本)。逐步替换旧Pod
什么是Ingress
Ingress为K8s集群中的服务提供了一个统一的入口,可以提供负载均衡、SSL终止和基于名称(域名)的虚拟主机、应用的灰度发布等功能,在生产环境中常用的Ingress控制器有Treafik、Nginx、HAProxy、Istio等。
相对于Service,Ingress工作在七层(部分Ingress控制支持2和6层),所以可以支持HTTP协议的代理,也就是基于域名的匹配规则。
Ingress 常见报错排查
404 表示访问的路由不存在,通常问题如下:
- Ingress 路径配置的不正确
- Ingress 的配置未被 Controller 解析
- 未使用正确的域名和路径访问
- 代理的服务没有该路径
- 请求的方法不同
413(Request Entity Too Large)报错
有时候需要上传一些大文件给程序,但是 nginx 默认允许的最大文件大小只有 8M,不足以满足生产最大上传需求,此时可以通过 nginx.ingress.kubernetes.io/proxy-body-size 参数进行更改(也可以在 ConfigMap 中全局添加):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
namespace: study-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 32m
spec:
....
503 一般是代理的服务不可用导致的,通常问题如下:
- Ingress 代理配置错误,比如 Service 名字或端口写错
- Ingress 代理的 Service 不存在
- Ingress 代理的 Service 后端 Pod 不正常
504 一般是代理的服务处理请求的时间过长,导致 Nginx 等待超时,此时需要确认服务的处
理时长,或者查看服务是否有问题
CORS 跨域报错:CORS错误。说明被跨域给拦截了,可以添加跨域配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: longtime
namespace: study-ingress
annotations:
# 允许跨域的请求方法
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST,OPTIONS, DELETE"
# 允许携带的请求头
nginx.ingress.kubernetes.io/cors-allow-headers: "X-Forwarded-For, Xapp123-XPTO"
# 允许跨域的域名
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
spec:
....
核心组件协作流程
以部署一个应用为例:
- 用户通过kubectl提交Deployment配置。
- API Server接收请求并写入etcd。
- Controller Manager创建Pod,Scheduler将Pod绑定到Node。
- 目标Node的kubelet启动容器,kube-proxy配置网络规则。
- Service对外暴露服务,流量通过负载均衡分发到Pod。
PVC和Pod处于Pending的原因
- PVC一直Pending的原因
- PVC的空间申请大小大于PV的大小
- PVC的StorageClassName没有和PV的一致
- PVC的accessModes和PV的不一致
- 请求的PV已被其他的PVC绑定
- 挂载的PVC的Pod一直Pending的原因
- PVC没有创建成功/PVC不存在
- PVC和Pod不在同一个Namespace
Pod如何实现亲和性与反亲和性?
亲和性与反亲和性通过节点亲和性(NodeAffinity)和Pod亲和性(PodAffinity/PodAntiAffinity)实现。
- 亲和性(Affinity):允许Pod根据节点或其他Pod的特征调度在特定节点。
- 反亲和性(Anti-affinity):防止Pod被调度到具有特定特征的节点或与其他Pod位于同一节点。
使用nodeAffinity指定Pod倾向于部署到特定节点,而PodAntiAffinity则避免多个相似Pod集中在同一节点上,增强容灾能力。
在复杂的分布式系统中,如何利用亲和力与拓扑域协同工作以确保服务的高可用性和性能优化?
使用拓扑域划分不同的可用域,然后使用亲和力尽量把服务分散开,同时根据需求优先调度某些节点。
如果部署一个5个副本的服务,需要把他们优先分散到具有subnet标签的节点上,能否实现?
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-service
spec:
replicas: 5
template:
metadata:
labels:
app: my-service # 关键:反亲和性需要这个 label 来识别“同类”
spec:
affinity:
# --- 步骤1:硬性过滤 ---
# 告诉调度器:我 *只* 允许去有 "subnet" 标签的节点
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: subnet # 假设你的标签键是 'subnet'
operator: Exists # 只要存在这个 key 就行
# 或者如果你有具体的值:
# operator: In
# values:
# - subnet-a
# - subnet-b
# --- 步骤2:软性打分 ---
# 告诉调度器:在那些你选出来的 "subnet" 节点里,
# *尽量* 不要把我的同类 Pod 放在同一个节点(hostname)上
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
# 'weight' 只是一个优先级,1-100 随便写
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- my-service
# "域":我们这里定义的“分散”范围是 "hostname",即节点
topologyKey: kubernetes.io/hostname
containers:
- name: web-server
image: nginx
在K8s集群中如何划分不同的租户?
首先根据节点划分标签组,之后根据标签配置污点,最后给不同租户添加不同的节点选择器和容忍。
污点的影响效果
- NoSchedule:禁止调度Pod到该节点上,但是已经运行在该节点到服务不受影响。适用于资源隔离和节点维护的场景。
- NoExecute:禁止调度Pod到该节点上,同时已经运行在该节点上的Pod也会被驱逐(终止并重新调度)。适用于节点故障、紧急维护和故障快速恢复的场景。
- PreferNoSchedule:类似于NoSchedule。但不是一个硬性限制,调度器会尽量避免将新的Pod调度到这个节点上,但如果其他节点都不满足条件,Pod仍然会被调度到这个节点上。适用于软性资源隔离的场景。
如何实现节点隔离(Pod不调度到某节点)?
- 使用kubectl cordon标记节点为不可调度。
- 使用taint与toleration实现节点级别Pod调度控制。
说一下ResourceQuota、LimitRange、QoS是什么?使用场景是什么?
| 名称 | 定义 | 使用场景 |
|---|---|---|
| ResourceQuota | 限制命名空间级别的资源总量,包括计算资源(CPU/内存)和对象数量(Pod/Service等) | 用于多租户环境下,避免某个租户过度使用资源 |
| LimitRange | 为命名空间内资源对象(Pod/Container)设置默认和最大/最小资源限制 | 规范配置:避免容器内存超限崩溃;自动填充未声明的资源请求值 |
| QoS | 根据Pod的资源配置确定其在资源紧张的优先级,确保关键任务的Pod能够获得资源 | 保障核心业务 |
Kubernetes中QoS的三种类型有哪些?
- Guaranteed:设置相同的requests和limits,保证资源。
- Burstable:requests < limits,可能资源被限制或驱逐。
- BestEffort:没有设置requests和limits,资源最低保证。
Kubernetes中,Pod资源限制超出时会发生什么?
- 超过内存(limits):Pod会被OOMKilled,容器自动重启。
- 超过CPU(limits):Pod被CPU限流(CPU被throttle),性能受限,但不会被驱逐或杀掉。
Kubernetes的调度算法主要考虑哪些因素?
- 节点资源充足性(CPU/内存)
- 节点亲和性与反亲和性
- 污点(taint)和容忍度(toleration)
- 自定义调度策略(调度扩展器)
什么是KEDA?
KEDA是一个基于K8s的事件驱动自动伸缩器。使用KEDA,可以根据需要处理的事件数量、消息队列来驱动K8s中任何服务的伸缩。
KEDA的核心思想是:只要有任务需要处理时,才扩展应用程序,并且在没有工作时缩减资源,甚至可以将副本缩容到零。这不仅提高了资源利用率,还降低了成本。
为什么需要KEDA?
- 基于事件扩缩容
- 基于消息队列扩缩容
- 基于流量扩缩容
- 基于自定义指标扩缩容
- 基于各种策略扩缩容
KEDA使用场景
- 基于消息队列的任务处理:KEDA支持从各类消息的数量自动扩容缩容相关服务
- 基于HTTP请求的扩缩容:KEDA支持从HTTP请求的数量自动扩缩容相关服务
- 定时任务和批处理:KEDA支持时间的触发器,定时进行扩缩容
- 无服务架构:KEDA支持Scale to Zero,功能和Serverless类似
KEDA架构
- ScaledObject:KEDA核心资源,用于定义扩缩容规则
- Controller:KEDA控制器,监听APIServer的KEDA对象,并根据规则通知Scaler调整副本数量
- Scaler:Scaler与HPA协同工作,以实现自动扩展
- External Trigger Source:外部事件或数据源,可以触发KEDA的扩展操作
- Metrics Adapter:用于定义自定义指标
KEDA核心资源
- ScaledObject:用于控制Deployment等资源的副本数,可以指定多种事件和消息来源控制资源的副本数,同时支持Scale to Zero
- ScaledJob:用于触发一次性Job任务,可以根据多种外部事件源触发创建一次性任务,主要用于处理批处理任务或临时任务,类似Serverless
- TriggerAuthentication:用于管理KEDA Scaler与外部事件源(如RabbitMQ、AWS SQS、Azure Queue等)之间的身份验证和授权,支持环境变量、ConfigMap、Secret等
全链路追踪核心概念
- Trace:一个请求的完整操作过程被称作一个Trace,代表从客户端发起请求到后端完全处理到整个过程,一个trace由多个span组成。
- Span:一个Span表示Trace中的一部分工作,可以理解为一次函数调用或者是一个HTTP请求。每个Span都包含了操作名称、开始时间、结束时间以及操作相关的元数据等信息。Span具有上下级关系(父子关系),同时多个Span的结合就表达了一次Trace。
- Trace ID 和 Span ID:每个Trace都有一个唯一的 Trace ID,每一个Span都有一个唯一的 Span ID,并且还包含了指向父级Span的引用。