k8s面试题总结
k8s面试题总结
一、网络插件 calico 的工作模式有哪几种
Calico 在 Kubernetes 中的工作模式主要分为以下几种,你在部署时可以根据集群环境、需求和底层网络选择不同模式:
1. BGP 模式
- 原理:每个节点运行 
calico/node,节点之间通过 BGP(Border Gateway Protocol) 交换路由信息。 - 特点:
- Pod IP 在整个集群中是可路由的,不需要 NAT。
 - 不依赖 Overlay(隧道),性能好,延迟低。
 - 常见有两种拓扑:
- Full-mesh BGP:所有节点互相建立 BGP 对等关系,适合小规模集群(几十个节点)。
 - Route Reflector 模式:大规模集群时,用一部分节点做 BGP Route Reflector 来减少对等连接数。
 
 
 
2. IP-in-IP 模式
- 原理:在节点之间使用 IP-in-IP 封装(类似 Overlay 网络),解决节点之间路由不可达的问题。
 - 特点:
- 适合没有配置 BGP 或底层网络不支持 Pod CIDR 直通的环境。
 - 数据包经过一次封装,性能比 BGP 模式稍差。
 - 默认模式之一,部署简单。
 
 
3. VXLAN 模式
- 原理:和 IP-in-IP 类似,但使用 VXLAN 封装。
 - 特点:
- 通常在云环境或底层网络受限时使用。
 - VXLAN 隧道更通用(大多数云厂商都支持),兼容性强。
 - 性能比纯三层(BGP 模式)差一些。
 
 
4. CrossSubnet 模式
- 原理:结合 BGP 和隧道(IP-in-IP 或 VXLAN)。
 - 特点:
- 同一子网内节点之间直接路由,不走隧道。
 - 跨子网节点之间才使用隧道封装。
 - 在性能和兼容性之间做平衡。
 
 
5. Policy-only 模式
- 原理:只使用 Calico 的 网络策略(NetworkPolicy) 功能,不负责 Pod 的网络互通。
 - 特点:
- 依赖 CNI 提供网络(比如 Flannel、Cilium、AWS VPC CNI),Calico 仅作为策略控制器。
 - 适合只想用 Calico 强大的安全策略功能的场景。
 
 
总结一下常见选择:
- 高性能裸机/自建数据中心 → BGP 模式(大规模用 Route Reflector)。
 - 云环境 / 无法直通路由 → VXLAN 或 IP-in-IP 模式。
 - 混合环境 → CrossSubnet。
 - 只要策略,不要网络 → Policy-only。
 
这是 Calico 各种工作模式的对比图(性能、兼容性、安全性 评分 1~5):
- BGP:性能最佳,但兼容性取决于底层网络是否支持。
 - IP-in-IP / VXLAN:兼容性强,适合云环境,但性能比直连稍差。
 - CrossSubnet:性能和兼容性折中。
 - Policy-only:依赖其他 CNI 提供网络,安全策略功能最强。
 
二、cgroup 和 ns 的区别
**在 **Linux 容器技术里,cgroup(control group)和 namespace(命名空间)是两大核心概念,它们解决的问题完全不同,但又经常配合使用。
1. cgroup(控制组)
- 作用:限制和管理进程可以使用的资源。
 - 核心点:资源隔离 + 限额控制。
 - 常见控制的资源:
- CPU(限制某个进程组最多使用多少 CPU 时间)
 - 内存(限制最大内存使用,超过时 OOM Kill)
 - 磁盘 I/O(限制读写带宽)
 - 网络带宽(在某些扩展里支持)
 
 - 使用场景:
- Docker 限制容器 CPU、内存用量
 - Kubernetes Pod 资源请求/限制(requests/limits)
 
 - 类比:像给进程“配额”,规定它能吃多少饭、喝多少水。
 
2. namespace(命名空间)
- 作用:提供进程间的隔离环境。
 - 核心点:视图隔离 + 资源虚拟化。
 - 常见类型:
