引言:为什么需要标准化接口?
在 Kubernetes 的设计哲学中,"可插拔架构"是核心原则。CRI(容器运行时接口)、CNI(容器网络接口)、CSI(容器存储接口)三大标准接口实现了 控制平面与基础设施的解耦,使得:
- 容器运行时可以自由选择(Docker/containerd/CRI-O)
- 网络方案能够按需切换(Calico/Flannel/Cilium)
- 存储系统得以灵活扩展(AWS EBS/NFS/分布式存储)
本篇学习k8s核心接口的 工作机制、核心组件 和 真实生产场景应用。
一、CRI(Container Runtime Interface):容器运行时接口
1.1 CRI 的作用与定位
CRI 是 Kubelet 与容器运行时之间的 通信协议,负责:
- 容器生命周期管理(创建/启动/停止)
- 镜像下载与管理
- 容器监控信息收集
1 2 3 4
| +----------------+ gRPC +-----------------+ | Kubelet | <=============> | CRI Runtime | | (控制平面组件) | (CRI协议) | (如 containerd) | +----------------+ +-----------------+
|
1.2 核心组件解析
- PodSandbox:Pod 的运行环境(Linux Namespace 隔离)
- ImageService:镜像拉取、删除、查询接口
- RuntimeService:容器与沙箱管理接口
1.3 工作流程示例(创建 Pod)
- Kubelet 调用
RunPodSandbox
创建沙箱环境
- 依次调用
CreateContainer
创建每个容器
- 调用
StartContainer
启动容器进程
1.4 主流实现对比
运行时 |
特点 |
适用场景 |
containerd |
轻量级,专注核心功能 |
生产环境首选 |
CRI-O |
专为K8s设计,OCI兼容 |
OpenShift 默认运行时 |
Docker |
通过dockershim兼容(已废弃) |
旧版本兼容方案 |
二、CNI(Container Network Interface):容器网络接口
2.1 CNI 的核心职责
- IP 地址分配:为每个 Pod 分配唯一 IP
- 网络连通性:实现 Pod 间、Pod 与外部网络通信
- 网络策略实施:通过插件实现网络隔离(如 NetworkPolicy)
2.2 插件工作流程
当 Pod 被创建时:
1 2 3 4
| 1. Kubelet 调用 CNI 插件 2. 插件配置 veth pair 连接容器与主机 3. 调用 IPAM 分配 IP(如 host-local) 4. 设置路由规则与 iptables 策略
|
2.3 常见插件类型
类型 |
代表实现 |
特点 |
Overlay |
Flannel VXLAN |
跨主机网络,需要封装协议 |
BGP |
Calico |
高性能,直接路由 |
eBPF |
Cilium |
可观测性 + 高性能策略 |
2.4 多网络接口场景
1 2 3 4 5 6 7 8
| { "name": "multi-network", "plugins": [ { "type": "macvlan", "master": "eth0" }, { "type": "vlan", "id": 100 } ] }
|
三、CSI(Container Storage Interface):容器存储接口
3.1 CSI 的架构分层
CSI 将存储管理分为三个核心服务:
1 2 3 4 5 6 7 8
| +-------------------+ +-----------------------+ | Controller Plugin | <---> | 存储系统(如 Ceph) | +-------------------+ +-----------------------+ ^ | gRPC +-------------------+ | Node Plugin | ---> 在节点挂载存储卷 +-------------------+
|
3.2 核心操作流程
- Provisioning:创建存储卷(
CreateVolume
)
- Attaching:将卷挂载到节点(
ControllerPublishVolume
)
- Mounting:将卷挂载到 Pod(
NodePublishVolume
)
3.3 高级特性支持
特性 |
接口方法 |
应用场景 |
动态扩容 |
ControllerExpandVolume |
在线调整存储大小 |
快照 |
CreateSnapshot |
数据备份与恢复 |
拓扑感知 |
GetTopology |
区域亲和性调度 |
3.4 开发 CSI 插件的关键步骤
- 实现 CSI Identity/Controller/Node 服务
- 部署 Sidecar 组件(external-provisioner、node-driver-registrar)
- 创建 StorageClass 定义存储类型
四、三大接口的协同工作
4.1 Pod 创建的全链路流程
1 2 3 4
| 1. Kubelet 通过 CRI 创建 PodSandbox 2. CNI 插件配置网络命名空间 3. CSI 插件挂载持久化存储卷 4. CRI 创建业务容器并加入沙箱
|
4.2 生产环境中的典型问题
- CRI 性能瓶颈:容器启动延迟高 → 优化镜像拉取策略
- CNI IP 耗尽:Pod 无法分配 IP → 调整 IPAM 配置
- CSI 挂载失败:存储卷无法附加 → 检查 RBAC 权限
五、开发自定义插件指南
5.1 CRI 开发注意事项
- 必须实现 CRI proto 定义的所有方法
- 使用
crictl
工具进行调试
- 集成 OCI 运行时(如 runc)
5.2 CNI 插件开发要点
1 2 3 4 5 6 7
| func cmdAdd(args *skel.CmdArgs) error { }
|
5.3 CSI 插件开发实践
- 使用 CSI 规范仓库 生成代码框架
- 实现必要的 gRPC 方法(至少 GET_VOLUME_INFO、CREATE_VOLUME)
- 通过
csc
工具进行端到端测试
总结:构建云原生基础设施的基石
理解 CRI/CNI/CSI 不仅能够帮助运维人员 深度排查集群问题,更是开发者 扩展 Kubernetes 能力 的关键。随着云原生生态的发展,这些接口已成为连接上层应用与底层基础设施的核心纽带。
下一步学习建议:
- 使用 minikube 实验不同容器运行时
- 开发一个简单的 CNI 插件实现固定 IP 分配
- 为本地存储实现 CSI 插件支持动态卷供给
延伸阅读