Kuberenetes 架构与核心组件

本文最后更新于 2025年8月14日 上午

架构

API Server

API访问

API Server 通过kube-apiserver进程提供服务。

  1. 启动一个带curl命令行的临时Pod, 在这个Pod里访问API Server。
1
2
3
4
5
kubectl run curl-test-pod --image=curlimages/curl -n default -i --tty - sh
~ $ cd /var/run/secrets/kubernetes.io/serviceaccount/
~ $ token=$(cat token)
~ $ curl --cacert ca.ca.crt -H "Authorization: Bearer $token"
<https://kubernetes:443/api>
  1. 通过kubectl get —raw命令行访问,仅支持get请求
1
# kubectl get --raw /api/v1 
  1. 使用curl命令行可以对API Server进行访问

    1. 获取kubectl 获取Config 配置中的整数信息
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # kubectl config view -raw
    apiVersion: v1
    cluster:
    - cluster:
    certificate-authority-data: xxxxxxxxxxxxxxxxxx
    server: <http://192.168.18.3:6443>
    name: kubernetes
    contexts:
    - context
    cluster: kubernetes
    user: kubernetes-admin
    name: kubernetes-admin&kubernetes
    current-context: kubernetes-admin@kubernetes
    kind: Config
    preferences: {}
    users:
    - name: kubernetes-admin
    user:
    client-certificate-data: yyyyyyyyyyyyyyyyyy
    client-key-data: zzzzzzzzzzzz

    certificate-authority-data: CA证书

    client-certificate-dat: 证书

    client-key-data: kubectl证书的私钥

    b. 使用base64存储 证书信息,使用curl 对服务器进行访问

    1
    # echo "xxxxxxxxxxxxxxxxxxxxxxxxx" | base64 -d 
    1
    # curl --cacert ./ca.crt --cert ./client.crt --key ./client.key <https://192.168.18.3:6443>

    c. 请求的返回信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    "kind": "APIVersions",
    "versions": [
    "v1"
    ],
    "serverAddressByClientCIDRs": [
    {
    "clientCIDR": "0.0.0.0/0",
    "serverAddress": "192.168.18.3:6443"
    }
    ]
    }

    d. 通过/api/v1用于查询API Server支持的资源对象的种类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    {
    "name": "configmaps",
    "singularName": "configmap",
    "namespaced": true,
    "kind": "Configmap",
    "verbs": [
    "create",
    "delete",
    "deletecollection",
    "get",
    "list",
    "patch",
    "update",
    "watch"
    ],
    "shortsNames": [
    "cm"
    ],
    "storageVersionHash": "qFsy16wFWjQ="
    },

应用场景

  1. 通过调用Kubernetes API 搭建特定的分布式集群。

API Server 本身也被注册为一个服务,通过访问服务进行创建过程

1
2
3
# kubectl get service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 169.169.0.1 <none> 443/TCP 1d
  1. 开发基于Kubernetes的图形化管理平台

基于性能考虑的设计

  1. API Server拥有大量高性能的底层代码。在API Server源码中使用了协程及队列这种轻量级的高性能并发代码,使单进程的API Server具备超强的多核处理能力,从而可以快速地并发处理大量的请求
  2. 普通List接口结合异步Watch接口,不但完美解决了Kubernete中各种资源对象的高性能同步问题,也提升了集群实时响应各种事件的灵敏度
  3. 采用了高性能的etcd而非传统的关系数据库,不仅解决了数据的可靠性问题,也极大地提升了API Server数据访问层的性能。

架构

API Server

API层

以REST方式提供各种API,除了Kubernetes资源对象的CRUD和Watch等主要API,还有健康检查,日志,性能指标等与运维监控相关的API

访问控制层

当有客户端访问API时,访问控制层负责对用户身份进行鉴权,验证用户的身份,核准访问权限,并根据配置的各种资源访问许可逻辑,判断是否允许访问

Registry层

Kubernetes把所有资源对象都保存在注册表中,准对注册表中的各种资源对象都定义了资源对象的类型,如何创建资源对象,如何转换资源的不同副本

etcd