- PID namespace:进程号隔离(容器里的 PID 1 不会看到宿主机 PID)
 - NET namespace:网络隔离(容器有独立网卡、IP、路由)
 - IPC namespace:进程间通信隔离(消息队列、信号量)
 - UTS namespace:主机名隔离(容器可有不同 hostname)
 - MNT namespace:挂载点隔离(不同文件系统视图)
 - USER namespace:用户和权限隔离(容器里 root 映射到宿主机普通用户)
 
 - 使用场景:
- 让容器拥有独立的文件系统、进程树、网络栈
 
 - 类比:像给进程戴上“VR 眼镜”,它只能看到自己虚拟出来的世界。
 
三、ns 隔离资源的原理
**要理解 **namespace(命名空间)是如何实现隔离的,得从 Linux 内核的设计原理 说起。
1. 基础概念
在 Linux 内核里,****一切都是全局的:
- **默认情况下,所有进程共享同一套 **进程号表、网络协议栈、挂载点表、主机名、IPC 资源。
 - 如果没有特殊机制,所有进程看到的都是同一个“系统”。
 
Namespace 的作用:就是在内核中创建多个“虚拟副本”,让进程只能访问自己那份副本,从而实现隔离。
2. 工作原理
(1)内核数据结构“虚拟化”
- **内核会为某些全局资源,设计一层 **namespace 抽象层。
 - 当新建一个 namespace 时,内核会生成该资源的“独立副本”。
 - **不同 namespace 下的进程,指向的是 **不同的内核对象。
 
例如:
- PID namespace:每个 namespace 都有独立的 PID 映射表。容器里的 PID 1,其实在宿主机可能是 2345。
 - NET namespace:每个 namespace 有自己的网卡、路由表、iptables 规则。容器之间网络互不影响。
 - MNT namespace:挂载点表被隔离,不同容器看到的文件系统层次不同。
 
(2)进程与 namespace 的绑定
- **每个进程在内核中都有一个 **
task_struct结构体。 - **里面包含指针,指向该进程所属的 **namespace 对象(pid_ns、net_ns、mnt_ns…)。
 - **所以 **同一宿主机上的进程,可以属于不同的 namespace。
 
(3)系统调用支持
- **Linux 提供了 **
clone()、unshare()、setns()等系统调用,用来创建或切换 namespace。 - 容器运行时(Docker、containerd、K8s)启动容器时,会调用这些 API:
clone(CLONE_NEWNET)→ 创建新的网络栈clone(CLONE_NEWPID)→ 创建新的 PID 空间clone(CLONE_NEWNS)→ 创建新的挂载空间
 
3. 类比理解
- namespace 就像一个 隔板,把原本全局共享的大空间分隔成多个小房间,每个进程只能在自己的房间里活动。
 - 进程看不到房间外的东西,所以它“以为”自己独占了系统。
 
🔹 总结
- 原理:namespace 通过内核抽象层,把全局资源复制/虚拟化成多个实例,每个进程只绑定到自己的实例。
 - 关键点:
- 数据结构隔离(不同 namespace,资源表不同)
 - 进程与 namespace 绑定(task_struct 记录所属 ns)
 - 系统调用支持(clone/unshare/setns 管理 ns 生命周期)
 
 
**⚡ **一句话:namespace 通过在内核中为全局资源建立多个副本 + 进程绑定不同副本,实现“视图隔离”。
四、k8s 创建 pod 的流程
**Kubernetes 创建一个 Pod,其实涉及 **API Server、调度器、kubelet、容器运行时 等多个核心组件。我给你梳理下 从用户提交 YAML 到 Pod 运行起来 的完整流程。
1. 用户提交请求
- **用户通过 **
kubectl apply -f pod.yaml或 API 调用,向 API Server 发送创建 Pod 的请求。 - API Server:
- 接收请求
 - 校验 YAML(合法性、schema、资源配额、Admission Webhook…)
 - **存储 Pod 对象到 **etcd
 
 
