Kubernetes 核心概念
从 Docker 到 Kubernetes 的演进
Docker 的出现彻底改变了应用程序的打包和部署方式。通过容器化技术,开发人员能够将应用程序及其依赖项打包到一个轻量级的、可移植的容器中,确保了"一次构建,到处运行"的一致性体验。然而,随着容器化应用的规模扩大,单机容器管理的局限性逐渐显现。
在单机环境中,Docker 提供了容器生命周期管理、资源隔离、网络配置等基础功能。但当应用规模扩展到多台服务器时,运维团队面临诸多挑战:跨主机的容器调度、服务发现、负载均衡、故障自愈、滚动升级、资源配额等问题变得日益复杂。手工管理几十甚至上百个容器不仅效率低下,而且容易出错。
容器编排平台应运而生。Kubernetes(K8s)作为容器编排领域的领导者,提供了一个完整的平台,用于自动化部署、扩展和管理容器化应用。它解决了多机环境下的核心问题:自动化调度、服务发现、负载均衡、存储编排、自动扩缩容、滚动更新和回滚、自我修复等。Kubernetes 不仅是一个编排工具,更是一个云原生应用的基础设施平台。
Kubernetes 架构
Kubernetes 采用主从架构,由控制平面和工作节点组成。
控制平面
控制平面负责集群的决策和全局管理,包含以下核心组件:
API Server 是整个系统的统一入口,提供 RESTful API 接口。所有内部组件、用户和外部系统都通过 API Server 与集群交互。它负责认证、授权、准入控制,并将请求持久化到 etcd。
etcd 是一个高可用的键值存储,用于存储集群的所有配置数据和状态信息。它是 Kubernetes 的唯一事实来源,确保了集群状态的一致性和可靠性。etcd 采用 Raft 共识算法,保证了分布式环境下的一致性和可用性。
Scheduler 负责将新创建的 Pod 调度到合适的工作节点上。调度决策基于资源需求、硬件约束、亲和性和反亲和性规则、数据局部性、工作负载干扰等多种因素。调度器通过 watch API 监听未调度的 Pod,并为其选择最优节点。
Controller Manager 运行多个控制器进程,每个控制器负责维护特定资源的期望状态。包括节点控制器、副本控制器、端点控制器、服务账户和令牌控制器等。控制器通过 API Server 监听资源变化,并不断调整实际状态以匹配期望状态。
工作节点
工作节点负责运行容器化应用,包含以下组件:
kubelet 是工作节点上的代理,负责与控制平面通信。它接收并执行来自 API Server 的指令,管理节点上的 Pod 生命周期,定期向控制平面报告节点和 Pod 的状态。kubelet 还负责挂载卷、下载镜像、运行容器等操作。
kube-proxy 是网络代理,负责维护节点上的网络规则。它实现了 Service 的负载均衡和服务发现功能,通过 iptables 或 IPVS 规则将流量转发到正确的 Pod。kube-proxy 监听 Service 和 Endpoints 的变化,实时更新网络规则。
Container Runtime 负责运行容器。Kubernetes 支持多种容器运行时,包括 Docker、containerd、CRI-O 等。容器运行时通过容器运行时接口(CRI)与 kubelet 交互,负责拉取镜像、创建和启动容器、监控容器状态等。
核心资源对象
Pod
Pod 是 Kubernetes 中最小的可部署单元,也是最小的调度单元。一个 Pod 可以包含一个或多个紧密协作的容器,这些容器共享网络命名空间、存储卷和生命周期。Pod 内的容器可以通过 localhost 相互通信,共享存储卷中的数据。
Pod 的设计理念是支持多容器协同工作模式,其中最典型的是 sidecar 模式。主容器负责核心业务逻辑,sidecar 容器负责辅助功能,如日志收集、监控代理、代理转发等。这种模式实现了关注点分离,提高了系统的模块化和可维护性。
Pod 是临时的、可替换的。当 Pod 所在节点故障或 Pod 本身出现问题时,控制器会创建新的 Pod 替换它。Pod 的 IP 地址是动态分配的,因此不应该直接依赖 Pod IP 进行服务发现。
Deployment
Deployment 是用于管理无状态应用的工作负载资源。它提供了声明式的更新方式,允许用户定义应用的期望状态,由控制器负责维护实际状态与期望状态的一致性。
Deployment 支持 Pod 的副本管理,确保指定数量的 Pod 副本始终运行。当 Pod 故障或节点失效时,Deployment 控制器会自动创建新的 Pod 替换失效的 Pod。
Deployment 支持滚动更新和回滚。当更新应用镜像或配置时,Deployment 会逐步替换旧版本的 Pod,确保在整个更新过程中始终有足够数量的 Pod 可用。如果更新失败或发现问题,可以轻松回滚到之前的版本。
Service
Service 定义了一种访问一组 Pod 的策略,解决了 Pod 动态 IP 带来的服务发现问题。Service 为一组功能相同的 Pod 提供一个固定的访问入口,通过标签选择器来确定要代理的 Pod 集合。
Service 支持多种类型:
ClusterIP 是默认类型,为服务分配一个集群内部的虚拟 IP 地址,只能在集群内部访问。这是最常用的服务类型,用于集群内部的服务间通信。
NodePort 在每个节点上开放一个端口,将外部流量转发到 Service。通过 <NodeIP>:<NodePort> 可以从集群外部访问服务。NodePort 是 ClusterIP 的超集,会自动创建一个 ClusterIP。
LoadBalancer 在 NodePort 的基础上,向云服务商申请一个负载均衡器,将外部流量分发到各个节点的 NodePort。LoadBalancer 适用于需要对外暴露服务的场景。
Service 通过 kube-proxy 实现负载均衡,默认采用轮询算法。Service 的 Endpoints 会被自动维护,当 Pod 健康状态变化时,Endpoints 列表会相应更新。
Ingress
Ingress 是一个 API 对象,用于管理集群外部访问服务的规则,特别是 HTTP 和 HTTPS 协议的七层路由。Ingress 充当集群的入口点,根据请求的主机名、路径等规则将流量路由到不同的 Service。
Ingress 支持基于主机名的虚拟主机,可以在同一个 IP 地址上托管多个域名。支持基于路径的路由,根据 URL 路径将请求分发到不同的后端服务。支持 TLS 终止,可以在 Ingress 层面处理 SSL/TLS 加密解密,减轻后端服务的负担。
Ingress 需要配合 Ingress Controller 使用,常见的 Ingress Controller 包括 Nginx Ingress Controller、Traefik、HAProxy Ingress 等。
ConfigMap 和 Secret
ConfigMap 用于存储非敏感的配置数据,以键值对的形式组织。ConfigMap 可以作为环境变量、命令行参数或配置文件挂载到 Pod 中。ConfigMap 的设计实现了配置与镜像的解耦,使得同一个镜像可以通过不同的 ConfigMap 在不同环境下运行。
Secret 类似于 ConfigMap,用于存储敏感信息,如密码、OAuth 令牌、SSH 密钥等。Secret 数据在存储和传输时会进行 Base64 编码,在使用时可以挂载为文件或环境变量。需要注意的是,Secret 的 Base64 编码并不是加密,在生产环境中应该结合 RBAC 和加密机制使用。
ConfigMap 和 Secret 支持热更新,当配置内容变化时,挂载的文件会自动更新。但环境变量形式的 ConfigMap 不会自动更新,需要重启 Pod 才能生效。
PersistentVolume 和 PersistentVolumeClaim
PersistentVolume(PV)是集群中的一块存储,由管理员预先配置或通过存储类动态创建。PV 是集群级别的资源,独立于 Pod 的生命周期存在。PV 支持多种存储类型,包括 NFS、iSCSI、Ceph、云存储(AWS EBS、GCE PD、Azure Disk)等。
PersistentVolumeClaim(PVC)是用户对存储的请求,类似于 Pod 对计算资源的请求。PVC 声明了所需的存储容量、访问模式(ReadWriteOnce、ReadOnlyMany、ReadWriteMany)等需求。PVC 会与合适的 PV 进行绑定,或者通过存储类动态创建新的 PV。
PV 和 PVC 的设计实现了存储的供应与使用的解耦。开发人员通过 PVC 申请存储,不需要关心底层存储的具体实现。管理员可以灵活配置不同类型的 PV,满足不同应用的存储需求。
Namespace
Namespace 提供了在一个物理集群中创建多个虚拟集群的能力,实现了资源隔离和配额管理。通过 Namespace,可以将集群资源划分为多个逻辑组,不同的团队或项目可以在各自的 Namespace 中工作,避免资源冲突。
Namespace 提供了作用域隔离,资源名称在同一个 Namespace 内必须唯一,但在不同 Namespace 中可以重复。Namespace 还支持资源配额和限制范围,可以限制 Namespace 中的资源使用量,防止单个 Namespace 占用过多资源。
Kubernetes 集群默认创建了几个 Namespace:default 用于没有指定 Namespace 的资源,kube-system 用于 Kubernetes 系统组件,kube-public 用于公共资源。
声明式 API 与控制器模式
Kubernetes 采用声明式 API 设计,这是其架构的核心特点之一。声明式 API 要求用户描述期望的状态,而不是描述如何达到该状态。例如,用户声明需要运行 3 个 Nginx 副本,而不是描述如何创建、启动和监控这 3 个副本。
控制器模式是实现声明式 API 的关键机制。控制器不断监控集群的实际状态,并将其与用户声明的期望状态进行比较。如果两者不一致,控制器会采取行动使实际状态向期望状态收敛。这个过程称为 Reconciliation Loop(协调循环)。
Reconciliation Loop 的工作流程如下:控制器通过 API Server 监听资源的变化事件,包括创建、更新、删除操作。当检测到变化时,控制器获取当前的期望状态和实际状态。如果两者不一致,控制器执行相应的操作,如创建、删除、更新资源,使实际状态逐步接近期望状态。
声明式 API 和控制器模式带来了诸多优势:自动化的自我修复能力,当实际状态偏离期望状态时自动纠正;更好的可扩展性,控制器可以并行处理多个资源;简化的操作模型,用户只需要声明期望状态,不需要关心实现细节;最终一致性,系统保证最终达到期望状态,但不保证中间过程。
网络模型
Kubernetes 的网络模型遵循扁平化网络原则,具有以下核心特性:每个 Pod 都拥有一个独立的 IP 地址,Pod 之间可以直接通信,无需 NAT(网络地址转换)。所有节点都可以与所有 Pod 通信,无需 NAT。Pod 看到的自己的 IP 地址与其他 Pod 看到的它的 IP 地址相同。
这种网络模型简化了应用的开发和部署。应用不需要因为容器化而进行特殊的网络适配,可以像在传统网络环境中一样工作。服务发现和负载均衡也变得简单,因为每个 Pod 都有独立的 IP 地址。
Kubernetes 通过 CNI(Container Network Interface)插件实现网络模型。CNI 定义了一套标准接口,允许不同的网络插件与 Kubernetes 集成。常见的 CNI 插件包括 Calico、Flannel、Weave Net、Cilium 等。
这些插件采用不同的网络实现方式:Flannel 使用 VXLAN 或 UDP 封装,简单易用;Calico 基于 BGP 协议,支持网络策略;Weave Net 创建覆盖网络,自动发现节点;Cilium 基于 eBPF,提供高性能和网络策略支持。
Kubernetes 的网络模型还支持网络策略(Network Policy),用于控制 Pod 之间的网络流量。网络策略可以基于标签选择器定义允许或拒绝的流量规则,实现微隔离和安全域划分。
调度策略
Kubernetes 的调度器负责将 Pod 分配到合适的工作节点上,调度决策基于多种策略和约束。
nodeSelector 是最简单的调度约束,通过标签选择器指定 Pod 只能调度到具有特定标签的节点上。例如,可以指定 Pod 只调度到 SSD 磁盘的节点上。nodeSelector 提供了基本的节点选择能力,但灵活性有限。
亲和性和反亲和性 提供了更细粒度的调度控制。节点亲和性(Node Affinity)分为 required(硬性要求)和 preferred(软性偏好)两种。required 节点亲和性类似于 nodeSelector,但支持更复杂的匹配规则;preferred 节点亲和性在满足条件时优先调度,但不强制要求。
Pod 亲和性和反亲和性(Pod Affinity/Anti-Affinity)基于 Pod 的标签进行调度决策。Pod 亲和性用于将相关的 Pod 调度到同一个节点或拓扑域中,以减少网络延迟和提升性能。Pod 反亲和性用于将互斥的 Pod 分散到不同的节点或拓扑域中,以提高可用性和容错能力。
污点和容忍度 提供了一种灵活的节点调度控制机制。污点(Taint)应用于节点,表示该节点具有特殊属性或限制。容忍度(Taint Toleration)应用于 Pod,表示 Pod 可以容忍具有特定污点的节点。
污点有三个效果:NoSchedule 表示除非 Pod 具有对应的容忍度,否则不会调度到该节点;PreferNoSchedule 表示尽量不调度到该节点,但在资源紧张时可以调度;NoExecute 表示不仅阻止新 Pod 调度,还会驱逐没有容忍度的现有 Pod。
污点和容忍度常用于以下场景:专用节点,为特定用途的节点添加污点,防止普通 Pod 调度;具有特殊硬件的节点,如 GPU 节点;节点维护,在维护前添加 NoExecute 污点,驱逐所有 Pod;节点故障检测,自动为故障节点添加污点。
调度器还支持优先级和抢占机制。高优先级的 Pod 可以抢占低优先级 Pod 的资源,确保关键应用能够及时运行。这为多租户环境下的资源分配提供了更好的保障。
总结
Kubernetes 作为云原生应用的核心平台,通过声明式 API、控制器模式、丰富的资源对象和灵活的调度策略,为容器化应用提供了完整的运行时环境。从单机容器管理到集群编排的演进,反映了分布式系统发展的必然趋势。掌握 Kubernetes 的核心概念,是构建现代化、可扩展、高可用应用的基础。