用于持久化存储Kubernetes资源对象的KV数据库。etcd的Watch API对于API Server来说至关重要,因为通过这个接口,API Server创新性地设计了List-Watch这种高性能的资源对象实时同步机制。

List-Watch过程

  1. 借助etcd提供的Watch API ,API Server可以监听在etcd上发生的数据操作事件,比如Pod创建事件,更新事件,删除事件等。事件发生后,etcd会即时通知API Server
  2. etcd 会 委托API Server 使用API Server的Watch接口,来让其他应用可以在不直接访问etcd的情况下,获得etcd的事件信息
  3. List-Watch机制可用于实现数据同步的代码逻辑。客户端首先调用API Server的List 接口获取相关资源对象的全量数据并将其缓存到内存中,如何启动对应资源对象的Watch携程,在接收到Watch事件后,根据事件的类型对内存中的全量资源对象列表做出相应的同步修改。

Kubenetes Proxy API

Kubernetes Proxy API 用于代理REST请求,将API Server 收到的REST请求转发到某个kubelet进程的REST端口,由该kubelet进程负责响应。

Node相关接口

1
2
3
4
/api/v1/nodes/{name}/proxy/pods           # 列出指定Node内的所有Pod的信息
/api/v1/nodes/{name}/proxy/metrics # 列出指定Node的性能指标的统计信息
/api/v1/nodes/{name}/proxy/spec # 列出指定Node的概要信息
/api/v1/nodes{name}/proxy/configz # 列出指定Node的当前参数信息

通过设置Debug模式可以进行更多信息的请求

1
--enable-debugging-handlers=true
1
2
3
4
5
6
7
/api/v1/nodes/{name}/proxy/run             # 在Node上运行某个容器
/api/v1/nodes/{name}/proxy/exec # 在Node上的某个容器内运行某个命令
/api/v1/nodes/{name}/proxy/attach # 在Node上attach某个容器
/api/v1/nodes/{name}/proxy/portForward # 实现Node上的Pod端口转发
/api/v1/nodes/{name}/proxy/logs # 列出Node的各类日志信息
/api/v1/nodes/{name}/proxy/runningpods # 列出在该Node上运行的Pod信息
/api/v1/nodes/{name}/proxy/debug/pprof # 列出node上当前Web服务的状态

Pod相关接口

1
2
/api/v1/namespaces/{namespace}/pods/{name}/proxy               #访问pod
/api/v1/namespaces/{namespace}/pods/{name}/proxy/{path:*} #访问Pod服务的URL路径

Service相关接口

1
/api/v1/namespaces/{namespace}/services/{name}/proxy

模块间通信

API Server作为集群的核心,负责集群各功能模块之间的通信,集群内的各个功能模块通过API Server将信息存入etcd中,当需要获取和操作这些信息时,则通过API Server 提供的REST接口来实现,从而实现各模块之间的信息交互

场景1

kubelet进程与API Server交互,每个Node上的kubelet每隔一段时间周期就会调用一次API Server 的REST接口信息来报告自身状态,API Server在接收到这些信息后,会将Node状态信息更新到etcd中。此外kubelet会通过API Server的Watch接口监听Pod信息,如果监听到新的Pod副本被调度绑定到本Node,则执行Pod对应的容器创建和启动逻辑;如果Pod被删除,就删除本Node上相应的Pod容器,如果监听到修改Pod的信息,则相应地修改本Node的Pod容器

场景2

kube-controller-manager进程与API Server的交互。 kube-controller-manager进程中的Node Controller模块通过API Server提供的Watch接口实时监控Node的信息,并做相应的处理

场景3

kube-scheduler与API Server的交互。Scheduler在注册过API Server的Watch接口监听到新建Pod副本的信息后,会检索所有符合该Pod要求的Node列表,开始执行Pod调度逻辑,在调度成功后将Pod绑定到目标Node上。

Controller Manager

Controller Manager 通过API Server 接口实时监控集群中特定资源的变化,当系统发生故障或者因其他原因导致目标资源对象的属性或状态发生变化时,Controller尝试将其状态调整为期望状态

Controller Manager中管理着多种Controller 对象分别管控对应的资源对象。

Finalizer机制

