Skip to main content

One post tagged with "container-orchestration"

View all tags

Kubernetes 全景解析 (0):架构设计与核心概念

· 20 min read
Rainy
雨落无声,代码成诗 —— 致力于技术与艺术的极致平衡

"如果你觉得 Kubernetes 太复杂,那是因为它解决的问题本身就很复杂。"

在云原生(Cloud Native)的世界里,Kubernetes(简称 K8s)已经从"可选技能"变成了"基础设施常识"。无论你是后端工程师、DevOps 工程师,还是架构师,理解 K8s 的设计思想和运行机制,都是构建现代分布式系统的必修课。

然而,K8s 的学习曲线之陡峭也是出了名的。官方文档动辄数千页,概念繁多且相互关联,很容易让人陷入"见树木不见森林"的困境。

本系列文章将从架构设计出发,逐层深入到核心概念、工作负载管理、网络模型、存储体系、调度策略与安全机制,帮助你构建一套完整、系统的 K8s 认知框架。本文作为系列的第零章,将聚焦于最根本的问题:Kubernetes 是什么?它是如何设计的?它由哪些核心部分组成?


一、为什么需要 Kubernetes

1.1 容器化演进的必然之路

要理解 K8s 存在的意义,我们需要先回顾应用部署方式的演进历程:

阶段部署方式隔离性资源利用率启动速度运维复杂度
物理机时代应用直接部署在物理服务器上-
虚拟机时代Hypervisor 划分多个 VM分钟级
容器时代Docker 等容器引擎秒级
编排时代Kubernetes 等编排系统秒级低(自动化)

物理机时代,一个应用独占一台服务器,资源浪费严重。为了提高利用率,我们开始在同一个物理机上部署多个应用,但随之而来的是依赖冲突、端口争抢、一个应用崩溃拖垮整台机器等问题。

虚拟机时代,Hypervisor(如 VMware、KVM)在物理机上虚拟出多个独立的操作系统实例,实现了良好的隔离。但虚拟机本身就很重——一个 VM 动辄几个 GB,启动需要数分钟,而且携带了完整的 Guest OS,大量资源被浪费在运行重复的系统服务上。

容器时代,Docker 横空出世。容器共享宿主机的内核,不需要 Guest OS,一个镜像通常只有几十 MB,启动只需毫秒级。容器通过 Namespace 实现视图隔离,通过 Cgroups 实现资源限制,在轻量和隔离之间找到了一个绝佳的平衡点。

但容器解决的是**"如何打包和运行应用"的问题,却没有解决"如何管理成百上千个容器"**的问题。当你的应用从 3 个容器扩展到 3000 个,跨越几十台机器时,以下问题接踵而至:

  • 哪个容器应该运行在哪台机器上?
  • 容器挂了谁来重启?机器挂了谁来迁移?
  • 如何实现滚动更新而不中断服务?
  • 如何让前端服务发现后端服务的地址?
  • 如何让外部流量均匀地分发到多个实例?

这就是 Kubernetes 登场的时刻。

1.2 K8s 解决的核心问题

Kubernetes 作为一个容器编排平台(Container Orchestration Platform),本质上解决的是一个大规模自动化管理的问题。它将运维人员从手工操作中解放出来,通过声明式配置和自动化控制循环,实现了:

  • 自动部署与回滚:声明期望状态,K8s 负责将实际状态趋近期望状态
  • 服务发现与负载均衡:内置 DNS 和 Service 机制,无需外部注册中心
  • 自动扩缩容:根据 CPU/内存/自定义指标自动调整实例数量
  • 自我修复:容器崩溃自动重启,节点故障自动迁移
  • 滚动更新与蓝绿部署:零停机更新应用

1.3 K8s 的设计哲学

理解 K8s 的设计哲学,比记住一百个命令更有价值。K8s 的三个核心设计理念贯穿了它的每一个组件:

声明式(Declarative)而非命令式(Imperative)

命令式 vs 声明式
  • 命令式:你告诉系统"做什么"——docker run nginxkubectl scale deployment nginx --replicas=3
  • 声明式:你告诉系统"你要什么"——提交一个 YAML 文件描述"我需要 3 个 Nginx 实例",K8s 会持续工作直到实际状态与期望状态一致

声明式的好处是:可重复、可审计、可版本化。同一个 YAML 文件,无论执行多少次,结果都是一致的。

不可变基础设施(Immutable Infrastructure)

K8s 中的容器镜像一旦构建就不应该被修改。需要更新时,你应该构建新镜像、创建新版本,而不是 SSH 进容器里改配置。这与传统"登录服务器打补丁"的运维方式截然不同。

