目录
Please enable Javascript to view the contents

K8s 扩展性机制——从基础设施到自定义控制器

 ·  ☕ 7 分钟

重要

Kubernetes 核心只做编排——调度、声明式 API、状态协调。容器的运行时、网络、存储、GPU、调度策略、自定义 API,全部通过扩展机制交给外部插件。

扩展机制按层级从下到上分为四层:

层级扩展机制管什么代表实现
基础设施层CRI、CNI、CSI运行时、网络、存储containerd、Calico、Ceph CSI
资源层Device Plugin、DRAGPU、FPGA 等硬件NVIDIA GPU Operator
调度层Scheduler Framework自定义调度逻辑scheduler-plugins、Volcano
API 与控制层CRD、Operator自定义资源和控制器Prometheus Operator
K8s 的扩展哲学:核心只定义接口规范,具体实现全部下放。修改网络方案不碰 Kubelet,换 GPU 驱动不重启调度器,增加 CRD 不需要改 API Server 代码。

1.简介

Kubernetes 通过接口解耦核心组件和具体实现。日常工作中四层的接触频率:

接口日常接触频率说明
CNI最高网络问题排查频繁,跨节点不通先看 CNI
CSI中等存储 PVC 挂不上、快照失败时排查
CRI较低通常由集群初始化工具配置(kubeadm/rke),日常运维少碰

2.基础设施层——CRI / CNI / CSI

2.1 CRI — 容器运行时接口

CRI(Container Runtime Interface)是 Kubelet 与容器运行时之间的 gRPC 协议。

1
2
3
4
5
6
7
8
Kubelet (gRPC Client)
    |
    | Unix Socket (如 /run/containerd/containerd.sock)
    |
    v
containerd / CRI-O (gRPC Server)
    ├── RuntimeService  → 管理 Pod Sandbox、Container 生命周期
    └── ImageService    → 拉取、列表、删除镜像

Kubelet 在启动时通过 --container-runtime-endpoint 指定 CRI 的 socket 路径。

参数示例值说明
--container-runtime-endpointunix:///run/containerd/containerd.sockCRI 实现监听的 socket
--image-service-endpoint默认与 runtime-endpoint 相同用于单独的镜像服务

CRI 的核心流程:

1
2
3
4
5
Kubelet 决定启动一个 Pod
    → RuntimeService.RunPodSandbox()    // 创建 Pod Sandbox(网络命名空间)
    → CNI 插件为 Sandbox 配置网络
    → RuntimeService.CreateContainer()  // 创建各容器
    → RuntimeService.StartContainer()   // 启动容器

Kubelet 的 CRI 请求是声明式的:只告诉容器运行时"我要一个什么状态的容器",不管怎么实现。这也是 CRI-O 和 containerd 可以互相替换的前提。

2.2 CNI — 容器网络接口