👉 此时,Pod 对象已经存在于 etcd,但还没运行。
2. 调度流程
- 调度器(kube-scheduler) 会监听到新 Pod 处于 
Pending状态。 - 调度器:
- 根据调度策略(资源请求/限制、亲和性/反亲和性、污点/容忍度、优先级等)筛选可用节点
 - 选择一个最优节点
 - **把调度结果(Pod → 节点)写回 **API Server
 
 
**👉 此时,Pod 还是 **Pending,但已经绑定到某个 Node。
3. kubelet 创建 Pod
- **目标节点上的 **kubelet 监听到有 Pod 调度过来。
 - kubelet 执行以下步骤:
- 向 API Server 拉取 Pod 的定义
 - **创建 **PodSandbox(通常是一个 pause 容器,充当 Pod 的网络 & namespace 容器)
 - 配置 Pod 网络(CNI 插件:Calico、Flannel…,为 Pod 分配 IP)
 - 配置存储卷(挂载 PV、PVC、本地目录、ConfigMap、Secret 等)
 - 拉取镜像(containerd / CRI-O / Docker shim)
 - 启动 Pod 中定义的各个容器
 
 
**👉 此时,容器运行起来,Pod 进入 **Running 状态。
4. Pod 生命周期管理
- kubelet 持续监控容器状态,上报给 API Server。
 - API Server 把状态写入 etcd。
 - **用户通过 **
kubectl get pod看到的状态,其实是从 etcd → API Server → kubectl 返回的结果。 - **如果容器异常退出,kubelet 会按 Pod 的 **
restartPolicy(Always/OnFailure/Never)决定是否重启。 
5. 事件流总结
- kubectl / API → 请求创建 Pod
 - API Server → 校验、存储到 etcd
 - 调度器 → 选择节点,更新 Pod 绑定信息
 - kubelet(目标节点) → 创建 PodSandbox、网络、存储、拉镜像、启动容器
 - Pod Running → 状态通过 kubelet 上报 API Server
 
🔹 总结
- API Server:前台,接收请求,存储对象
 - Scheduler:选人(决定 Pod 跑在哪个节点)
 - Kubelet:干活的工人(在节点上真正创建容器)
 - etcd:存档,保存集群所有状态
 
⚡一句话:用户提交 YAML → API Server 存储 → Scheduler 分配 → Kubelet 创建 → Pod Running。
五、svc 暴露端口用到的是哪个组件
bernetes 里,****Service (svc) 暴露端口时用到的核心组件主要是 kube-proxy。
Service 暴露端口的实现组件
1. kube-proxy
- 运行在每个节点上。
 - 作用:
- 监听 API Server 上的 Service 和 Endpoints 变化。
 - **在节点上设置转发规则,让访问 **
ServiceIP:Port能被转发到后端 Pod。 
 - 实现方式:
- iptables 模式(常用):基于 iptables 的 DNAT 规则转发流量。
 - ipvs 模式:基于 Linux IPVS,性能更好,支持更多调度算法(rr、lc、dh 等)。
 - userspace 模式(很少用,性能差)。
 
 
**👉 **核心点:Pod 内部或节点上访问 Service ClusterIP,流量先经过 kube-proxy 配置的规则,再转发到某个 Pod。
2. Service 类型决定是否需要其他组件
- ClusterIP(默认):
- 仅集群内部可访问。
 - 依赖 kube-proxy 实现端口转发。
 
 - NodePort:
- 在每个 Node 上打开一个端口(30000–32767)。
 - 仍由 kube-proxy 维护规则,把访问 Node:Port 的流量转发到 Pod。
 
 - LoadBalancer:
- **需要依赖云厂商的 **云负载均衡器(比如 AWS ELB、阿里云 SLB)。
 - kube-proxy 仍然负责节点内部转发。
 
 - ExternalName:
- 不依赖 kube-proxy,只是 DNS CNAME 到外部地址。
 
 
🔹 总结
- 核心组件:
kube-proxy(iptables 或 ipvs 规则,负责转发 Service 流量)。 - 扩展组件:
- NodePort → 依赖 kube-proxy
 - **LoadBalancer → 依赖 **云厂商 LB + kube-proxy
 - ExternalName → 依赖 DNS,不走 kube-proxy
 
 