最终一致性(Eventual Consistency)

K8s 不保证你的请求立即生效,但保证系统最终会收敛到期望状态。这种设计牺牲了即时性,换取了极高的可靠性和容错能力。即使你同时提交了多个冲突的变更,系统也能通过控制循环最终达到一个一致的状态。


二、K8s 整体架构

Kubernetes 采用经典的主从架构(Master-Worker Architecture),分为**控制面(Control Plane)数据面(Data Plane)**两个层级。理解这两个层面的职责划分,是理解 K8s 一切行为的基础。

2.1 架构全景图

2.2 控制面组件详解

控制面是 K8s 集群的"大脑",负责全局决策和集群状态的维护。在生产环境中,为了保证高可用,控制面组件通常部署在多个独立的 Master 节点上。

kube-apiserver:集群的统一入口

kube-apiserver 是整个 K8s 系统的唯一入口。所有组件——无论是内部的 Scheduler、Controller,还是外部的 kubectl、CI/CD Pipeline——都通过 API Server 进行通信。

为什么所有通信都要经过 API Server?

这种设计被称为 "Hub-and-Spoke" 模式。它的好处是:

  1. 统一鉴权:所有请求都在一个地方进行认证(Authentication)、授权(Authorization)和准入控制(Admission Control)
  2. 解耦:各组件不需要知道彼此的存在,只需要与 API Server 交互
  3. 审计:所有操作都有统一的日志记录

API Server 本身是无状态的,它可以水平扩展。所有的状态数据都存储在 etcd 中。

etcd:集群的"真相之源"

etcd 是一个分布式的、一致的键值存储系统,基于 Raft 共识算法实现。它是 K8s 集群的唯一数据源(Single Source of Truth)——集群中所有的一切:节点信息、Pod 状态、配置数据、Secret……全部存储在 etcd 中。

etcd 是 K8s 的命脉
  • etcd 的性能直接决定了整个集群的响应速度
  • etcd 的数据丢失意味着集群状态的丢失(虽然 Pod 可以重建,但某些运行时状态无法恢复)
  • 生产环境建议部署 3 或 5 个 etcd 节点(奇数个,满足 Raft 多数派要求)
  • 必须定期备份 etcd 数据

kube-scheduler:调度决策者

当你创建一个 Pod 时,API Server 只是将这个 Pod 的信息记录到了 etcd 中——此时 Pod 还处于 Pending 状态,因为它还没有被分配到任何节点上。Scheduler 的职责就是为每个未调度的 Pod 选择一个最合适的节点。

调度过程分为三个阶段:

  1. 过滤(Filtering):排除不满足条件的节点(资源不足、端口冲突、污点容忍不匹配等)
  2. 打分(Scoring):对剩余节点进行优先级打分(亲和性、镜像本地性、负载均衡等),选择得分最高的节点
  3. 绑定(Binding):将调度决策应用到集群,将 Pod 与选定节点进行绑定
调度框架(Scheduling Framework)

从 v1.19 起,Kubernetes 调度器采用插件化架构(Scheduling Framework),上述三个阶段对应调度框架中的核心扩展点。整个调度过程分为调度周期(Scheduling Cycle)绑定周期(Binding Cycle),调度周期串行执行,绑定周期可并发执行。

参考文档:Scheduling Framework

kube-controller-manager:状态守护者

Controller Manager 运行着多个控制器(Controller),每个控制器都是一个独立的控制循环(Reconciliation Loop),负责监控集群的某一部分状态,并持续将其推向期望状态。

常见的内置控制器包括:

控制器职责
Deployment Controller确保 Deployment 管理的 Pod 副本数符合期望
ReplicaSet Controller确保 ReplicaSet 管理的 Pod 副本数符合期望
Node Controller监控节点健康状态,节点失联时触发 Pod 驱逐
Service Account Controller为命名空间创建默认 ServiceAccount
EndpointSlice Controller维护 Service 与 Pod 的映射关系(推荐使用 EndpointSlice 替代已废弃的 Endpoints)
控制器的本质:控制循环

每个控制器的工作模式都是相同的:

while true:
实际状态 = 从 API Server 获取当前状态
期望状态 = 从配置中获取期望状态
if 实际状态 != 期望状态:
执行调谐操作(创建/删除/更新)
sleep(一段时间)

这就是 K8s 所谓的**"调谐(Reconciliation)"**机制。

cloud-controller-manager:云平台桥梁

