恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Kubernetes 1.27继续使用Docker运行时:cri-dockerd适配层配置全攻略

  • 首页
  • 资讯中心
  • /
  • Kubernetes 1.27继续使用Docker运行时:cri-dockerd适配层配置全攻略

相关资讯

Python实战:PyQt5 + OpenCV + Dlib 打造AI桌面应用 2026/10/14 2:57:54
简洁美观的值班大屏:轻量前端架构实现运行态决策提效 2026/10/14 2:57:54
安卓IM系统开发实战:WebSocket连接管理与消息可靠性设计 2026/10/14 2:57:54

最新资讯

Agent-Reach:多智能体通信与路由编排基础设施实践
用40年前的航空安全规范,驯服爱说废话的AI代码生成
电商数据对接实战:类目树解析与商品榜单接口调用的踩坑指南
隐马尔可夫模型在金融量化分析中的应用与实践
指针网络+DRL解TSP:端到端学习城市访问序列
纯手绘背景的底层逻辑:从物理媒介到视觉意图

今日推荐

IBM Verify Identity Access 修复 22 个漏洞:两个 9.8 严重 RCE 无需认证
小区物业管理系统
小型超市仓库管理系统

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Kubernetes 1.27继续使用Docker运行时:cri-dockerd适配层配置全攻略

