3. Kubernetes核心架构:从Master到Worker,一探究竟
聊到Kubernetes,很多人第一反应就是「复杂」。其实说白了,它就是一个大型的分布式操作系统。你想想看,操作系统管理进程、内存、磁盘,K8s管理容器、网络、存储。道理是一样的。
我个人习惯把K8s集群比作一个公司。Master节点就是管理层,Worker节点就是一线员工。今天我们就来拆解一下,这个公司到底是怎么运作的。
3.1 Master节点:集群的大脑
Master节点负责整个集群的决策和调度。它不跑你的业务应用,只负责「管人」。我见过不少新手把业务Pod也调度到Master上,嗯,这在生产环境是大忌。
3.1.1 API Server:集群的「前台」
API Server是整个集群的入口。所有的操作,无论是kubectl命令、Pod调度、还是Controller的监听,最终都要经过它。
- 认证与授权:谁来了?能干什么?API Server会检查你的证书或Token。
- 请求路由:把写请求(如创建Pod)存入etcd,把读请求(如查询Pod状态)从缓存或etcd中取出。
- 准入控制:在请求真正执行前,有一堆插件会检查它。比如资源配额、Pod安全策略等。
核心要点:API Server是无状态的,它只负责处理请求。真正的数据存在etcd里。所以你可以横向扩展API Server,但etcd不行。
我在项目中遇到过一个问题:某次集群突然变慢,所有kubectl命令都要等好几秒。排查后发现是etcd的磁盘IO打满了。API Server本身没问题,但后端存储扛不住了。所以监控API Server时,别忘了看etcd的健康状态。
3.1.2 Scheduler:集群的「HR」
Scheduler负责给新创建的Pod找个合适的Worker节点。它不负责运行Pod,只负责「分配」。
调度过程其实就两步:
- 过滤:把不满足条件的节点剔除。比如节点资源不足、有污点(Taints)等。
- 打分:对剩下的节点打分,选分数最高的。打分策略包括资源利用率、亲和性规则等。
你想想看,如果集群里有100个节点,Scheduler得在几秒内完成这个决策。默认的调度器已经很快了,但如果你有特殊需求,比如GPU任务优先调度到有GPU的节点,可以写自定义调度器。
避坑指南:我曾经遇到过Pod一直处于Pending状态,查了半天发现是Scheduler的Leader选举出了问题。Scheduler本身是高可用的,但只有Leader在工作。如果Leader挂了,新的Leader没选出来,所有Pod都调度不了。所以一定要监控Scheduler的Leader状态。
3.1.3 Controller Manager:集群的「监工」
Controller Manager其实是一堆控制器的集合。每个控制器负责维护一种资源的期望状态。
举个例子:
- Deployment Controller:确保运行的Pod副本数等于你指定的数字。多了就杀掉,少了就创建。
- Node Controller:监控节点健康状态。节点挂了,它负责给上面的Pod打上「不可调度」的标记。
- Endpoint Controller:维护Service和Pod的对应关系。
控制器的核心逻辑就是一个循环:
for {
实际状态 := 从API Server获取当前状态
期望状态 := 从API Server获取用户定义的期望状态
if 实际状态 != 期望状态 {
执行操作,让实际状态向期望状态靠拢
}
等待一段时间,继续循环
}
说白了,就是「看现状,想目标,动手改」。这个模式在K8s里无处不在。
3.2 Worker节点:干活的「员工」
Worker节点是真正运行你业务容器的地方。每个Worker节点上都有三个核心组件:Kubelet、Kube-proxy、容器运行时。
3.2.1 Kubelet:节点的「管家」
Kubelet是Master在Worker节点上的代理人。它负责:
- 从API Server接收Pod的定义
- 调用容器运行时(如Docker、containerd)启动或停止容器
- 定期向API Server上报节点和Pod的状态
- 执行存活探针(Liveness Probe)和就绪探针(Readiness Probe)
我建议你把Kubelet的日志级别调高一点。默认的日志信息太少,出了问题很难排查。我曾经遇到过Pod反复重启,查了半天才发现是Kubelet的cgroup驱动和容器运行时的不一致。
注意:Kubelet不是高可用的。每个节点只有一个Kubelet进程。如果它挂了,这个节点上的所有Pod都会失去管理。所以一定要用systemd或supervisor保证Kubelet进程的稳定性。
3.2.2 Kube-proxy:网络的「交通警察」
Kube-proxy负责实现Service的负载均衡。它把发往Service VIP的流量,转发到后端的Pod上。
Kube-proxy有三种模式:
| 模式 | 原理 | 性能 | 适用场景 |
|---|---|---|---|
| userspace | 用户态代理,性能差 | 低 | 已废弃,别用 |
| iptables | 利用Linux内核的iptables规则 | 中等 | 小规模集群(< 1000个Service) |
| IPVS | 利用Linux内核的IPVS模块 | 高 | 大规模集群,推荐使用 |
我个人习惯用IPVS模式。iptables在Service数量多的时候,规则更新会非常慢,而且容易导致CPU飙升。IPVS使用哈希表,性能稳定得多。
3.2.3 容器运行时:真正的「工人」
容器运行时负责拉取镜像、创建容器、管理容器的生命周期。常见的容器运行时包括:
- Docker:最流行,但K8s 1.24之后已经弃用Docker作为默认运行时。
- containerd:Docker的底层运行时,现在K8s默认使用它。
- CRI-O:专门为K8s设计的轻量级运行时。
你想想看,容器运行时是直接和Linux内核打交道的。它负责创建cgroup、namespace,设置网络等。如果它出了问题,整个节点上的容器都会受影响。
避坑指南:我曾经遇到过节点磁盘写满,导致容器运行时无法拉取新镜像。排查后发现是容器日志没有轮转。从那以后,我养成了一个习惯:在每个节点上配置日志轮转,并且监控磁盘使用率。
3.3 Pod与工作负载资源
Pod是K8s中最小的调度单元。一个Pod可以包含一个或多个容器,这些容器共享网络和存储。
但实际工作中,我们很少直接创建Pod。我们用的是工作负载资源:
- Deployment:管理无状态应用,支持滚动更新和回滚。
- StatefulSet:管理有状态应用,每个Pod有唯一的网络标识和持久化存储。
- DaemonSet:在每个节点上运行一个Pod,比如日志收集器、监控Agent。
- Job/CronJob:运行一次性任务或定时任务。
我建议你记住一个原则:能用Deployment就别用裸Pod。Deployment提供了自愈、扩缩容、更新等能力,裸Pod挂了就真的挂了。
举个例子,一个典型的Deployment定义:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
这段代码的意思是:我要3个nginx Pod,每个Pod运行一个nginx容器,监听80端口。如果某个Pod挂了,Deployment Controller会自动创建一个新的。
嗯,这里要注意:Pod的IP是动态的,所以不要直接通过Pod IP访问。要用Service来暴露服务。
好了,K8s的核心架构就聊到这里。从Master到Worker,从API Server到Kubelet,每个组件各司其职。理解了这个架构,你就能明白为什么K8s能管理成千上万个容器了。