CNI(Container Network Interface)是 CNCF 定义的容器网络规范。Kubelet 通过 CNI 调用插件为每个 Pod 分配 IP、创建网络接口、配置路由。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Kubelet
    |
    | 读取 /etc/cni/net.d/*.conf  → 确定用哪个 CNI 插件
    | 调用 CNI 二进制(/opt/cni/bin/)
    |
    v
CNI Plugin
    ├── ADD    → 创建 veth pair,分配 IP,写入路由
    ├── DEL    → Pod 删除时回收 IP,删除 veth
    └── CHECK  → 周期性健康检查现有配置

CNI 插件按数据面分为两类:

类型原理代表性能
Overlay封装隧道(VXLAN/IPIP)Flannel VXLAN、Calico IPIP有封装开销
路由不封装,直接路由Calico BGP、Flannel HostGW接近裸机

深度解析、包流向和方案选型见 K8s 网络 CNI 系列

2.3 CSI — 容器存储接口

CSI(Container Storage Interface)是 CNCF 定义的容器存储标准。Kubernetes 通过 CSI 将存储操作从核心代码剥离到外部组件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[外部 CSI 组件]
    ├── Controller Plugin      → Provision/Delete(创建/删除 PV)
    ├── Node Plugin            → Stage/Publish(挂载到 Pod)
    ├── external-provisioner   → 监听 PVC 事件,调用 Controller.CreateVolume
    ├── external-attacher      → 监听 VolumeAttachment 事件
    └── node-driver-registrar  → 注册插件到 Kubelet

[Kubernetes 核心]
    ├── kube-controller-manager → 创建 PV / PVC 对应的 VolumeAttachment
    └── Kubelet                 → 调用 Node Plugin 完成挂载

CSI 替换了早期的 In-tree Volume Plugin(插件编进 K8s 二进制)和 FlexVolume(脚本式插件),支持:

特性In-treeCSI
独立升级否,需跟随 K8s 版本是,独立发布
动态供应部分支持完整支持
快照/克隆不支持支持
在线扩容不支持支持

深度架构解析见 K8s 存储 CSI 系列

2.4 三个接口的调用链(一次 Pod 启动)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
调度器选中 Node
Kubelet 收到 Pod Spec
┌── CRI: RunPodSandbox   → 创建 Pod Sandbox(共享网络命名空间)
├── CNI: ADD              → 分配 IP、创建 veth、配置路由 → Pod 网络就绪
├── CRI: CreateContainer  → 为 Init Container 和主 Container 分别创建
├── CSI: PublishVolume     → 将 PV 挂载到 Pod 对应的路径
└── CRI: StartContainer   → 启动容器 → Pod Running

三个接口不是孤立工作——CRI 创建 Sandbox 之后 CNI 才能插网络,CSI 挂载在容器启动之前,CRI 拉起容器在最后。

3.资源层——Device Plugin / DRA

基础设施层管 CPU、内存、磁盘、网络,但当 Pod 需要 GPU、FPGA、Infiniband 等专用硬件时,Kubelet 不知道这些设备的存在。Device Plugin 是 Kubelet 发现和分配硬件资源的扩展机制。

3.1 Device Plugin

1
2
3
4
5
6
7
8
9
Kubelet
    |
    | 通过 Unix Socket 发现插件(/var/lib/kubelet/device-plugins/)
    |
    v
Device Plugin (vendor-provided)
    ├── ListAndWatch  → 向 Kubelet 上报设备列表及健康状态
    ├── Allocate      → 调度器选出 Node 后,Kubelet 调用 Allocate 获取设备挂载信息
    └── 健康检查       → 设备变更时重新上报

Pod 声明需要 GPU:

1
2
3
resources:
  limits:
    nvidia.com/gpu: 1

Device Plugin 上报的资源名(nvidia.com/gpu)出现在 Node 的 status.allocatable 中,调度器据此做 Pod 放置决策。

步骤动作
Device Plugin 启动 → 向 Kubelet 注册Kubelet 将资源加入 Node Status
用户创建带 GPU 请求的 Pod调度器根据资源筛选节点
Kubelet 调用 AllocateDevice Plugin 返回设备路径、环境变量等挂载信息
Kubelet 启动容器挂载 GPU 设备、注入环境变量

深度解析见 K8s 设备插件系列

3.2 DRA——动态资源分配

Device Plugin 是静态的——Pod 必须声明固定数量的 GPU。DRA(Dynamic Resource Allocation,K8s 1.26+)允许更灵活的设备分配:

特性Device PluginDRA
分配粒度整卡整卡或 MIG 分区
设备选择由调度器决定用户可在 Claim 中描述需求
跨 Pod 共享不支持支持
网络设备不支持支持 Infiniband、DPU

4.调度层——Scheduler Framework

K8s 默认调度器只认 CPU/内存/节点亲和性。当需要自定义调度逻辑(如 GPU 拓扑感知、成本优先、实时性优先)时,通过 Scheduler Framework 的扩展点插入自定义逻辑。

1
2
3
4
调度周期(每个 Pod 一次)
  QueueSort → PreFilter → Filter → PreScore → Score → Reserve → Permit → Bind
绑定周期(异步)                                                     PreBind → Bind → PostBind

关键扩展点:

扩展点作用示例
Filter过滤不满足条件的 NodeGPU 型号筛选、存储类型筛选
Score为每个 Node 打分成本优先(选最便宜)、装箱率优先(选最满)
Reserve资源预占GPU 拓扑感知预留
Permit阻塞/放行调度等待外部条件满足(如 license 校验)

各扩展点可以注册多个插件,调度器在每个阶段依次调用,Score 阶段的分数加权求和决定最终选中节点。

Scheduler Framework 的深度解析见独立文章 Scheduler Framework 详解

5.API 与控制层——CRD / Operator

前面三层解决"如何运行 Pod",这一层解决"如何声明和管理业务对象"。

5.1 CRD——自定义资源

CRD(Custom Resource Definition)允许在 K8s API 中注册新的资源类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: mysqls.database.example.com
spec:
  group: database.example.com
  versions:
    - name: v1
      served: true
      storage: true
  scope: Namespaced
  names:
    plural: mysqls
    singular: mysql
    kind: MySQL

注册后 kubectl 可以直接操作:

1
2
kubectl get mysqls
kubectl describe mysql my-db

CRD 本身只声明数据结构,不包含业务逻辑。业务逻辑由 Operator 实现。

5.2 Operator——自定义控制器

Operator 监听 CRD 资源的变化(创建、更新、删除),调用 K8s API 实现自动化运维。

1
2
3
4
5
CRD 声明期望状态          →  例如:Spec.Replicas = 3
Operator(控制器)        →  持续对比 Spec 和实际状态
实际状态                  →  kubectl get pods | grep mysql
  ↓ 有差异
Operator 执行调谐          →  创建 StatefulSet、Service、PVC…
场景人工操作Operator 自动化
扩缩容手动改 Deployment replicas改 CRD Spec,Operator 执行
备份恢复登录 Pod,dump + 上传CRD 声明备份策略,Operator 定时执行
主从切换手动 promote slaveOperator 检测主库异常,自动切换

深度解析见 CRD 概念、使用场景、go 示例K8s 扩展——Operator

6.总结

四层扩展机制从基础设施到业务逻辑:

层级机制解决的核心问题
基础设施层CRI / CNI / CSI容器怎么跑、网怎么通、盘怎么挂
资源层Device Plugin / DRAGPU / FPGA 等硬件怎么接入调度
调度层Scheduler Framework自定义 Node 筛选和打分逻辑
API 与控制层CRD / Operator业务状态怎么声明、怎么自愈

选型逻辑:先有(基础设施层),再加(资源层),后改(调度层),最后配(CRD/Operator)。从下到上是扩展能力的递进。

7.参考

分享

Hex
作者
Hex
CloudNative Developer