CRD 与 Operator 模式——扩展 Kubernetes 的标准路径
Kubernetes 的核心设计哲学之一是可扩展性。API Server 内置的资源类型——Pod、Deployment、Service——只能覆盖通用计算模型,但现实中的应用远不止于此:数据库集群有自己的主从切换逻辑,消息队列有 topic 副本的分配策略,机器学习训练任务有 GPU 亲和性和检查点管理。CustomResourceDefinition(CRD)和 Operator 模式正是 Kubernetes 给出的扩展机制:让用户把领域知识编码进集群本身,而不是写在外部脚本或运维手册里。 CRD 的核心能力是向 API Server 注册新的 Group/Version/Kind(GVK)。注册完成后,kubectl get myapp 和 kubectl get pod 在 API 层面对等——同样走 REST 接口,同样存储到 etcd,同样支持 watch、label selector 和 RBAC 授权。Operator 在 CRD 之上再加一层:部署一个 Controller,持续监听自定义资源的变化,把用户声明的期望状态翻译成若干内置 Kubernetes 资...
资源管理与自动伸缩:requests、limits、HPA 与 VPA
安全模型控制谁能做什么,资源管理控制能用多少。这两个维度共同决定了集群的多租户能力。requests 和 limits 是 Kubernetes 资源模型的基础,理解它们的精确语义是做好容量规划的前提。HPA 和 VPA 在此基础上提供了自动化的弹性能力。 在传统物理机和虚拟机时代,资源隔离靠硬件分区或 hypervisor,资源弹性靠人工扩容。Kubernetes 把资源管理内置为一等公民,通过 cgroup 在内核层面强制执行,通过控制器实现自动化弹性。这一篇的核心问题是:requests 和 limits 如何影响调度和运行时行为,HPA 和 VPA 如何根据负载自动伸缩? 资源模型全景 1234567891011121314151617181920212223242526调度时(kube-scheduler) ┌────────────────────────────────────────────────────────────┐ │ Node Allocatable = Node Capacity - System Reserved │ │ ─...
RBAC 与安全模型:认证、授权与准入控制
密钥只有在有效的访问控制下才有意义。Kubernetes 的安全控制分三层:认证(谁在访问)、授权(能做什么)、准入控制(允许什么操作)。三层各有职责,缺一不可。 在单体应用时代,安全通常集中在网络边界和数据库访问控制。容器化和微服务之后,工作负载数量激增,身份变得复杂:一个 Pod 就是一个独立的执行主体,可能需要读取 Secret、调用其他服务、操作集群资源。Kubernetes 的安全模型由哪三个层次组成、RBAC 的 Role/RoleBinding/ClusterRole/ClusterRoleBinding 如何组合使用,是本篇的核心内容。 三层安全模型 12345678910111213141516171819202122232425262728293031323334请求到达 API Server │ ▼┌──────────────────────────────────┐│ 1. Authentication(谁?) ││ ──────────────────────────── ││ X.509 cert → U...
配置与密钥管理:ConfigMap、Secret 与外部集成
存储体系解决了持久化数据问题。配置和密钥是另一类需要与 Pod 生命周期解耦的数据:应用配置(数据库地址、功能开关)和敏感信息(密码、API Key、TLS 证书)不应该打包到镜像里,因为不同环境配置不同,密钥也需要独立的访问控制。 十二因素应用(The Twelve-Factor App)把"配置"定义为在不同部署(开发、测试、生产)之间存在差异的东西,并要求配置必须与代码严格分离。Kubernetes 的 ConfigMap 和 Secret 是这个原则的原生实现。ConfigMap 和 Secret 如何把配置注入 Pod、外部密钥管理系统(Vault、AWS Secrets Manager)如何与 Kubernetes 集成,是本篇覆盖的内容。 配置注入全景 12345678910111213141516171819202122232425 ┌──────────────────────────────────────────┐ │ Kubernetes API ...
存储体系:PV、PVC、StorageClass 与 CSI
前几篇建立了计算(Pod 调度和运行)和网络(Pod 间通信和服务发现)的模型。有状态应用(数据库、消息队列、对象存储)需要持久化存储,Pod 重启后数据不丢失。Kubernetes 通过 PV/PVC/StorageClass 三层抽象解耦了存储的供应和使用。 在虚拟机时代,存储通常由运维工程师手动挂载:NFS 目录、SAN LUN、本地磁盘,挂载路径硬编码在部署脚本里。容器化之后,Pod 随时可能漂移到不同节点,存储和计算的生命周期必须显式解耦。Kubernetes 的回答是引入三个层次:PV(实际存储的抽象)、PVC(应用的存储需求声明)、StorageClass(动态供应的策略工厂)。PV/PVC 的绑定机制和 CSI 驱动如何让外部存储系统成为 K8s 的一等公民,是本篇的核心内容。 CSI(Container Storage Interface)的出现解决了 in-tree 驱动的历史包袱。此前,每个云厂商、每个存储系统都要向 Kubernetes 主代码库提交驱动代码,升级路径混乱且周期漫长。CSI 定义了一套 gRPC 接口,任何存储厂商都可以编写独立的驱动程序,...
架构总览:Broker、Controller 与元数据管理
上一篇确立了追加日志是 Kafka 的核心抽象。这一篇展开这根日志运行在什么样的集群架构上。 一个常见的简化说法是"Kafka 是一组 broker"。更准确的描述是:Kafka 集群由若干 broker 进程组成,其中一个 broker 承担 controller 角色,负责元数据管理和 partition leader 选举。 本文只抓一个问题:从 topic 到磁盘目录,数据和元数据分别如何组织。 Broker:存储日志并服务读写请求 Broker 是 Kafka 集群中的工作进程。每个 broker 做两件事: 存储分配给它的 partition 的日志文件(.log、.index、.timeindex)。 服务 produce 请求(追加记录到日志尾部)和 fetch 请求(按 offset 从日志中读取记录)。 一个 broker 可以同时持有多个 topic 的多个 partition。每个 partition 在磁盘上是一个独立的目录,目录名格式为 {topic名}-{partition号}。 1234567891011broker-0 ...
Ingress 与 Gateway API:七层流量的入口演进
Service 把集群内部的流量调度问题解决了,但把服务暴露到集群外部的 HTTP/HTTPS 流量需要另一层抽象。NodePort 和 LoadBalancer 都在四层工作——它们能把外部 TCP 流量转发进来,但无法根据 HTTP 的 Host 头或 URL 路径做路由决策,也无法终止 TLS、做 URL 重写、实现金丝雀发布。Ingress 就是 Kubernetes 为七层 HTTP 路由设计的原生对象,它在 1.1 版本进入 alpha,1.19 版本 GA,至今仍是绝大多数集群的 HTTP 入口方案。 Ingress 的设计在简单场景里非常直观:声明哪个 host + 哪个路径对应哪个 Service,TLS 证书放在 Secret 里引用,一个 Controller(Nginx、Traefik、HAProxy 等)负责把这些规则翻译成实际的反向代理配置。这套模型在业务不复杂时运作良好,但当需要金丝雀发布、基于请求头的路由、跨命名空间的服务暴露、gRPC 原生路由时,规范本身的表达能力不够,各家 Controller 用 annotation 扩展——结果是注解的命...
Service 与 kube-proxy:虚拟 IP、iptables 与 IPVS
Service 的 ClusterIP 是一个不存在于任何网卡的虚拟 IP。在节点上运行 ip addr,看不到它;用 ping 测试,收不到回应;但对它发起 TCP 连接,数据却能稳定到达某个后端 Pod。这个"幽灵 IP"能够工作,完全依赖 kube-proxy 写入每个节点内核的 iptables 或 IPVS 规则——规则在,转发在;规则消失,连接消失。 理解这一机制的起点是区分两种截然不同的角色:kube-proxy 是"规则维护者",内核的 netfilter/IPVS 子系统才是"数据面执行者"。kube-proxy 进程本身从不处理任何用户请求,它只监听 kube-apiserver 上 Service 和 EndpointSlice 的变化,把这些变化翻译成内核规则,然后等待下一次变化。真正处理数据包的是内核——每个到达某 ClusterIP:port 的数据包,在经过 iptables nat 表的 PREROUTING 链时,被 DNAT 规则改写目标地址,转向某个真实的 Pod IP:port,整...
网络模型与 CNI:每个 Pod 一个 IP 背后的实现
Kubernetes 对网络做出了一个看似简单的承诺:每个 Pod 拥有一个集群范围内唯一的可路由 IP,Pod 之间无需 NAT 可直接通信,节点访问 Pod 也无需 NAT。三条规则,没有一条涉及实现细节。这种"定义行为、不定义机制"的风格与 Kubernetes 整体的设计哲学一致,但也意味着没有任何一行核心代码实现了这个承诺——它完全由 CNI 插件负责兑现。 理解 CNI 的切入点不是插件本身,而是 Linux 网络命名空间带来的问题。每个容器拥有独立的网络栈,包含独立的路由表、ARP 缓存、iptables 规则集。新建的命名空间里只有一个回环接口 lo,对外完全不可达——这正是容器隔离的本意。CNI 插件的全部工作就是在这种隔离性上凿出一条通道:创建 veth pair,把一端移入 Pod 命名空间,另一端挂到宿主机网桥,配置 IP 地址和路由,让 Pod 从完全隔离的孤岛变成集群网络里的一个节点。 跨节点通信是第二层复杂性。同节点内的 Pod 通过共享网桥即可互通,但当数据包需要离开宿主机的物理网卡,穿越真实的交换机和路由器,抵达另一台节点,再...
kubelet 与容器运行时:节点上到底发生了什么
前两篇讲了调度(选节点)和 Pod 生命周期(状态机)。这一篇下到节点层:kubelet 在节点上把一个 Pod spec 变成真实运行的进程。 容器运行时曾经等于 Docker。Kubernetes 1.24 移除了 dockershim,此后所有节点必须使用实现了 CRI(Container Runtime Interface)的运行时:containerd、CRI-O 或其他。这次迁移对用户基本无感,但原理上有重要变化——kubelet 和运行时之间的通信从内嵌的特定实现变成了标准 gRPC 接口。 本文只问一个问题:从 pod.spec.nodeName 被写入,到容器进程在节点上跑起来,发生了什么? 节点内部全景图 123456789101112131415161718192021222324API Server → etcd (Pod.spec.nodeName = this-node) │ ▼kubelet (watches own node's Pods via Informer)┌───────────────────────────...