如果你在 AWS、GCP、Azure 等云平台上运行 K8s,CCM 负责与云厂商的 API 交互,管理云平台特有的资源:

  • Node Controller:调用云 API 查询节点地址和状态
  • Route Controller:配置云平台的路由规则
  • Service Controller:创建云平台的负载均衡器(如 AWS ELB)

CCM 的引入使得 K8s 的核心代码不需要耦合任何特定云厂商的 SDK,实现了云平台无关性。

2.3 数据面组件详解

数据面(也叫 Worker Node)是实际运行应用工作负载的地方。每个 Worker 节点上运行着三个核心组件:

kubelet:节点上的"车间主任"

kubelet 是运行在每个 Worker 节点上的代理,它的职责是:

  1. 接收指令:从 API Server 获取分配到本节点的 Pod 规格(Spec)
  2. 管理容器:通过 CRI(Container Runtime Interface)调用容器运行时,创建和管理 Pod 中的容器
  3. 健康检查:定期执行 Liveness Probe、Readiness Probe 和 Startup Probe
  4. 状态上报:将节点和 Pod 的状态信息上报给 API Server

你可以把 kubelet 理解为一个"车间主任"——它不制定生产计划(那是 Scheduler 的事),但负责确保分配到自己车间的生产任务被正确执行。

kube-proxy:网络规则的维护者

kube-proxy 运行在每个节点上,负责维护节点的网络规则,实现 Service 的负载均衡和网络代理。它通过操作 iptables 或 IPVS 规则,将访问 Service 的流量转发到后端的 Pod。

简单来说,当你访问一个 Service 的 ClusterIP 时,kube-proxy 维护的规则会将流量自动转发到该 Service 关联的某个 Pod 上。

kube-proxy 是可选组件(v1.34+)

根据 Kubernetes 官方文档,kube-proxy 是一个可选组件。如果你使用的网络插件(CNI)自身实现了 Service 的数据包转发功能,并提供与 kube-proxy 等效的行为,那么你不需要在集群节点上运行 kube-proxy

例如,Cilium 等现代 CNI 插件可以直接替代 kube-proxy 的功能,通过 eBPF 实现更高效的 Service 负载均衡和网络代理。

参考文档:Kubernetes Architecture - kube-proxy (optional)

Container Runtime:容器的实际执行者

kubelet 本身并不直接运行容器,而是通过 CRI(Container Runtime Interface) 标准接口调用容器运行时。常见的 CRI 兼容运行时包括:

  • containerd:目前最主流的选择,Docker 的核心运行时组件独立出来的版本
  • CRI-O:专为 Kubernetes 设计的轻量级运行时,由 Red Hat 主导
  • Kata Containers:提供虚拟机级别的隔离,适用于安全要求极高的场景
Docker 与 K8s 的"分手"

在 K8s 1.20 之前的版本中,kubelet 通过一个名为 dockershim 的内置组件直接与 Docker 通信。但从 K8s 1.24 开始,dockershim 被正式移除。这并不意味着你不能在 K8s 中运行 Docker 镜像——Docker 镜像遵循 OCI 标准,containerd 和 CRI-O 都能运行它们。移除的只是对 Docker daemon 的直接依赖。


三、核心概念模型

Kubernetes 中的一切都被抽象为 API 对象(API Object)。理解这些对象及其关系,是使用 K8s 的基础。

3.1 API 对象与声明式配置

在 K8s 中,你不需要告诉系统"如何做",而是描述"你要什么"。你通过提交 YAML(或 JSON)文件来定义 API 对象,API Server 会将你的声明持久化到 etcd,然后各个控制器会持续工作,确保实际状态趋近于你声明的期望状态。

3.2 YAML 配置结构解析

每个 K8s API 对象的 YAML 配置都遵循以下结构:

apiVersion: apps/v1 # API 版本,标识对象属于哪个 API 组
kind: Deployment # 对象类型,K8s 内置了几十种对象类型
metadata: # 对象的元数据(名称、标签、注解等)
name: nginx-deployment
namespace: default
labels:
app: nginx
tier: frontend
spec: # 对象的规格(期望状态)
replicas: 3 # 期望运行 3 个 Pod 副本
selector: # 选择器,用于关联管理的 Pod
matchLabels:
app: nginx
template: # Pod 模板,定义如何创建 Pod
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
YAML 配置的四个必填字段
  1. apiVersion:指定 API 版本。v1 是核心 API 组,apps/v1networking.k8s.io/v1 等是扩展 API 组
  2. kind:对象类型,如 Pod、Deployment、Service、ConfigMap 等
  3. metadata:对象的"身份证",至少包含 name,通常还包含 labelsannotations
  4. spec:对象的"期望状态",不同类型的对象有不同的 spec 结构

