【Kubernetes】—— K8s核心原理一文吃透从架构到调度的完整拆解你可能听过 Kubernetes 很多次知道它能编排容器但真要说清楚它内部怎么运作的、为什么要这么设计、各个组件之间怎么配合——这些才是你真正需要理解的东西。这篇文章不讲怎么装 K8s那是下一篇的事而是把它的核心原理拆开来讲透。一句话看完这篇你能画出 K8s 的架构图讲清楚每个组件的职责理解 Pod、Service、Deployment 这些核心对象背后的设计逻辑。一、先搞明白K8s 到底在解决什么问题假设你有 10 个微服务每个服务跑 3 个副本总共 30 个容器。用 Docker 跑起来没问题但接下来你要面对一连串头疼的事容器挂了谁来重启要扩容怎么把新容器均匀分到几台机器上服务 A 要访问服务 BB 的 IP 一直在变怎么处理滚动更新的时候怎么保证不丢请求某台机器宕机了上面的容器怎么迁移这些问题Docker Compose 解决不了它只管单机手动运维又太累。Kubernetes 就是来干这件事的在集群层面自动化地管理容器的生命周期、网络、存储、调度。说直白点Docker 管一个容器K8s 管一群容器。你手动要做的事K8s 帮你做的事容器挂了手动重启自动检测并重启自愈手动 SSH 到机器上部署声明式配置一条命令部署到集群手动分配容器到哪台机器调度器自动选择最优节点手动配负载均衡Service 自动分发流量手动做滚动更新Deployment 自动渐进式替换二、架构全景K8s 集群长什么样一个 K8s 集群由两类节点组成Control Plane控制平面和Worker Node工作节点。控制平面是大脑工作节点是手脚。┌─────────────────────────────────────────────────────┐ │ Control Plane │ │ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────┐ │ │ │ API Server│ │ Scheduler │ │Controller│ │ etcd │ │ │ │ │ │ │ │ Manager │ │ │ │ │ └─────┬─────┘ └─────┬─────┘ └────┬─────┘ └──┬───┘ │ │ └──────────────┴────────────┴──────────┘ │ └─────────────────────────┬───────────────────────────┘ │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ ┌─────────────┐┌─────────────┐┌─────────────┐ │ Worker Node ││ Worker Node ││ Worker Node │ │ ┌─────────┐ ││ ┌─────────┐ ││ ┌─────────┐ │ │ │ kubelet │ ││ │ kubelet │ ││ │ kubelet │ │ │ └─────────┘ ││ └─────────┘ ││ └─────────┘ │ │ ┌─────────┐ ││ ┌─────────┐ ││ ┌─────────┐ │ │ │kube-proxy│ ││ │kube-proxy│ ││ │kube-proxy│ │ │ └─────────┘ ││ └─────────┘ ││ └─────────┘ │ │ ┌───┐ ┌───┐ ││ ┌───┐ ┌───┐ ││ ┌───┐ ┌───┐ │ │ │Pod│ │Pod│ ││ │Pod│ │Pod│ ││ │Pod│ │Pod│ │ │ └───┘ └───┘ ││ └───┘ └───┘ ││ └───┘ └───┘ │ └─────────────┘└─────────────┘└─────────────┘Control Plane 四大组件API Server——集群的总前台。所有操作kubectl 命令、控制器的协调、kubelet 的上报都必须经过它。它对外暴露 RESTful API内部负责认证、授权、准入控制。你可以把它理解为集群的唯一入口。etcd——集群的数据库。所有集群状态节点信息、Pod 配置、Service 映射都存在这里。它是一个分布式 KV 存储用 Raft 协议保证一致性。K8s 集群挂了90% 的情况先查 etcd。Scheduler——集群的调度员。当一个新 Pod 需要创建时Scheduler 根据资源需求、亲和性、污点容忍等规则决定这个 Pod 跑在哪台 Node 上。它不做实际部署只做决策然后把结果写回 API Server。Controller Manager——集群的管家团。里面跑着一堆控制器Deployment Controller、Node Controller、Service Controller 等每个控制器负责一种资源的期望状态 → 实际状态的持续对齐。比如 Deployment Controller 发现副本数少了就会创建新 Pod。Worker Node 三大件kubelet——节点上的代理人。它跟 API Server 保持通信接收 Pod 的调度指令调用容器运行时如 containerd来创建和管理容器同时上报节点和 Pod 的状态。kube-proxy——节点上的网络管家。它维护节点上的网络规则iptables 或 IPVS确保 Service 的流量能正确转发到后端 Pod。没有它Service 就是个空壳。容器运行时——真正跑容器的地方。早期是 Docker现在主流是 containerd 或 CRI-O。kubelet 通过 CRIContainer Runtime Interface跟它交互。本章小结组件所在位置一句话职责API ServerControl Plane所有操作的唯一入口etcdControl Plane存储集群全部状态SchedulerControl Plane决定 Pod 跑在哪台机器Controller ManagerControl Plane持续对齐期望状态与实际状态kubeletWorker Node执行 Pod 生命周期管理kube-proxyWorker Node维护 Service 网络转发规则三、核心对象拆解Pod / Service / Deployment这三个是 K8s 里出场率最高的对象。搞懂它们你就搞懂了 K8s 80% 的日常操作。3.1 Pod最小调度单元Pod 不是容器它是一组容器的包装盒。一个 Pod 里的容器共享网络命名空间互相可以用 localhost 访问和存储卷。为什么要有 Pod因为有些场景下两个容器必须住在一起。比如一个 Web 服务 一个日志收集 Sidecar它们需要共享同一个网络栈。Pod 就是 K8s 对这种亲密关系的抽象。 重点Pod 是临时品。它随时可能被销毁重建IP 地址也会变。所以永远不要直接访问一个 Pod 的 IP——这就是 Service 存在的意义。一个最小的 Pod 定义apiVersion:v1kind:Podmetadata:name:my-applabels:app:my-appspec:containers:-name:my-appimage:nginx:1.25ports:-containerPort:80但实际项目中你几乎不会直接创建 Pod。你会通过 Deployment 来管理它。3.2 DeploymentPod 的管家Deployment 解决的是我需要 3 个一样的 Pod 持续运行这个问题。它声明你想要多少个副本然后由 Deployment Controller 持续保证实际数量和期望一致。你我要 3 个 nginx Pod Deployment Controller收到我盯着。少了一个我就补多了一个我就删。Deployment 还管滚动更新。当你改了镜像版本它会按策略逐步替换旧 Pod而不是一刀切全部停掉。这就是生产环境能做到零停机发布的基础。apiVersion:apps/v1kind:Deploymentmetadata:name:my-appspec:replicas:3# 期望 3 个副本selector:matchLabels:app:my-appstrategy:type:RollingUpdaterollingUpdate:maxSurge:1# 最多多出 1 个 PodmaxUnavailable:0# 最多允许 0 个不可用template:metadata:labels:app:my-appspec:containers:-name:my-appimage:nginx:1.25ports:-containerPort:80resources:requests:cpu:100mmemory:128Milimits:cpu:250mmemory:256Mi⚠️ 注意resources字段不是可选的装饰。不写 requestsScheduler 就无法合理分配资源不写 limits一个失控的容器可能把整台节点的内存吃光。生产环境必须写。3.3 Service稳定的访问入口Pod 的 IP 会变Service 给你一个固定的虚拟 IPClusterIP和 DNS 名字。不管你后端 Pod 怎么漂移、怎么替换访问 Service 的地址始终不变。apiVersion:v1kind:Servicemetadata:name:my-servicespec:selector:app:my-app# 匹配标签为 appmy-app 的 Podports:-protocol:TCPport:80# Service 暴露的端口targetPort:80# 转发到 Pod 的端口Service 有几种类型用得最多的是这三种类型使用场景特点ClusterIP默认集群内部互访只能在集群内访问NodePort开发测试、简单暴露在每个节点上开一个端口LoadBalancer生产环境对外暴露需要云厂商支持AWS ALB 等坑就坑在这里很多人以为 Service 是负载均衡器其实它只是一组 iptables/IPVS 规则。真正的流量转发是 kube-proxy 在每个节点上做的。Service 的 ClusterIP 甚至不是一个真实存在的网络接口——它是个虚 IP靠 DNAT 规则把流量转到后端 Pod。四、Pod 的一生从声明到运行理解一个 Pod 从创建到运行的完整链路你就能理解 K8s 各组件是怎么协作的。你执行 kubectl apply │ ▼ API Server 收到请求校验后写入 etcd │ ▼ Deployment Controller 检测到副本数不足 │ ▼ 创建 Pod 对象此时 Pod 处于 Pending 状态 │ ▼ Scheduler 发现未调度的 Pod │ ▼ 根据资源、亲和性、污点等规则选择 Node │ ▼ 把调度结果写回 Pod 的 spec.nodeName 字段 │ ▼ 目标 Node 的 kubelet 检测到分配给自己的 Pod │ ▼ kubelet 调用 containerd 拉镜像、创建容器 │ ▼ 容器启动Pod 状态变为 Running │ ▼ kubelet 持续上报 Pod 状态给 API Server重点这条链路上任何一环出问题Pod 都会卡在某个状态。排查问题的时候沿着这条链路往下查基本都能定位到原因。常见卡住的状态Pending最常见的原因是资源不足CPU/Memory 不够或者没有满足条件的 Node污点、亲和性。用kubectl describe pod name看 Events。ImagePullBackOff镜像拉不下来。检查镜像名是否正确、仓库是否需要认证、网络是否通畅。CrashLoopBackOff容器启动后立刻退出。用kubectl logs pod-name看容器日志。五、调度机制Pod 是怎么选 Node 的Scheduler 不是随机分配的它有两步过滤Filtering和打分Scoring。过滤阶段把不满足条件的 Node 删掉。比如 Pod 需要 2 核 CPU只有 1 核的 Node 直接出局Pod 有 nodeSelector 要求不匹配的 Node 直接出局。打分阶段在剩下的 Node 里按策略打分选得分最高的。默认策略会优先选资源利用率较低的 Node避免把所有 Pod 都堆在同一台机器上。几个影响调度的关键机制机制作用使用场景nodeSelector按标签选择 Node“这个 Pod 必须跑在 SSD 机器上”nodeAffinity更灵活的 Node 选择“优先选 zone-a实在没有就选 zone-b”Pod Affinity跟其他 Pod 亲近或远离“Web 和缓存放同一台机器”Taints TolerationsNode 拒绝某些 Pod“这台机器是 GPU 专用普通 Pod 不要来”Resource Requests声明 Pod 需要多少资源Scheduler 据此判断 Node 是否够用⚠️ 注意如果你设了 requests 但不设 limitsPod 可以超卖使用资源极端情况下会触发 OOMKilled。如果你设了 limits 但不设 requestsPod 默认 requests limits等于完全不超卖。根据业务特性选择合适的策略。六、网络模型K8s 的网络怎么通的K8s 的网络模型有三条基本原则这是官方硬性要求所有 Pod 可以不经过 NAT 直接互相访问所有 Node 可以不经过 NAT 直接访问所有 PodPod 看到的自己的 IP 和别人看到的它的 IP 一样为了实现这三条需要一个CNIContainer Network Interface插件。常见的有插件特点适用场景Calico支持 NetworkPolicy性能好生产环境首选Flannel简单轻量小集群、学习环境Cilium基于 eBPF性能极强大规模集群、需要高级网络策略实际用下来Calico 的稳定性最好Cilium 的性能最猛但学习曲线陡。如果你是入门阶段Flannel 够用上生产直接选 Calico。Pod 网络解决的是Pod 之间怎么通信。Service 网络解决的是怎么用固定地址访问一组 Pod。两者配合构成了 K8s 完整的网络体系。七、声明式管理K8s 的核心哲学这是理解 K8s 最重要的一点很多人忽略了。K8s 采用声明式Declarative管理而不是命令式Imperative。区别在哪命令式“创建 3 个 Pod然后把第一个的镜像改成 v2然后删掉第三个……”——你在告诉系统怎么做。声明式“我要 3 个 nginx v2 Pod资源限制是这样网络配置是这样。”——你只告诉系统要什么系统自己想办法达到。这就是为什么 K8s 里一切都是 YAML。你写好 YAML 描述期望状态apply 一下K8s 自动计算当前状态和期望状态的差异然后执行必要的操作。这个理念贯穿了整个 K8s 设计Deployment声明我要 3 个副本Controller 负责对齐Service声明我要把流量分发到这些 Podkube-proxy 负责配规则HPA声明CPU 超过 80% 就扩容HPA Controller 负责调整副本数说白了你写的是目标K8s 是执行者。你不需要关心具体怎么达到目标只需要定义目标本身。这就是 K8s 最大的设计优势。八、常见误区这些坑你大概率会踩误区一Pod 就是容器Pod 是容器的包装盒不是容器本身。一个 Pod 里可以有多个容器主容器 Sidecar。Pod 拥有独立的网络命名空间和存储卷容器共享这些资源。误区二Service 是负载均衡器Service 只是一组转发规则的声明。真正的流量转发由 kube-proxy 在每个节点上通过 iptables/IPVS 规则实现。如果你需要七层负载均衡HTTP 路由、限流等得用 Ingress 或 Gateway API。误区三kubectl apply 就是部署apply 只是把 YAML 提交给 API Server。真正的部署发生在后面的一系列控制器协调过程中。apply 之后立刻 get pods 看不到东西是正常的——给 Scheduler 和 kubelet 一点时间。误区四namespace 是硬隔离namespace 只是逻辑隔离不是网络隔离。不同 namespace 的 Pod 默认可以互相访问。要实现网络隔离必须配 NetworkPolicy需要 CNI 插件支持。误区五K8s 能自动处理所有故障K8s 能处理的是进程级别的故障Pod 挂了、容器 OOM 了。但它处理不了应用级别的故障你的代码有 Bug、数据库连接超时。健康检查livenessProbe 和 readinessProbe能帮你覆盖一部分但不是万能的。九、小结你真正需要记住的 7 件事Control Plane 是大脑API Server 是入口etcd 是数据库Scheduler 管调度Controller Manager 管对齐。Worker Node 是手脚kubelet 执行kube-proxy 管网络。Pod 是最小调度单元不是容器是容器的包装盒。Pod 是临时的IP 会变。Deployment 管副本和更新声明式地管理 Pod 的数量和版本支持滚动更新。Service 提供稳定入口给一组 Pod 一个固定地址后端变了前端不变。调度是过滤 打分先排除不满足条件的 Node再选最优的。网络靠 CNI 插件K8s 只定义网络模型具体实现由插件完成。声明式是核心哲学告诉 K8s “要什么”不要告诉它 “怎么做”。参考资源Kubernetes 官方文档 - 概念Kubernetes 官方文档 - 教程kubectl 官方文档