Finalizer 机制为了解决:

  • 如果资源对象之间有引用关系,则不能被删除。Kuberenetes通过资源对象的属主引用,这一特性来表明两个对象之间存在从属关系
  • 如果涉及物理资源和设备的占用,则需要先做资源释放和回收操作,然后才能删除

Finalizer提供了一种删除操作前的拦截机制,能够让控制器在资源对象被删除前进行回调,查看被占用的资源和设备的释放这两项工作是否已经完成,进而判断资源对象是否可以被删除。如果一个资源对象需要对删除操作进行保护,则某些控制器会在合适的时机,添加相应的Finalizer机制到被被保护对象的metada.finalizers属性里并更新此对象。metadata.finalizers是一个数组属性,每个值都对应一个Finalizer。当Finalizer关联的控制器检测到目标资源对象正处于被删除状态时,就会执行相应的pre-delete操作,每执行完一个回调,就会删除finalizers列表中对应的Finalizer记录。当资源对象上的finalizers列表为空时,API Server才会将这个对象彻底删除。

例如PersistentVolume上的kubernetes.io/pv-protection,它可用于防止意外删除PersistentVolume对象。当一个PV对象被某个Pod使用时,Kubernetes会给这个PV对象添加pv-protection Finalizer信息,如果此时我们试图删除这个PV对象,那么它将进入被删除状态,但是控制器因为该Finalizer存在而无法删除该资源。当Pod停止使用该PV对象时,Kubernetes就会清除pv-protection Finalizer,随后控制器删除该PV对象。

在引入资源对象的Finalizer机制后,Kubernetes资源对象的删除操作就被设计成两步删除的模式

  1. API Server 通过标记对象的meta.deletionTimestamp属性,来告知系统中的各个相关组件,目标对象已进入被删除状态,并进入相关的对象销毁流程。
    1. 为Pod定制的优雅销毁流程,主要由kubelet负责执行
    2. 其他资源对象的简单销毁流程
  2. 当资源对象上捆绑的Finalizer都被相应的处理器处理并清楚后,API Server执行资源对象的Delete操作,真正从etcd中删除对象

Deployment Controller

Deployment Controller的核心作用是确保集群中某个Deployment关联的Pod副本数量在任何时候都保持预设值。

Deployment Controller在工作过程中实际上是在控制两类资源对象:Deployment和ReplicaSet。在创建了Deployment资源对象后,Deployment Controller也默默创建了对应的ReplicaSet。

Deployment Controller 的作用有:

  • 确保在当前集群中有且仅有N各Pod实例,N是在Deployment中定义的Pod副本数量
  • 通过调整spec.replicas 属性的值来实现系统扩容或者缩容
  • 通过改变Pod模板来实现系统的滚动更新

Deployment Controller的场景:

  • 重新调度: 不管想运行1各副本还是1000各副本,副本控制器都能确保指定数量的副本存在于集群中,即时发生Node故障或Pod副本被终止运行等意外状况
  • 弹性伸缩:手动或者通过自动扩容代理修改副本控制器spec.replicas属性的值,即可非常容易地增加或减少副本的数量
  • 滚动更新:副本控制器被设计成通过逐个替换Pod来辅助服务的滚动更新

Node Controller

kubelet进程在启动时通过API Server注册自身Node信息,并定时向API Server汇报状态信息。API Server在接收到这些信息后,会将这些信息更新到etcd中。在etcd中存储的Node信息包括Node健康状况,Node资源,Node名称,Node地址信息,操作系统版本,Docker版本,kubelet版本。Node健康状况包括就绪,未就绪和未知三种。Node Controller通过API Server 实时获取Node的相关信息,管理和监控集群中各个Node的相关控制功能