3.3 API 对象层级关系

K8s 的 API 对象之间存在着清晰的层级关系。上层对象管理下层对象,形成了一个从粗粒度到细粒度的管理链。

Pod:K8s 的最小调度单元

初学者常有一个疑问:为什么 K8s 的最小单位是 Pod 而不是 Container?

Pod 是一个逻辑概念,它可以包含一个或多个紧密耦合的容器。这些容器共享:

  • 网络命名空间:同一个 Pod 中的容器可以通过 localhost 互相访问
  • 存储卷:可以挂载共享的 Volume
  • 运行约束:总是被调度到同一个节点上

一个典型的多容器 Pod 场景是"Sidecar 模式":主容器运行应用逻辑,Sidecar 容器负责日志收集、监控数据导出或代理转发。


四、一次请求的完整旅程

理论讲了不少,现在让我们通过一个具体的场景来串联所有知识:当你执行 kubectl apply -f nginx-deployment.yaml 时,K8s 内部到底发生了什么?

4.1 完整时序图

4.2 控制循环(Reconciliation Loop)详解

时序图展示了一次性的创建流程,但 K8s 的真正威力在于其持续运行的控制循环。让我们深入理解这个机制:

第一步:感知变化(Watch 机制)

K8s 的各个组件并不是定期轮询 API Server,而是通过基于 HTTP 长连接的 Watch 机制 来感知变化。当你创建、修改或删除一个对象时,API Server 会通过 Watch 通道将事件推送给所有订阅者。事件类型包括:

  • ADDED:新对象被创建
  • MODIFIED:对象被更新
  • DELETED:对象被删除

这种基于事件驱动的设计,比轮询更高效,延迟更低。

第二步:计算差异(Diff)

控制器收到事件后,会将实际状态期望状态进行对比。例如,Deployment Controller 发现期望的副本数是 3,但当前只有 2 个 Pod 在运行。

第三步:执行调谐(Reconcile)

控制器计算出需要执行的操作后,会通过 API Server 发起调谐请求。在上面的例子中,Deployment Controller 会创建一个新的 ReplicaSet,ReplicaSet Controller 会创建一个新的 Pod。

第四步:重复

整个过程是一个无限循环。即使某个操作失败了,下一轮循环也会再次尝试。这就是 K8s 实现自愈能力的根本原因。

水平扩展:自定义控制器

K8s 的控制器模式不仅限于内置资源。通过 CRD(Custom Resource Definition)Operator 模式,你可以定义自己的 API 对象和对应的控制器。例如,Prometheus Operator 可以管理 Prometheus 实例的生命周期,Cert-Manager Operator 可以自动化 TLS 证书的申请和续期。这就是 K8s 被称为"平台的平台"的原因。


五、本章小结与下一篇预告

本文作为 Kubernetes 全景解析系列的第零章,我们从宏观视角梳理了 K8s 的全貌:

维度核心要点
设计哲学声明式配置、不可变基础设施、最终一致性
架构分层控制面(决策)+ 数据面(执行)
控制面组件API Server(入口)、etcd(存储)、Scheduler(调度)、Controller Manager(控制循环)
数据面组件kubelet(节点代理)、kube-proxy(网络代理)、CRI(容器运行时)
核心抽象一切皆 API 对象,通过 YAML 声明期望状态
运行机制Watch 事件驱动 + 控制循环持续调谐

掌握这些基础知识后,你将不再对 K8s 感到迷茫——它的每一个行为都可以追溯到上述架构和机制中。

下一篇,我们将深入 K8s 的工作负载管理: 从 Pod 的生命周期到 Deployment、StatefulSet、DaemonSet 等工作负载控制器的使用场景与最佳实践。理解了工作负载,你就能真正开始在 K8s 上部署和运行应用了。


系列导航

章节主题状态
0架构设计与核心概念✅ 已发布
1工作负载与 Pod 生命周期深度解析✅ 已发布
2网络模型与服务发现全链路解析✅ 已发布
3存储体系与配置管理深度剖析✅ 已发布
4调度器、资源管理与弹性伸缩✅ 已发布
5安全体系与可观测性全景✅ 已发布
6生产级微服务架构实战✅ 已发布
7有状态应用与 Operator 模式实战✅ 已发布

参考文档

本文内容基于 Kubernetes 官方文档校验,以下为核心参考链接: