Kubernetes CRI 容器运行时接口全解析:从 gRPC 接口设计到多运行时生态与调试实战
云原生教程【免费下载链接】kubernetes-handbookKubernetes Handbook Kubernetes指南 https://kubernetes.feisky.xyz项目地址https://gitcode.com/gh_mirrors/kub/kubernetes-handbook点击查看免费下载本文以 extension/cri/README.md 为核心结合 extension/cri/cri-tools.md、extension/cri/frakti.md 及仓库内的 Kubelet、特性开关与部署文档系统梳理 Kubernetes CRIContainer Runtime Interface的接口模型、运行时生态、RuntimeClass 多运行时机制以及基于 crictl 的调试与基于 Frakti 的隔离运行时落地实践。读完本文你将掌握 CRI 的架构原理、如何开发与对接一个 CRI 运行时、如何用 crictl/critest 验证与排障以及如何通过 RuntimeClass 在同一集群内混用多种运行时。CRIContainer Runtime Interface容器运行时接口是 Kubernetes v1.5 引入的容器运行时插件接口。它将 Kubelet 与容器运行时彻底解耦原本完全面向 Pod 级别的内部接口被拆分为面向 Sandbox 与 Container 的 gRPC 接口并将镜像管理与容器管理分离到不同的服务。正是凭借 CRIKubernetes 得以摆脱对单一容器引擎如 Docker的强绑定使 containerd、CRI-O、Frakti、Virtlet 等各具特色的运行时可以以插件方式平滑接入。CRI 的设计由来与整体架构演进时间线CRI 的构思早在 Kubernetes v1.4 就进入设计与讨论阶段v1.5 发布第一个测试版本v1.5发布 CRI 首个测试版v1.6已有 frakti、cri-o 等外部容器运行时接入v1.7新增 cri-containerd支持用 Containerd 管理容器。这一演进路径印证了 CRI 的核心目标——让 Kubelet 通过一套稳定的接口与任意容器运行时通信而不是把运行时实现焊死在 Kubelet 内部。在 concepts/components/kubelet.md 中同样可以看到容器运行时负责真正管理镜像和容器的生命周期Kubelet 通过 CRI 与容器运行时交互而容器执行引擎如 dockershim、rkt 等只是 Kubelet 内部组件中的一层。采用 CRI 后的组件职责划分引入 CRI 之后Kubernetes 的组件协作模型变为组件职责Kubelet维护容器生命周期、VolumeCSI与网络CNI管理是 CRI 的客户端Container RuntimeCRI shim镜像管理以及 Pod/容器的真正运行是 CRI 的服务端API Server唯一的资源操作入口Kubelet 通过其 watch API 感知调度到本节点的 Pod完整创建 Pod 的流程为用户通过 REST API 创建 Pod → API Server 写入 etcd → Scheduler 检测到未绑定 Node 的 Pod 并完成调度绑定 → Kubelet 检测到新 Pod 后通过 Container Runtime 运行该 Pod → Kubelet 从 Container Runtime 取回 Pod 状态并回写 API Server参见 concepts/components/README.md。CRI 接口RuntimeService 与 ImageServiceCRI 基于 gRPC 定义了RuntimeService与ImageService两个 gRPC 服务分别负责容器运行时的生命周期管理与镜像管理。接口定义随 Kubernetes 版本演进位于不同的代码路径Kubernetes 版本接口定义位置v1.14 及以上kubernetes/cri-api仓库的pkg/apis/runtimev1.10 ~ v1.13pkg/kubelet/apis/cri/runtime/v1alpha2v1.7 ~ v1.9pkg/kubelet/apis/cri/v1alpha1/runtimev1.6pkg/kubelet/api/v1alpha1/runtime通信模型Kubelet 作为 CRI 的 gRPC 客户端容器运行时则实现 CRI 的服务端gRPC Server通常称为CRI shim。容器运行时启动 gRPC Server 时需监听本地的 Unix SocketLinux 支持unix格式Windows 使用tcp格式Kubelet 通过该 Socket 发起 gRPC 调用。开发一个 CRI 容器运行时开发新的容器运行时只需实现 CRI 的两个 gRPC ServiceRuntimeService 与 ImageService并将 gRPC Server 监听在本地 Unix Socket 上。原文给出了一个最小可运行的 Go 示例骨架import ( // Import essential packages google.golang.org/grpc runtime k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2 ) // Serivice implements runtime.ImageService and runtime.RuntimeService. type Service struct { ... } func main() { service : Service{} s : grpc.NewServer(grpc.MaxRecvMsgSize(maxMsgSize), grpc.MaxSendMsgSize(maxMsgSize)) runtime.RegisterRuntimeServiceServer(s, service) runtime.RegisterImageServiceServer(s, service) lis, err : net.Listen(unix, /var/run/runtime.sock) if err ! nil { logrus.Fatalf(Failed to create listener: %v, err) } go s.Serve(lis) // Other codes }实现要点示例中通过grpc.MaxRecvMsgSize/grpc.MaxSendMsgSize设置 gRPC 消息大小上限这是因为 CRI 的PullImage、CopyFile等调用可能携带较大的镜像与文件内容默认的 4MB gRPC 限制通常不够用Service结构体需同时实现runtime.ImageService与runtime.RuntimeService两个接口分别注册到同一 gRPC Server监听地址为本地 Unix Socket如/var/run/runtime.sock与 Kubelet 的--container-runtime-endpoint保持一致。更完整的实现可参考 Kubelet 内置的 dockershim 以及社区 CRI-O 项目的做法仓库内相关描述见 concepts/components/kubelet.md 的容器运行时小节。Streaming API 的设计与演进对于Exec、PortForward 和 Attach等 Streaming APICRI 要求容器运行时返回一个 streaming server 的 URL供 Kubelet 重定向来自 API Server 的请求。这里存在一个重要的行为分界v1.10 及更早版本容器运行时必须返回一个 API Server 可直接访问的 URL通常与 Kubelet 使用相同的监听地址v1.11 开始Kubelet 新增--redirect-container-streaming参数默认为false默认不再转发而是代理Streaming 请求。这样运行时可以返回一个 localhost 的 URL也不再需要为 streaming server 配置 TLS。这一演进显著降低了第三方运行时的接入成本——运行时无需暴露对外的可访问地址只需在本机提供 streaming 服务即可。Kubelet 对接 CRI 的配置在启动 Kubelet 时通过以下参数指定容器运行时监听的 Unix Socket 路径kubelet --container-runtimeremote --container-runtime-endpointunix:///var/run/runtime.sock --image-service-endpointunix:///var/run/runtime.sock参数说明--container-runtimeremote声明使用 remoteCRI运行时模式--container-runtime-endpoint容器运行时 gRPC 服务的 Socket 路径--image-service-endpoint镜像服务 gRPC 服务的 Socket 路径可与运行时共用同一 Socket。仓库中 setup/k8s-hard-way/09-bootstrapping-kubernetes-workers.md 给出了一个基于 containerd 的真实配置示例其 systemd 单元中同时配置了ExecStart/usr/local/bin/kubelet \ --config/var/lib/kubelet/kubelet-config.yaml \ --container-runtimeremote \ --container-runtime-endpointunix:///var/run/containerd/containerd.sock \ --image-pull-progress-deadline2m \ --kubeconfig/var/lib/kubelet/kubeconfig \ --network-plugincni \ --register-nodetrue \ --v2此外concepts/components/kubelet.md 还展示了 Kubelet 与 CRI 相关的内部组件视图Kubelet 的 syncLoop 从 API 或 manifest 目录接收 Pod 更新交由辅助 manager 处理其中 CRI 层负责与 container runtime shim 通信网络则由 CNI/kubenet 插件承担。CRI 容器运行时生态当前基于 CRI 的容器引擎已相当丰富按维护方与核心特性可整理如下CRI 容器运行时维护者主要特性容器引擎DockershimKubernetes内置实现、特性最新dockercri-oKubernetesOCI 标准不需要 DockerOCIrunc、kata、gVisor…cri-containerdContainerd基于 containerd 不需要 DockerOCIrunc、kata、gVisor…FraktiKubernetes虚拟化容器hyperd、dockerrktletKubernetes支持 rktrktPouchContainerAlibaba富容器OCIrunc、kata…VirtletMirantis虚拟机和 QCOW2 镜像LibvirtKVM按实现类型展开Docker核心代码保留在 Kubelet 内部的 dockershimpkg/kubelet/dockershim是当时最稳定、特性支持最好的运行时OCI 容器运行时遵循 Open Container Initiative 标准无需 Docker社区有两个实现Containerd支持 Kubernetes v1.7与 CRI-O支持 Kubernetes v1.6支持的 OCI 容器引擎包括runcOCI 标准容器引擎gVisor谷歌开源的基于用户空间内核的沙箱容器引擎Clear ContainersIntel 开源的基于虚拟化的容器引擎Kata Containers基于虚拟化的容器引擎由 Clear Containers 与 runV 合并而来PouchContainer阿里巴巴开源的胖容器引擎Frakti支持 Kubernetes v1.6提供基于 hypervisor 和 docker 的混合运行时适用于运行非可信应用如多租户、NFV场景Rktlet支持 rkt 容器引擎rknetes 代码已在 v1.10 中弃用VirtletMirantis 开源的虚拟机容器引擎直接管理 libvirt 虚拟机镜像须为 qcow2 格式Infranetes直接管理 IaaS 平台虚拟机如 GCE、AWS 等。Containerd从独立组件到内置 CRI 插件以 Containerd 为例其 CRI 接入方式经历了两次形态变化1.0 及以前版本用 cri-containerd containerd 的组合替换 dockershim 与 docker daemon1.1 版本直接将 cri-containerd 内置进 Containerd简化为一个CRI 插件。Containerd 内置的 CRI 插件实现了 Kubelet CRI 接口中的 Image Service 与 Runtime Service通过内部接口管理容器与镜像并通过 CNI 插件为 Pod 配置网络。仓库中 setup/k8s-hard-way/03-compute-resources.md 选择 Ubuntu 20.04 的原因正是其对 containerd 容器引擎有很好的支持而 setup/k8s-hard-way/09-bootstrapping-kubernetes-workers.md 展示了对应的 containerd 配置sudo mkdir -p /etc/containerd/ cat EOF | sudo tee /etc/containerd/config.toml [plugins] [plugins.cri.containerd] snapshotter overlayfs [plugins.cri.containerd.default_runtime] runtime_type io.containerd.runtime.v1.linux runtime_engine /usr/local/bin/runc runtime_root EOF该配置将 containerd 的 CRI 插件默认运行时指向 runcsnapshotter 使用 overlayfs这正是 CRI 插件管理容器与镜像、通过内部接口对接底层 OCI 引擎的落地形态。RuntimeClass同一集群内的多运行时调度RuntimeClass 是 v1.12 引入的新 API 对象用于在同一个集群内支持多种容器运行时。典型场景包括Kata Containers / gVisor 与 runc 混用普通 Pod 用 runc高隔离需求 Pod 用 Kata/gVisorWindows Process isolation 与 Hyper-V isolation containers 混用。在 setup/feature-gates.md 的 Feature Gates 表中RuntimeClass特性在 v1.12 为 Alpha 阶段、默认关闭false。因此使用前需开启特性开关RuntimeClass在相关组件上通过--feature-gatesRuntimeClasstrue开启Frakti 部署中使用的AllAlphatrue也是同类做法见 extension/cri/frakti.md创建 RuntimeClass CRD通过kubectl apply应用 Kubernetes 仓库cluster/addons/runtimeclass/runtimeclass_crd.yaml中的清单。随后即可定义 RuntimeClass 对象。RuntimeClass 属于node.k8s.ioAPI 组、是非命名空间资源apiVersion: node.k8s.io/v1alpha1 # RuntimeClass is defined in the node.k8s.io API group kind: RuntimeClass metadata: name: myclass # The name the RuntimeClass will be referenced by # RuntimeClass is a non-namespaced resource spec: runtimeHandler: myconfiguration # The name of the corresponding CRI configuration而在 Pod 中通过spec.runtimeClassName指定要使用的 RuntimeClassapiVersion: v1 kind: Pod metadata: name: mypod spec: runtimeClassName: myclass # ...调度器会结合 RuntimeClass 与节点上的运行时能力完成调度runtimeHandler需要与容器运行时CRI shim中实际配置的 handler 名称对应。调试与验证crictl 与 critest通常容器引擎都会附带命令行工具帮助调试如 Docker 场景下的docker命令。但在使用其他容器引擎时推荐使用crictl替代docker工具。crictl是 cri-tools 的一部分它提供了类似 docker 的命令行能力不需要经过 Kubelet 就能直接通过 CRI 与容器运行时通信适用于所有实现了 CRI 接口的容器运行时。需要特别注意的边界crictl并非kubectl的替代品它只通过 CRI 与容器运行时通信用于调试与排障并不用于运行生产容器虽然 crictl 也提供运行 Pod 和容器的子命令但这些命令仅推荐用于调试如果在 Kubernetes Node 上用 crictl 创建了新的 Pod它们会被 Kubelet 检测到并停止、删除。cri-tools 还提供了验证工具critest通过运行一系列测试验证容器运行时对 CRI 的实现是否与 Kubelet 的需求一致。官方推荐所有容器运行时在发布前都通过其测试实践中critest常作为容器运行时集成测试的一部分用于保证代码更新不会破坏 CRI 功能。cri-tools 已在 v1.11 版 GA仓库的 setup/index.md 版本依赖表中也列出了 v1.12.0 版本的 crictl。crictl 常用命令实战查询 Pod按名称过滤$ crictl pods --name nginx-65899c769f-wv2gp POD ID CREATED STATE NAME NAMESPACE ATTEMPT 4dccb216c4adb 2 minutes ago Ready nginx-65899c769f-wv2gp default 0Pod 列表$ crictl pods POD ID CREATED STATE NAME NAMESPACE ATTEMPT 926f1b5a1d33a About a minute ago Ready sh-84d7dcf559-4r2gq default 0 4dccb216c4adb About a minute ago Ready nginx-65899c769f-wv2gp default 0 a86316e96fa89 17 hours ago Ready kube-proxy-gblk4 kube-system 0 919630b8f81f1 17 hours ago Ready nvidia-device-plugin-zgbbv kube-system 0镜像列表$ crictl images IMAGE TAG IMAGE ID SIZE busybox latest 8c811b4aec35f 1.15MB k8s-gcrio.azureedge.net/hyperkube-amd64 v1.10.3 e179bbfe5d238 665MB k8s-gcrio.azureedge.net/pause-amd64 3.1 da86e6ba6ca19 742kB nginx latest cd5239a0906a6 109MB容器列表含已退出容器$ crictl ps -a CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT 1f73f2d81bf98 busyboxsha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 7 minutes ago Running sh 1 9c5951df22c78 busyboxsha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47 8 minutes ago Exited sh 0 87d3992f84f74 nginxsha256:d0a8828cccb73397acb0073bf34f4d7d8aa315263f1e7806bf8c55d8ac139d5f 8 minutes ago Running nginx 0 1941fb4da154f k8s-gcrio.azureedge.net/hyperkube-amd64sha256:00d814b1f7763f4ab5be80c58e98140dfc69df107f253d7fdd714b30a714260a 18 hours ago Running kube-proxy 0在容器内执行命令$ crictl exec -i -t 1f73f2d81bf98 ls bin dev etc home proc root sys tmp usr var查看容器日志crictl logs 87d3992f84f74 10.240.0.96 - - [06/Jun/2018:02:45:49 0000] GET / HTTP/1.1 200 612 - curl/7.47.0 - 10.240.0.96 - - [06/Jun/2018:02:45:50 0000] GET / HTTP/1.1 200 612 - curl/7.47.0 - 10.240.0.96 - - [06/Jun/2018:02:45:51 0000] GET / HTTP/1.1 200 612 - curl/7.47.0 -Frakti 实战hypervisor 级别的隔离运行时Frakti 是 Kubelet CRI 的一个运行时实现提供hypervisor 级别的隔离特别适用于运行不可信应用以及多租户场景。它实现了一个混合运行时特权容器以 Docker container 的方式运行普通容器则以 hyper container 的方式运行在虚拟机VM内。Frakti 的完整部署步骤参见 extension/cri/frakti.md仓库还提供了 deploy/frakti/ubuntu.md 与 deploy/frakti/centos.md 两套分平台的集群部署文档。其核心流程可概括为安装 hyperd主容器引擎Ubuntu 下安装qemu libvirt-bin后执行 hyper 官方安装脚本并配置/etc/hyper/configecho -e Kernel/var/lib/hyper/kernel\n\ Initrd/var/lib/hyper/hyper-initrd.img\n\ Hypervisorqemu\n\ StorageDriveroverlay\n\ gRPCHost127.0.0.1:22318 /etc/hyper/config systemctl enable hyperd systemctl restart hyperd安装 docker辅助容器引擎供特权容器使用与frakti二进制并以 systemd 服务方式运行 frakti关键参数包括--listen/var/run/frakti.sockCRI 监听 Socket、--hyper-endpoint127.0.0.1:22318对接 hyperd与--streaming-server-addr%Hstreaming 地址安装 CNI 并配置网络注意 frakti 目前仅支持 bridge 插件且所有机器上 Pod 的子网不能相同例如 master 用10.244.1.0/24、第一个 Node 用10.244.2.0/24集群模式下还需为容器网络配置直接路由配置 Kubelet 使用 frakti 运行时sed -i 2 i\EnvironmentKUBELET_EXTRA_ARGS--container-runtimeremote --container-runtime-endpoint/var/run/frakti.sock --feature-gatesAllAlphatrue /etc/systemd/system/kubelet.service.d/10-kubeadm.conf systemctl daemon-reload初始化集群master 上执行kubeadm init --pod-network-cidr 10.244.0.0/16 --kubernetes-version latest可选移除 master 污点以调度 PodNode 上通过kubeadm join --token $token ${master_ip}加入。Frakti 是理解CRI 运行时如何真正改变容器隔离语义的最佳样例——同一套 Kubelet、同一个 CRI 接口运行时却可以提供从普通容器到完整虚拟机的隔离梯度。小结与延伸阅读CRI 的价值在于把容器引擎的差异封装在接口之后Kubelet 只面向 RuntimeService/ImageService 编程运行时的隔离级别、镜像格式、沙箱技术都可以自由演进。从 v1.5 的初版到 v1.12 的 RuntimeClass再到 cri-tools 的 GAKubernetes 的运行时插件体系已经完整覆盖了接口定义 → 运行时实现 → 集群接入 → 多运行时调度 → 调试验证的全链路。进一步阅读仓库中的相关文档extension/cri/cri-tools.mdcrictl 与 critest 的完整说明与命令示例extension/cri/frakti.md 与 deploy/frakti/ubuntu.md、deploy/frakti/centos.mdFrakti 的 Allinone 与集群部署细节concepts/components/kubelet.mdKubelet 内部组件、Pod 管理流程与 CRI 层的定位setup/feature-gates.mdRuntimeClass 等特性开关的版本与默认值setup/k8s-hard-way/09-bootstrapping-kubernetes-workers.md基于 containerd CRI 的从零搭建实战。赞分享云原生教程【免费下载链接】kubernetes-handbookKubernetes Handbook Kubernetes指南 https://kubernetes.feisky.xyz项目地址https://gitcode.com/gh_mirrors/kub/kubernetes-handbook点击查看免费下载相关推荐Kubernetes 容器运行时接口CRI深度解析架构、接口定义与后端生态Kubernetes 容器运行时接口CRI深度解析架构、接口定义与后端生态 容器运行时接口Container Runtime Interface简称教程云原生容器编排Stable Diffusion WebUI Forge 完整新手指南低显存也能快速跑起 AI 图像生成Stable Diffusion WebUI Forge 完整新手指南低显存也能快速跑起 AI 图像生成 Stable Diffusion WebUI For人工智能大模型媒体生成本地部署深度学习终极笔记本散热解决方案如何用NoteBook FanControl实现智能温控与性能优化终极笔记本散热解决方案如何用NoteBook FanControl实现智能温控与性能优化 你是否曾经在安静的图书馆里被笔记本电脑风扇的突然轰鸣声打断思路或者系统编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考