发布时间:2026/10/14 2:57:54
Kubernetes 1.27继续使用Docker运行时:cri-dockerd适配层配置全攻略 从Kubernetes 1.20宣布废弃dockershim开始社区里就一直有个争论K8s以后到底还能不能用Docker到了1.27版本答案其实已经很明确——能但前提是把路子走对。kubelet不再直接认识Docker的socket想让集群继续用Docker作为运行时中间必须加一个适配层。这篇笔记记录的是我当时把一套1.27集群从默认的containerd切到Docker runtime的完整过程包括为什么要加cri-dockerd、kubeadm init的cri-socket应该怎么写以及配完之后怎么验证它真的生效了。如果你正好在纠结新集群用哪种运行时或者想把老集群迁到1.27继续保留docker命令习惯这篇应该对你很有用。1. Kubernetes 1.27的docker runtime链路到底长什么样1.1 从dockershim移除说起很多人一听到Kubernetes移除dockershim就以为K8s不再支持Docker这个理解是偏的。准确说法是kubelet不再内置那一段专门对接Docker的桥接代码。早期Kubernetes为了跑起来在kubelet里直接嵌了一块叫dockershim的转换模块它把kubelet发出的CRI请求翻译成Docker API这样K8s就能用Docker来创建容器。这个设计解决了当时容器运行时生态贫瘠的问题但代价是kubelet和Docker的版本耦合太紧。后来CNCF生态里出现了更纯粹的容器运行时CRI规范也成熟了Kubernetes从1.20宣布废弃dockershim1.24正式删除到1.27这个版本kubelet已经完全不再内置它对Docker的兼容层。那1.27想继续用Docker怎么办答案是cri-dockerd。这是一个独立进程专门把CRI请求翻译成Docker API它替代了当年dockershim的位置只不过从内嵌代码变成了外部服务。理解这件事的关键在于CRI是一个接口规范它不是某个具体软件任何进程只要实现了这套接口kubelet就能让它来管容器。cri-dockerd就是这样一个外部实现。拿生活中的情况类比CRI就像墙上的标准插座kubelet只会插标准插头dockershim是当年为了把一个不符合标准的旧插头强行插进去而做的转接器cri-dockerd则是后来重新做的、更规范的新转接器。你最终还是能点亮Docker这盏灯只不过中间多了一段转接。1.2 Docker和containerd的从属关系还有一个很常见的误解就是把Docker runtime和containerd当成完全对立的两条路线。实际上Docker Engine本身是分层的最上面的docker CLI是给人敲命令用的dockerd负责管理镜像、网络、卷、构建这些上层能力再往下dockerd也依赖containerd来真正管理容器生命周期最底层是runc这类OCI运行时去启动进程。所以在用Docker runtime的架构里完整链路是这样的kubelet - (CRI) - cri-dockerd - (Docker API) - dockerd - containerd - runc也就是说即使你走Docker这条路底层最终还是会落到containerd和runc。这一点想通了很多后续选型就不会纠结了——用Docker runtime多出来的开销主要是cri-dockerd和dockerd这两个进程的常驻资源容器本身执行效率并不会因为多包了一层而明显下降毕竟最终干活的还是同一套底层。网上那些K8s不支持Docker了的说法准确讲应该是Kubernetes不再内置dockershim而Docker作为CRI运行时在1.27里完全还能用只是需要把cri-dockerd这个适配层部署好。这也是我写这篇笔记的核心前提。2. 环境准备内核、cgroup驱动和cri-dockerd部署2.1 先把节点的底子打好不管你的节点以后跑containerd还是Docker有些系统层面的准备是绕不开的。我这边统一用Debian系的节点做演示RHEL系的思路一样就是包管理器命令不同。先确认几件事CPU至少2核、内存至少2GB磁盘留20GB以上。主机名、MAC地址、product_uuid都要保证唯一尤其是多节点实验环境直接克隆虚拟机出来的节点很容易踩这个坑。swap必须关掉kubeadm在初始化时会检查只要swapon开着就直接报错中断。内核模块和网络转发参数也需要提前配好。容器网络和iptables转发都依赖这些内核特性尤其是Calico、Flannel这类网络插件如果br_netfilter没加载Pod之间通信经常表现为时好时坏非常难查。建议直接这样配cat EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfiltercat EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sudo sysctl --system这些参数不是玄学它们决定了Kubernetes节点上的Pod流量能不能被iptables规则正确处理。漏掉br_netfilter的话桥接流量会绕过netfilter网络策略和Service转发就可能失效。2.2 Docker的cgroup驱动必须和Kubelet对齐节点基础环境准备好之后安装Docker。这里有一个特别容易被忽略的点cgroup驱动。Docker的默认cgroup驱动是cgroupfs而Kubernetes从1.24开始默认推荐、并且kubelet几乎总是以systemd驱动运行。两者不一致时kubelet启动日志里会明确报错连节点注册都完不成。这个坑我见过太多次了而且报错信息写得非常直白kubelet cgroup driver: systemd is different from docker cgroup driver: cgroupfs解决方式是在安装完Docker后立刻写一个daemon.json并重启dockerd{ exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m } }sudo systemctl daemon-reload sudo systemctl restart docker docker info | grep -i cgroup看到Systemd就说明改好了。另外容器日志建议加上max-size限制不然后台跑几个打印狂魔容器能把你磁盘写满。这一步不提前做后面初始化集群必然要折返。2.3 下载并部署cri-dockerdcri-dockerd作为适配层是整条链路里的关键部件。它的release包里自带二进制和systemd配置下载时要注意版本和Kubernetes 1.27配套一般选0.3.x的最新发行版即可太老的版本不支持CRI v1协议后面会踩到CRI v1 runtime API is not implemented这类错。解压后把cri-dockerd二进制放到/usr/local/bin然后准备systemd service。release包里自带的unit配置可以直接用但为了讲清楚进程参数我这里给一个精简版本[Unit] DescriptionCRI Docker Afterdocker.service [Service] ExecStart/usr/local/bin/cri-dockerd \ --network-plugincni \ --pod-infra-container-imageregistry.k8s.io/pause:3.9 Restartalways RestartSec10 [Install] WantedBymulti-user.target有两个参数值得单独说明。--pod-infra-container-image指定的是每个Pod里那个pause沙箱容器的镜像。如果节点所在网络访问官方镜像仓库不顺畅这里可以改成你们内部仓库里的pause:3.9路径不然Pod会一直卡在ContainerCreating。--network-plugincni则让cri-dockerd把网络配置交给CNI插件去处理这和Kubernetes节点上需要先装好CNI二进制是一个道理。配置好后启动并确认socket文件存在sudo systemctl daemon-reload sudo systemctl enable --now cri-docker ls -l /var/run/cri-dockerd.sock看到socket文件生成适配层就算起来了。后面kubelet、crictl都是通过这个socket和cri-dockerd通信。3. kubeadm init与节点加入cri-socket参数不能偷懒3.1 控制平面初始化一切就绪后用kubeadm初始化控制平面。这里最核心的一个参数就是--cri-socket它直接告诉kubeadm你该用哪个运行时接口。sudo kubeadm init \ --kubernetes-versionv1.27.x \ --cri-socketunix:///var/run/cri-dockerd.sock \ --pod-network-cidr10.244.0.0/16为什么我不依赖kubeadm的自动探测因为如果节点上同时存在containerd.sock和cri-dockerd.sock自动探测的结果不确定可能选到默认的containerd路径那你这套Docker runtime就白配了。显式指定让结果可控。这里补充一句--pod-network-cidr要和你后面选的网络插件匹配比如Flannel对应10.244.0.0/16Calico则根据它的配置来决定。这个CIDR不直接影响runtime但写错了网络插件会起不来。init成功后会输出一串重要信息包括kubeconfig路径、join命令和token。把admin.conf拷到本地让kubectl可以管理集群mkdir -p $HOME/.kube sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config然后安装网络插件。我习惯用Calico直接apply它对应的manifest即可。很多新手在这时候发现master节点一直NotReady就去查kubelet日志查半天发现其实是网络插件没装。节点状态要从NotReady变Ready必须等CNI就绪。3.2 worker节点加入时也别忘了cri-socket控制平面起来后worker节点加入时有个非常容易犯的低级错误join命令里不带--cri-socket。sudo kubeadm join 192.168.x.x:6443 \ --token token \ --discovery-token-ca-cert-hash sha256:hash \ --cri-socket unix:///var/run/cri-dockerd.sock如果不带这个参数kubeadm会用默认的containerd socket去探测runtime。结果就是节点确实join进去了但状态一直NotReadykubelet日志里反复报连不上containerd。我自己调试时遇到过这个问题第一反应是去查kubelet配置后来才发现是join命令少了个参数属于配置层面的粗心但排查起来极其耗费时间。3.3 kubelet的兜底配置虽说init和join时指定了cri-socket但有些场景下你还得手动确认kubelet的启动参数。kubeadm生成的kubelet配置主要在/var/lib/kubelet/kubeadm-flags.env里KUBELET_KUBEADM_ARGS--container-runtime-endpointunix:///var/run/cri-dockerd.sock --container-runtimeremote如果这里不是cri-dockerd的socket路径就会出现节点注册了但runtime状态对不上的情况。改完这个文件后一定要执行sudo systemctl daemon-reload sudo systemctl restart kubeletkubeadm升级版本时经常会重写这个文件所以升级完集群最好顺手检查一遍这是我从一次升级事故里总结出的经验。4. 验证runtime生效从kubectl到crictl到真实故障表4.1 kubectl视角第一层确认配置完所有节点后先别急着跑应用先确认runtime到底有没有生效。最直接的就是看节点信息kubectl get nodes -o wide输出结果里有一列CONTAINER-RUNTIME如果你的链路没问题这里显示的是类似docker://24.0.7的信息前缀是docker就说明kubelet确实通过cri-dockerd在跟Docker通信。如果想看更详细的信息可以describe节点kubectl describe node node-name | grep -i Container Runtime Version看到docker版本号说明节点上报给控制面的runtime元数据也是对的。这里还要解释一个细节kubectl层面看到的是kubelet上报的runtime字符串它不一定代表所有容器都在用Docker管理但至少说明CRI链路里cri-dockerd是通的。真正要验证容器层还得看下一层工具。4.2 crictl和docker的对照二层确认crictl是CRI标准的命令行工具它不关心底层是containerd还是Docker只关心你配置的runtime-endpoint。在这个架构里crictl应该指向cri-dockerd的socketsudo crictl config --set \ runtime-endpointunix:///var/run/cri-dockerd.sock \ --set image-endpointunix:///var/run/cri-dockerd.sock配置完后跑一下crictl info能看到runtime类型和版本。再随手拉一个测试镜像分别用crictl和docker看容器sudo crictl ps sudo docker ps你会发现crictl列出的容器在docker ps里也能看到只是名字不太一样。这是因为cri-dockerd把CRI容器翻译成了Docker容器底层是同一批进程。我自己做这个验证时同时跑这两个命令的感觉就像在对照同一份数据的两种展示形式。反过来如果crictl配置错了地址比如指向docker.sock就会报CRI runtime is not supported因为Docker本身并不直接对外提供CRI接口。4.3 实测踩过的坑一张故障排查对照表这一路下来我把几个高频故障整理成了一张表后面遇到类似报错可以直接对照现象根因处理方式kubelet启动报cgroup driver不一致Docker的cgroup驱动还是cgroupfs改daemon.json设为systemd并重启dockerdCRI v1 runtime API is not implementedcri-dockerd版本太老升级到支持CRI v1的0.3.x版本Pod一直ContainerCreating日志报拉取pause镜像失败pause:3.9镜像源不可达将cri-dockerd的--pod-infra-container-image指向内部仓库节点NotReadykubelet连不上/var/run/containerd/containerd.sockjoin或kubelet配置未指定cri-dockerd的socket在kubeadm-flags.env里改endpoint并重启kubeletdocker ps能看到容器kubectl查不到Podcri-dockerd进程没被systemd托管后自启检查cri-docker.service状态并enable这张表看起来很简单但每一条背后都对应着至少半小时的排查时间。尤其是第一条cgroup驱动不一致报错信息很吓人实际改动却很小就一行JSON配置的事。5. 1.27下继续用还是换containerd聊聊我的选型参考5.1 两种方案的真实差异整套Docker runtime配好之后我用了一段时间也拿它和containerd做过实际对比。这里不吹不黑只说客观差异维度Docker runtimecri-dockerdcontainerd原生CRI组件数量kubelet cri-dockerd dockerd containerdkubelet containerd常驻内存占用多约200-300MB相对更省命令行习惯可继续用docker exec/logs/ps需用crictl/ctr命令风格不同镜像管理方式dockerd负责镜像层docker images查看crictl images工具链更朴素排查日志便利性所有容器都能用docker logs直观crictl logs也能用但输出格式更克制从性能上看两者容器吞吐差距很小因为Docker底层同样依赖containerd。真正拉开差距的是运维习惯和组件数量。如果你所在团队的脚本里全是docker命令迁移到containerd意味着所有自动化工具都要重写一遍那用cri-dockerd过渡是完全合理的选择。5.2 我的建议与一个小技巧落到具体场景我的建议是这样的如果你是要新建一个干净集群没有历史包袱直接上containerd。它是Kubernetes的默认路径文档、CNI插件、监控组件默认适配都是往这条路靠的少一层适配器就少一个排查维度。如果是为了升级老集群到1.27而节点上跑了一堆依赖docker命令的运维脚本那保Docker runtime比较省事关键是把cri-dockerd的systemd服务设好别让它在节点重启后掉链子。如果只是测试学习环境我反而推荐用cri-dockerd。因为docker ps看到的东西更直观初学者对着docker命令行理解K8s的容器模型会容易很多跑完想知道Pod里的容器在宿主机上长什么样一条docker ps就看见了。最后分享一个我实际用下来的小技巧不管你选哪种runtime都建议在节点上装好crictl并把runtime-endpoint指向正在使用的socket。因为crictl看的是CRI真实状态它的视角和kubelet几乎一致。而docker命令行看到的部分信息比如容器名和暂停容器之间的关系有时候反而会让人误解CRI层的逻辑。遇到调度异常需要定位时crictl ps -a的输出往往比docker ps更有参考价值。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号