⚡一句话:Kubernetes Service 暴露端口的底层实现,核心就是 kube-proxy,它在每个节点配置转发规则,把 Service IP/端口映射到后端 Pod。
六、云上以及二进制部署的k8s 怎样扩容集群
☁️ 云上 K8s 扩容
(典型:阿里云 ACK、腾讯云 TKE、AWS EKS、GKE、AKS)
1. 控制平面扩容
- 大多数云厂商已经提供了高可用的 API Server / etcd 管理,用户通常不需要手动扩容控制平面。
 - **如果支持 **专有集群 / 自管控制平面,一般通过控制台或 API 新增 Master 节点,云平台会自动调整 
etcd和kube-apiserver。 
2. Node 扩容
方式一:****控制台/CLI 一键加节点
- 在控制台选择“添加节点” → 选择云服务器规格、数量。
 - 系统自动安装 kubelet / kube-proxy,并加入集群。
 
方式二:****弹性伸缩 (Cluster Autoscaler)
- 开启自动伸缩,云平台会自动创建/释放节点。
 - 常用于弹性业务场景。
 
**👉 **云上扩容的关键是:节点由云厂商提供初始化脚本,自动向 API Server 注册。
🖥 二进制部署 K8s 扩容
(二进制方式:kubeadm 之外的纯手工安装,常见于生产环境或大规模私有云)
1. 扩容 Master 节点
- 需要手动准备新服务器,安装:
kube-apiserver、kube-scheduler、kube-controller-manager。 - 将新 Master 加入现有的 etcd 集群:
- 在 etcd 上添加新成员 → 同步数据
 - 修改所有 Master 配置 → 让它们都能访问完整 etcd 集群
 
 - 配置 kube-apiserver 使用新的 etcd 集群。
 - 配置高可用入口(Nginx/HAProxy/Keepalived/VIP)来统一 API Server 地址。
 
2. 扩容 Node 节点
步骤:
- 在新机器上安装必要组件:
- kubelet
 - kube-proxy
 - CNI 插件(Calico/Flannel/Cilium 等)
 
 - 配置 kubelet:
- **指定 **
--kubeconfig指向 API Server - 设置节点名、证书、工作目录
 
 - **指定 **
 - 启动 kubelet → kubelet 会向 API Server 注册自己。
 - **管理员在 Master 上 **
kubectl get nodes查看新节点状态。 
3. 注意点
- 证书签发:如果启用了 TLS,需要新节点的 kubelet 证书由集群 CA 签发。
 - 网络:确保新节点与 Pod 网段、Service 网段互通。
 - 负载均衡:如果是 Master 扩容,记得更新 LB 配置,把新 Master 加入。
 
🔹 总结对比
| 部署方式 | Master 扩容 | Node 扩容 | 
|---|---|---|
| 云上托管 | 云厂商自动维护,用户无需操作 | 控制台/CLI 添加节点,或启用弹性伸缩 | 
| 二进制自建 | 手动安装组件,加入 etcd,配置 LB | 手动安装 kubelet/kube-proxy,配置证书,加入 API Server | 
⚡一句话:
- 云上扩容 → 控制台点几下,节点自动加进来。
 - 二进制扩容 → 自己装 kubelet/kube-proxy/网络插件,搞证书,搞 etcd/LB。
 
七、k8s有几种探针以及区别 探针失败了 k8s 会咋样
exec TCPSoket HTTPGet
**在 Kubernetes 里 **Pod 的健康检查是靠 探针 (Probe) 实现的,一共有三种:
1. 探针类型
✅ Liveness Probe(存活探针)
- 作用:判断容器是否“还活着”。
 - 失败时行为:kubelet 会 杀掉容器并重启(遵循 
restartPolicy)。 - 典型用途:容器进程卡死、死循环、死锁时,用它来自动重启恢复。
例子1
2
3
4
5
6livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 5 
解释:
- 容器启动后 10 秒开始检测。
 - **每 5 秒检查一次 **
/healthz接口。 - 如果接口连续失败,k8s 会重启容器。
 
2. Readiness Probe(就绪探针)
- 作用:检查容器是否 准备好接收流量。
 - 行为:如果 Readiness 探针失败,Pod 会 从 Service 的 Endpoints 中移除,不会被流量路由到。
 - 典型场景:应用启动慢,或者加载了大数据才真正可用。
 
示例:
1  | readinessProbe:  | 
解释:
- **容器启动 5 秒后开始检查 **
/ready接口。 - 接口失败则表示容器暂时不接收流量,但不会被重启。
 
3. Startup Probe(启动探针)
- 作用:用于检测 容器启动是否成功,适用于启动慢的应用。
 - 行为:
- **在容器启动阶段,Startup Probe 失败会 **直接重启容器。
 - 启动完成后,Startup Probe 会停止工作,交给 Liveness Probe 监控。
 
 - 典型场景:Java、数据库等启动很慢的服务。
 
例子
1  | startupProbe:  | 
解释:
- **每 10 秒检查一次 **
/healthz。 - 连续失败 30 次才重启容器,适合启动时间较长的应用。
 
4. 区别总结表
| 探针类型 | 触发动作 | 典型用途 | 
|---|---|---|
| Liveness | 失败 → 容器重启 | 死锁、进程挂掉 | 
| Readiness | 失败 → Pod 从 Service 移除 | 应用暂时不可用 | 
| Startup | 失败 → 容器重启(仅启动阶段) | 启动慢的应用 | 
5. 举例说明容器探针失败后的行为
假设我们有一个 Nginx 容器:
1  | containers:  | 
- **如果 **
/healthz接口返回非 200,连续失败:- k8s 会杀掉 nginx 容器并重启。
 
 - 如果我们加了 Readiness Probe:
- Pod 会暂时被 Service 下线,不会被访问,直到探针恢复。
 
 
八、k8s组件总览
1️⃣ 命名空间 / 资源隔离相关
- Namespace(命名空间):Kubernetes 内置,用于逻辑隔离资源。
 - NetworkPolicy:控制 Pod 间网络访问策略,实现隔离。
 - RBAC(Role/ClusterRole):权限隔离。
 - ResourceQuota / LimitRange:资源使用隔离。
 
类似 “ns” 的概念,主要是做逻辑分组、隔离和权限控制。
2️⃣ 服务发现 / DNS
- CoreDNS:
- 默认集群 DNS 组件。
 - **为 Pod 提供 **
service-name.namespace.svc.cluster.local解析。 
 - kube-dns(旧版,已被 CoreDNS 替代)。
 - ExternalDNS:
- 将 Kubernetes Service 的域名自动同步到外部 DNS(如 Route53、阿里云 DNS)。
 
 
**核心功能是名字解析和服务发现,类似 Linux 下的 **
nslookup/hosts功能,但在集群内部自动化。
3️⃣ 网络 / CNI 相关
- CNI 插件(Container Network Interface):
- Calico:提供网络策略和安全组功能。
 - Flannel:简单的 L2/L3 网络实现。
 - Weave Net:支持加密和跨节点 Pod 通信。
 - Cilium:基于 eBPF 的高级网络和安全策略。
 
 - kube-proxy:
- 实现 ClusterIP、Service 负载均衡。
 
 
这些组件都和 Pod 通信、网络路由、服务发现有关系。
4️⃣ 配置 / 配置管理
- ConfigMap:管理非敏感配置信息。
 - Secret:管理敏感信息(密码、证书)。
 - ServiceAccount / Token:提供 Pod 对 API Server 的访问凭证。
 
配置、密钥、访问控制也是“命名和资源管理”的一部分。
5️⃣ 高级服务发现 / 服务网格
- Istio / Linkerd / Consul:
- 提供微服务间流量管理、服务发现、可观测性。
 - 结合 Envoy 代理实现 L7 层流量控制。
 
 
💡 总结: ** “类似 **ns 的组件”,可以理解为 命名、隔离、发现、路由相关的系统组件,主要包括:
- 命名空间、RBAC、资源配额(隔离)
 - CoreDNS / kube-dns / ExternalDNS(服务发现)
 - CNI 插件、kube-proxy(网络和路由)
 - 配置管理组件(ConfigMap / Secret)
 - 高级服务网格(Istio / Consul / Linkerd)
 
九、Deployment StatefulSet 有状态的和无状态的服务之间的区别
**在 **Kubernetes 中,Deployment 和 StatefulSet 是两种常见的 工作负载控制器,主要用于管理 无状态服务 和 有状态服务。它们的区别主要体现在以下几个方面:
1. 适用场景
- Deployment(无状态服务)
- **用于 **无状态应用,比如 Nginx、前端应用、微服务 API、负载均衡器等。
 - 每个 Pod 都是相同的,之间没有身份差异,随时可替换或扩缩容。
 
 - StatefulSet(有状态服务)
- **用于 **有状态应用,比如 MySQL、Redis(主从)、Zookeeper、Kafka、Etcd。
 - **每个 Pod 都有 **固定身份(编号、存储),不能随便替换。
 
 
2. Pod 标识(Identity)
- Deployment
- Pod 名称是随机的,比如:
nginx-5c9c7d8c9f-abc12。 - 删除一个 Pod,再起的新 Pod 名字不同。
 - **所有 Pod **对外是一样的。
 
 - Pod 名称是随机的,比如:
 - StatefulSet
- Pod 有固定的编号,比如:
mysql-0,mysql-1,mysql-2。 - **删除 **
mysql-1后,新建的 Pod 还是mysql-1。 - Pod 之间有顺序和唯一身份。
 
 - Pod 有固定的编号,比如:
 
3. 存储(Storage)
- Deployment
- **一般配合 **临时存储(emptyDir) 或共享存储。
 - Pod 删除后数据也会丢失。
 
 - StatefulSet
- **支持 **稳定的持久化存储(PVC),通常由 
volumeClaimTemplates生成。 - 即使 Pod 被删除或迁移,数据依然会保留,并重新挂载到同编号的 Pod 上。
 
 - **支持 **稳定的持久化存储(PVC),通常由 
 
4. 启动顺序与依赖
- Deployment
- **Pod 可以 **无序并行启动,因为它们没有依赖关系。
 
 - StatefulSet
- **Pod 有顺序:先启动 **
pod-0,再启动pod-1…… - **删除时也是 **逆序删除。
 - **适合需要 **主从/集群初始化 的场景。
 
 - **Pod 有顺序:先启动 **
 
5. 网络标识(DNS)
- Deployment
- Pod 的 DNS 名字是随机的,只能通过 Service 访问。
 
 - StatefulSet
- 每个 Pod 都有稳定的 DNS 名字:
1
2<pod-name>.<service-name>.<namespace>.svc.cluster.local
比如:mysql-0.mysql.default.svc.cluster.local - 方便应用之间直接通过固定域名访问。
 
 - 每个 Pod 都有稳定的 DNS 名字:
 
6. 典型使用场景
- Deployment(无状态)
- Web 服务(Nginx、Tomcat)
 - API 服务
 - 静态内容服务
 
 - StatefulSet(有状态)
- 数据库(MySQL、Postgres、MongoDB)
 - 分布式协调服务(ZooKeeper、Etcd、Consul)
 - 消息队列(Kafka、RabbitMQ)
 
 
📌 总结一句话
- **如果应用 **不依赖持久存储、Pod 身份、启动顺序 → 用 Deployment。
 - **如果应用 **需要固定身份、稳定存储、顺序启动 → 用 StatefulSet。
 
十、yaml方式介绍deploy有哪些组件
qexo
1  | # 前置准备  | 
nginx
1  | # 前置准备  | 
~