Controller决策

  1. Controller Manager 在启动时,如果设置了 —cluster-cidr参数,那么就为每个没有设置Spec.PodCIDR的Node都生成一个CIDR地址,并用该CIDR地址设置Node的Spec.PodCIDR属性,这样做的目的是防止不同Node的CIDR地址发生冲突
  2. 逐个读取Node信息,多次尝试修改nodeStatusMap中的Node状态信息,该Node信息和在Node Controller的nodeStatusMap中保存的Node信息进行比较。如果判断出没有收到Kubelet发送的Node信息,第一次收到Node上的kubelet发送的Node信息或在该处理过程中Node状态变成非‘健康’状态,则在nodeStatusMap中保存该Node的状态信息,并将Node Controller所在节点的系统事件作为探测时间和Node状态变化时间。如果判断出在指定时间内收到新的Node信息,但Node状态没发生变化,则在nodeStatusMap中保存该Node的状态信息,并将Node Controller所在Node的系统时间作为探测时间,将上次Node信息中的Node状态变化时间作为该Node状态变化时间,如果判断出在某段时间内没有收到Node状态信息,则设置Node状态为“未知”,并且通过API Server保存Node状态。
  3. 逐个读取Node信息,如果Node状态变为非Ready状态,则将该Node加入待删除队列,否则将该Node从队列中删除。如果Node状态为非Ready状态,且系统指定了Cloud Provider,则Node Controller调用Cloud Provider查看Node,若发现Node故障,则删除etcd中的Node信息,并删除与该Node相关的Pod等资源的信息。

在后续的版本中对Node Controller 进行了功能拆分:

Node ipam Controller 是集群中为Node分配Pod CIDR的控制器。为了保证集群中的Pod的IP地址不重复,集群中的每个Node都需要使用一段相互不重复的PodCIDR地址段,每个Node上的Pod都从改地址段中获取一个Pod IP地址。如果在启动kube-controller-manager进程时没有设置—cluster-cidr参数,则需要Node ipam Controller来动态地给Node分配Pod CIDR地址段,此时需要设置参数—allocate-node-cidrs为true,即开启Node ipam Controller, 则具体负责分配Pod CIDR 的是CIDR Allocator组件,由—cidr-allocator-type来设置。可用的CIDR Allocator组件有以下几种:

  • RangeAllocator: 使用内部的CIDR对Node 进行分配,它与RouteController配合使用,确保网络的连通性
  • CloudAllocator: 从底层云平台同步Pod CIDR并分配。

将基于污点的Pod驱逐功能拆分到Taint Eviction Controller中,其余功能则保留在Node Lifecycle Controller中。

  • Node Lifecycle Controller 关于Node的健康情况,并给对应的Node添加NotReady 与Unreachable 污点标签
  • Taint Eviction Controller 监测Node和Pod的update 变化情况,并执行基于NoExecute污点的Pod驱逐动作

ResourceQuota Controller

ResourceQuota Controller 用于进行资源配额管理,使得指定的资源对象在任何时候都不会超量占用系统物理资源,保障整个集群的平稳运行

目前Kubernete支持以下三个级别的资源配置管理:

  • 容器级别: 可以对容器分配的CPU和Memory 等计算资源进行限制
  • Pod级别: 可以对一个Pod内所有容器占用的资源总量进行限制
  • 命名空间级别: 可以对Pod,Replication Controller, ResourceQuota,Secret和可持有PV对象等数量进行限制

资源配额控制的设计

Kubernetes的配额管理通过Admission Control来控制,它具备两种策略:

LimitRanger

当Pod定义中声明了LimitRanger,则用户通过API Server请求创建或者修改资源时,Admission Control会计算当前配额的使用情况。如果不符合配额约束,则创建对象失败。

ResourceQuota

对于定义了ResourceQuota的命名空间,ResourceQuota Controller会定期统计和生成该命名空间中各类对象的资源使用总量,包括Pod,Service,RC和Secret等的实例的个数,以及该命名空间中所有Container实例的资源使用量,之后将统计结果写入etcd的reourceQuotaStatusStorage目录中。写入resourceQuotaStatusStorage的内容包含Resource名称,配额值,当前使用量。随后这些统计信息会被Admission Contol使用,以确保相关命名空间中的资源配额总量不会超过ResourceQuota中的限定值

Namespace Controller

用户通过API Server可以创建新的命名空间并将其保存到etcd中,Namespace Controller 定时通过API Server读取命名空间的信息,如果命名空间被API标识为优雅删除,则将该命名空间设置为被删除状态并保存在etcd中。同时,Namespace Controller 删除该命名空间中的ServiceAccount,Deployment,Pod,Secret,PersistentVolume,ListRange,ResourceQuota和Event相关资源对象

