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 | # 前置准备 |
~