在命名空间被设置为被删除状态后,Admission Controller的NamespaceLifecycle插件会阻止为该Namespace创建新的资源。同时,在Namespace Controller删除该命名空间中的所有资源对象后,Namespace Controller会对该命名空间执行finalize操作,删除该命名空间的spec.finalizers域中的信息

如果Namespace Controller 观察到命名空间设置了删除期限,同时该命名空间的spec.finalizers域是空的,那么Namespace Controller 将通过API Server删除该命名空间的资源

Endpoint Controller

Endpoint Controller 负责生成和维护所有Endpoint对象的控制器

Endpoint Controller 负责监控Service和对应的Pod副本的变化,如果检测到Service被删除,则删除和该Service对应的Endpoint对象。如果监控到新的Service被创建或者被修改,则根据该Service信息获取相关的Pod列表,然后创建或者更新Service对应的Endpoint对象。如果检测到Pod的事件,则更新它所对应的Service的Endpoiny对象。Endpoint Controller主要通过API Server提供的以下接口操作Endpoint对象

1
2
3
4
POST /api/v1/namespaces/{namespace}/endpoints            # 创建Endpoint对象
PUT /api/v1/namespaces/{namespace}/endpoints/{name} # 更新Endpoint对象
DELETE /api/v1/namespaces/{namespace}/endpoints/{name} # 删除Endpoint对象
DELETE /api/v1/namespaces/{namespace}/endpoints # 删除Endpoints组

Scheduler

Scheduler用于对待调度的Pod通过一些复杂的调度流程计算出其最佳目标Node,再将Pod绑定到目标Node上。Scheduler是负责Pod调度的进程。

Scheduler的作用是将待调度的Pod按照特定的调度算法和调度策略绑定到集群中某个合适的Node上,并将绑定信息写入etcd。整个调度过程中涉及到3个对象,分别是待调度的Pod列表,可用Node列表及调度算法和调度策略,

调度流程

  1. 通过调度算法为待调度Pod列表中的每个Pod都从Node列表中选择一个最合适它的Node。
  2. 目标Node上的kubelet通过API Server监听到Scheduler产生的Pod绑定事件,获取对应的Pod清单,下载Image镜像并启动容器。

旧版本调度

  1. 过滤阶段,遍历所有目标Node,筛选出符合要求的候选Node。在此阶段,Scheduler将不合适的Node全部过滤掉,在筛选完成后通常会有多个候选Node供调度,从而进入打分阶段。如果结果集为空, 则表示当前没有符合条件的Node,此时Pod会保持在Pending状态
  2. 打分阶段,在过滤阶段的基础上,采用优选策略计算出每个候选Node的积分,积分最高者胜出。挑选出最佳Node后,Scheduler会把目标Pod安置在该Node上,完成调度

调度框架Scheduler Framework

Scheduler Framework在原调度策略上进行了一些扩展

  • PreEnqueue: 对新来的计划调度的Pod进行筛查,只有完全具备条件的Pod才能进入待调度队列中,不具备条件的Pod则被放到Unshedulable队列中等待机会。这里可以有多个插件对同一个Pod进行筛查,只有当所有插件的接口都返回成功时,该Pod才满足调度条件
  • QueueSort: 对调度队列中待调度的Pod进行排序,一次只能启用一个队列排序插件
  • PreFilter:在过滤之前预处理Pod或集群的信息,可以将Pod标记为不可调度
  • Filter:相当于调度策略中的Predicates,用于过滤不能运行Pod的Node。过滤器的调用顺序是可配置的,如果么有Node通过所有过滤器的筛选,则该Pod将被标记为不可调度。
  • PreScore: 信息扩展点,可用于Node预打分操作
  • Score:给完成过滤的Node打分,调度器会选择得分最高的Node
  • Reserve: 信息扩展点,当资源已被预留给Pod时,会通知插件
  • Permit: 可以阻止或延迟Pod绑定
  • PreBind:在Pod绑定Node之前执行
  • Bind:将Pod与Node绑定

Kuberenetes 架构与核心组件
http://gadoid.io/2025/08/14/Kubernetes-架构与核心组件/
作者
Codfish
发布于
2025年8月14日
许可协议