Pod卡在ContainerCreating?从容器运行时到Rancher多集群管理一次讲透

发布时间:2026/9/26 17:09:31
Pod卡在ContainerCreating?从容器运行时到Rancher多集群管理一次讲透 去年接过一个朋友的求助他照着教程用kubeadm搭了一套K8s集群往里部署Prometheus的时候Pod一直卡在ContainerCreating日志狂刷failed to create pod sandbox: rpc error: code Unknown desc failed to create containerd task。他搜了一整晚把网上能查的帖子都翻遍了还是没搞明白到底是containerd的问题、CNI插件的问题还是某个配置文件写错了。说实话这类问题我见过太多次它的难点不在于命令有多复杂而在于大多数人只熟悉K8s的表层操作根本不了解Pod从kubelet下发指令到容器真正跑起来中间到底经历了什么。这篇我会把整条链路串起来讲清楚先拆透Pod这个K8s的最小调度单元再讲Deployment等控制器如何支撑业务然后落到集群级别的高可用、证书续签、GPU、Prometheus监控这些实战刚需最后用Rancher把多集群管理的落地方式完整演示一遍。内容全部是真实部署和排障过程中验证过的方案适合正在学K8s的运维、被Pod故障折磨的开发者以及打算用Rancher统一管理多个集群的团队。1. Pod核心原理K8s一切管理的基础1.1 为什么K8s偏偏把Pod作为最小调度单元在K8s还没成为主流之前Docker把容器定义为最小单位一个容器跑一个进程docker run一把梭就完事。真到了生产环境问题就暴露了很多服务根本不是孤立进程Web服务旁边必须跟一个日志采集器API服务加一个指标上报的边车sidecar容器这两个进程要共享网络栈最好还能访问同一份数据卷。如果以容器为单位去调度这些绑定关系很难表达很可能你前一秒把日志采集器调度到另一台机器后一秒它就够不着日志文件了。Docker Compose虽然能用但它本质上只解决单机本地编排没有跨节点的全局调度能力。K8s正是在这个背景下设计了Pod一组紧密协作的容器共享同一生命周期、同一网络命名空间、同一组存储卷永远被调度到同一个节点上。这里有个关键实现真正持有网络命名空间的不是业务容器而是一个叫pause的infra容器。它极其轻量启动时先占住Network Namespace、UTS、IPC这些内核资源业务容器再逐个加入它的命名空间。这就是为什么你在GPU节点上用crictl ps会看到一堆名字里带pause的容器。打个比方Pod是一张饭桌pause容器是那张桌板业务容器是围坐的人大家共享桌面可以递菜但每个人手中的餐具和口味是独立的。理解了这个底层依赖后面很多排障思路就通了如果Pod的沙箱创建失败一定是pause容器在创建过程中出问题那问题范围就锁定在kubelet、containerd、runc、CNI这几层而不是业务容器本身的代码。1.2 Pod的生命周期与探针机制Pod的状态有Pending、ContainerCreating、Running、Succeeded、Failed还有一个让新手闻风丧胆的CrashLoopBackOff。Pending阶段意味着调度还没完成或者镜像还在拉取如果你看到Pod一直Pending多半是节点资源不足、节点亲和性约束不满足或者PVC没绑定成功。我个人很少去背状态定义而是习惯直接kubectl describe pod xxx看事件再结合kubectl get events的时间线问题一般就清楚了。探针这块值得单独说。K8s提供三种探针livenessProbe决定容器要不要重启readinessProbe决定服务是否接入流量startupProbe专门解决慢启动容器的误杀问题。最典型的案例是Java服务启动需要两分钟如果你只配了liveness探针容器在启动过程中CPU稍高、迟迟没有监听端口探针失败几次后就会被杀掉重建然后进入无限重启循环。正确做法是先配一个startupProbe给它一个宽松的宽限期等主进程真正ready之后再把liveness和readiness接管过来。我自己的排查习惯是直接看Pod的YAML里status.containerStatuses字段里面的State和LastTerminationState信息非常直白比反复翻日志更快。1.3 K8s和Docker到底有什么区别这个问题在热词里反复出现也是很多新手最纠结的地方。把K8s和Docker当成二选一本身就理解错了。Docker是容器运行时解决的是单个容器怎么创建、怎么跑K8s是容器编排系统解决的是成百上千个容器怎么协同、调度、扩缩容、自愈。更准确地说Docker只是K8s可选的运行时之一。K8s与运行时之间隔着一层CRIContainer Runtime Interfacecontainerd、CRI-O、Kata Containers都能接进来。从K8s 1.24开始kubelet移除了内嵌的dockershim生产环境几乎默认走containerd。所以别再问为什么我Docker都起不来K8s也崩了——很可能Docker本身没问题而是你用旧工具链去排查新架构的故障。如果只是在本机跑个MySQL调试代码甚至不需要K8s一条docker run就够了。但如果你要管理几十台主机、上千个容器靠手工敲Docker命令注定会崩溃你需要K8s这个调度大脑。理解这个边界你就知道什么场景该上K8s什么场景别硬上。2. 工作负载与控制器从单一Pod到业务集群2.1 Deployment为什么不能直接裸用Pod很多人刚开始学K8s时习惯kubectl run或手动创建一个Pod形态上挺像那么回事但生产环境没人这么干。裸Pod没有自愈能力被误删就是没了节点宕机也不会自动在别处重建。Deployment的出现就是为了解决这个问题。从结构上看Deployment管着ReplicaSetReplicaSet负责拉起指定数量的Pod副本。一旦某个Pod挂了ReplicaSet会立刻重新调度一个出来保证我想要的副本数永远达标。Deployment真正的价值在于它还支撑滚动更新和回滚你可以平滑地把镜像从v1切到v2出问题再秒级回滚这是裸Pod完全做不到的。热词里有个特别有意思的提问如果给K8s Deployment一个中文名字是什么我理解最贴切的叫法是副本管家或者发布指挥。它每天操心两件事一是副本数量对不对二是应用版本要不要换。来一个能直接用的Deployment YAML示例apiVersion: apps/v1 kind: Deployment metadata: name: nginx-demo spec: replicas: 3 selector: matchLabels: app: nginx-demo template: metadata: labels: app: nginx-demo spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 200m memory: 256Mi注意我特意写了resources字段。不给limits的Pod在生产环境就像脱缰野马一个内存泄漏的死循环就能把整台节点吃垮很多节点突然NotReady的事故就是这么来的。2.2 控制器家族怎么选StatefulSet、DaemonSet、JobDeployment不是万能的。如果你的应用有状态比如数据库主从、消息队列每个Pod需要稳定的网络标识和独立的存储卷那Deployment不适合要选StatefulSet。StatefulSet会给Pod分配web-0、web-1这类带序号的名称PVC跟着实例走重启后身份不乱。如果需要在每个节点上固定跑一个Pod比如日志采集的Filebeat/Fluentd、节点监控的node-exporter、网络插件Calico的Felix这是DaemonSet的活。DaemonSet保证只要节点匹配条件就一定有一个Pod在跑节点多了就自动扩节点下线就自动清。Job和CronJob则是为一次性任务准备的跑完就退出适合做批量计算、数据迁移、定时备份。选型其实不难记住一条主线无状态服务优先Deployment有状态上StatefulSet节点级组件用DaemonSet任务类用Job/CronJob。有次我接手一个项目开发坚持把Web应用做成StatefulSet理由是老项目一直这么干的。结果扩容时每个Pod都要等PVC挂载速度非常慢还经常卡在ContainerCreating。我给他换成Deployment加共享存储配合会话保持中间件问题直接消失。理解每种控制器的设计初衷比背一堆命令有用得多。2.3 ConfigMap与Deployment配套把配置从镜像里解放出来传统部署方式喜欢把配置文件写进镜像改一个参数就要重新build、push、pull循环往复又慢又容易出错。ConfigMap就是为此设计的把配置文件从镜像中分离通过环境变量或挂载卷方式注入Pod。这样镜像可以保持不变配置随时调整。两种注入方式的区别值得注意环境变量方式适合少量变量但Pod启动后修改ConfigMap不会自动更新容器内的环境变量volume挂载方式适合整个配置文件比如nginx.conf、application.yml整体挂载到指定路径修改ConfigMap后文件会在几秒内同步但很多应用并不会热加载仍然需要重启进程。这里有个实战技巧想让ConfigMap变更自动触发滚动更新可以在Deployment的模板里加一个注解比如kubectl patch deployment xxx -p {spec:{template:{metadata:{annotations:{config-version:20250101}}}}}相当于骗过控制器触发一次滚动发布这是很多团队采用的通用方案。坑也很常见Pod启动报CreateContainerConfigError一大半原因是引用了不存在的ConfigMap或Secret key看Event基本一目了然。顺便提醒一句Secret里的Base64编码只算混淆、不算加密真正的数据库密码等敏感信息别直接放git仓库优先考虑KMS或Vault。2.4 支撑高并发的组件Service、Ingress、HPA热词里有人问k8s用于处理高并发的组件这个问题可以一次讲透。K8s应对高并发不是靠单个组件而是靠一条链路配合Service提供稳定的虚拟IP和DNS名字后端Pod挂了自动摘除Ingress作为七层入口把域名和路径路由到不同Service是流量收敛的第一站HPAHorizontalPodAutoscaler根据CPU、内存或自定义指标自动伸缩Pod副本数ClusterAutoscaler在节点层面伸缩Pod排队时自动加机器。想象一个大促场景用户流量从Ingress进来转发到ServiceService把负载分摊到多个Pod上。QPS突然飙升HPA监测到Pod CPU升高自动把副本从3个拉到20个节点资源不够ClusterAutoscaler再拉起新节点流量回落后再回收资源。这套机制是K8s处理高并发的底气所在。我在裸机上搭集群的一个经验是如果没提前配好metrics-server和HPA大促时你只能手动kubectl scale deployment xxx --replicas50手速再快也跟不上流量爬坡速度。自动化伸缩才是集群应对高并发的正确姿势。3. 集群实战高可用、证书、GPU、监控3.1 三台Master怎么保证高可用热词里k8s三台master怎么保证高可用被搜了很多次不少人的误区是只要起3个master节点就算高可用了。实际上kube-apiserver本身是无状态服务真正决定集群可用性的是etcd。etcd是强一致的分布式存储至少需要3个节点形成多数派quorum是2也就是说3个etcd成员最多只能容忍1个故障。生产环境通常的做法分两类一类是自建在三台Master前置一个负载均衡VIP常用HAProxy加Keepalived组合也可以用kube-vip这种轻量方案所有组件包括kubelet、kubectl、controller-manager、scheduler都指向这个VIP。另一类是用安装工具省心比如热词里提到的KubeKey它自动编排三个控制面节点、内置负载均衡非常适合Ubuntu环境SealOS也是一键安装的选项适合快速实验。实操时的关键点是第一个master执行kubeadm init剩下两个master用kubeadm join --control-plane加入同时带着etcd一起初始化。如果三个master都在同一个机房VIP方案就够用跨机房的多地域容灾是另一个话题复杂度高不少。另外提醒一句单节点控制面不叫高可用把etcd和数据盘放在同一块SSD也是隐患故障域一旦重合宕机就是雪崩。我个人的建议是如果团队没有专门的运维同事来维护HAProxy和Keepalived直接用KubeKey这类工具反而更稳它把负载均衡、证书、初始化流程都封装成了一套成熟逻辑后面再接Rancher也很顺。3.2 集群证书过期自动续签kubeadm默认签发的证书有效期是一年很多K8s集群都有一年之痒第13个月临近时证书突然过期组件之间互相认证失败集群全面告警。排查时用一条命令就能看到每张证书的剩余时间kubeadm certs check-expiration处理方案有很多种最直接的手动续签步骤是kubeadm certs renew all kubeadm init phase kubeconfig admin --config /etc/kubernetes/kubeadm.yaml systemctl restart kubelet这里有个特别容易踩的坑证书renew之后本地~/.kube/config里的admin证书还是旧的直接用kubectl会一直报Unauthorized必须重新生成admin.conf并替换本地配置。手工操作不放心的话可以把这三条命令写进crontab比如每月1号凌晨执行一次注意续签完成后重启kubelet保证端到端链路使用新证书。更自动化的方式是利用kubelet证书轮换client证书默认会轮换server证书需要手动开启rotateCertificates和serverTLSBootstrap同时配合kube-controller-manager的CSR批准控制器否则每个节点会积压大量Pending状态的CSR。我的建议是证书续签必须写进运维SOP别抱侥幸心理。集群监控里加一个证书到期时间检查项比等到宕机再抢救省心得多。3.3 K8s如何调用GPU机器学习和模型推理场景需要把GPU挂进容器但K8s本身不认识NVIDIA的GPU。它背后依赖的是Device Plugin机制以DaemonSet形式跑在每个GPU节点上向kubelet上报这台机器有4张卡调度器看到资源后才会把Pod分配过来。部署路径大致是这样先在GPU节点上装好NVIDIA驱动然后配置容器运行时使用nvidia-container-runtime。注意以containerd为主力运行时的集群光有驱动还不够runtime层不认识GPU设备的话Pod照样起不来。接下来部署NVIDIA Device Plugin然后在Pod的resources里声明nvidia.com/gpu: 1并视运行时配置加上对应的runtimeClassName。现在更推荐直接用NVIDIA GPU Operator它把驱动、runtime、device plugin、监控一次性编排到位大幅减少手工配置。常见的坑有三个Pod一直Pending先去检查节点上有没有上报nvidia.com/gpu资源报failed to detect nvidia driver version说明驱动与运行时版本不匹配GPU请求数量目前只能是整数写不了0.5。服务如果要做GPU分片那是MIGMulti-Instance GPU的进阶玩法这里先不展开。3.4 部署Prometheus监控K8s集群热词里高频出现k8s部署prometheus和部署prometheus监控k8s说明监控需求非常硬。Prometheus监控K8s主要分四类目标节点指标用node-exporter采集CPU、内存、磁盘、网络K8s对象状态用kube-state-metrics采集Deployment副本数、Pod状态、PVC用量容器运行指标由kubelet内置的cAdvisor暴露Prometheus直接抓container_cpu_usage_seconds_total这类指标控制平面指标包括kube-apiserver、kube-controller-manager、kube-scheduler和etcd。社区现在最主流的部署方式是直接用kube-prometheus-stack这个Helm Chart它把Prometheus、Grafana、AlertManager、node-exporter、kube-state-metrics、ServiceMonitor和告警规则全部打包在一起不用再一个个组件拼装helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update kubectl create namespace monitoring helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack -n monitoring --set grafana.adminPasswordAdmin123 --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage100Gi安装完后把Grafana的Service改成NodePort或配Ingress就能看到整套默认Dashboard。踩坑方面默认Prometheus的数据目录是emptyDirPod一重启监控历史全部清零生产环境必须挂PVC。另外kube-prometheus-stack的版本和K8s版本有兼容矩阵别拿最新版往老集群硬塞。如果只是想快速看指标先跑通抓取目标和告警规则再慢慢加复杂规则也不迟。4. Rancher实战把K8s集群管理从命令行拉回可视化4.1 为什么还是需要一个Rancher原生K8s操作再熟练当手上管着三个集群、每个集群几百个工作负载时终端的效率还是会到瓶颈。Rancher的出现就是为解决这个问题它本质上是跑在K8s之上的管理平台核心能力包括多集群统一入口、可视化工作负载、项目级权限体系、应用商店与Fleet GitOps、内建Prometheus加Grafana监控。它不是K8s的替代品而是K8s的控制台底层用的仍然是原生API。这里要和Portainer区分一下Portainer偏轻量容器管理Docker场景更顺手Rancher是面向K8s舰队管理的重量级平台适合同时管多个K8s集群的团队。哪个场景选择哪个工具主要是看集群规模和协作复杂度。4.2 部署Rancher Server的两种方式生产环境推荐把Rancher跑在一个高可用的K8s集群上通过Helm安装helm repo add rancher-stable https://releases.rancher.com/server-charts/stable helm repo update kubectl create namespace cattle-system helm install rancher rancher-stable/rancher --namespace cattle-system --set hostnamerancher.example.com --set replicas3 --set bootstrapPasswordAdmin123 kubectl -n cattle-system rollout status deploy/rancher这里有个细节hostname必须是你之后能访问的域名尽量绑定正式域名生产环境不要直接用IP裸跑。部署完成后浏览器访问域名初始化admin密码时确认server-url这个值要和hostname保持一致否则后续agent连不上。快速体验的场景可以直接用Docker单容器方式docker run -d --name rancher --restartunless-stopped -p 80:80 -p 443:443 --privileged rancher/rancher:stable这种方式适合本地学习数据都存在容器里换机器就没了别拿它承担生产任务。4.3 通过Rancher导入已有集群Rancher最有价值的功能之一就是把现存K8s集群纳入管控。整个流程并不复杂先在Rancher UI进入集群管理、选择导入已有集群给集群起个名字接着Rancher会生成一段kubectl apply命令里面带着导入token最后在目标集群上执行这段命令即可。命令执行后Rancher会往该集群部署cattle-cluster-agent这个agent负责与Rancher Server通过wss协议保持长连接通信。验证是否成功就回到Rancher UI看集群状态一般从Provisioning变成Active就代表导入完成。我在多个混合云环境里的实操心得是导入前务必确认网络连通性。如果Rancher Server和下游集群不在同一网络必须提前做反向代理或内网隧道不然集群状态会一直Pendingagent日志全是connection refused。导入成功之后节点状态、工作负载、事件、监控都聚合在同一个界面上日常排查效率比ssh一台台登节点高一个量级。4.4 Rancher日常工作流与几个关键避坑我使用Rancher的标准工作流是进入项目与命名空间选择目标项目在工作负载页面创建Deployment填写镜像、环境变量、资源限制然后创建Service和Ingress配置域名和证书最后在监控页面查看Pod指标和告警。整个流程全部可视化完成对团队里不那么熟悉命令行的同事特别友好。但Rancher也有几个关键坑要避开。第一Rancher Server所在集群在UI里叫local集群尽量不要把业务应用部署到里面。一旦local集群挂了Rancher控制台也跟着挂最终还得靠kubectl应急就失去了可视化管理的目的。第二Rancher版本和下游K8s版本要查官方兼容矩阵我见过太多升级完Rancher下游集群全部Disconnected的事故都是没有先确认版本匹配。第三证书问题Rancher自签名证书有效期较长但如果你接入了企业CA必须保证证书链完整否则UI访问会一直报不安全。第四数据备份不能省Rancher本身提供backup-restore-operator配合对象存储做定期备份下游集群更关键的是etcd快照必须做而且最好异地保存。5. 高频排障与常用命令5.1 failed to create pod sandbox完整排查链路这个报错在热词里被大量搜索值得单独深入拆解。它的完整形态通常是failed to create pod sandbox: rpc error: code Unknown desc failed to create containerd task: failed to create shim task很多新手以为这是K8s代码层面的报错实际上是整条链路问题在kubelet层的统一呈现前半段发生在kubelet与containerd之间的CRI调用后半段发生在containerd调用runc创建沙箱进程。链路里任何一环出问题最终都会包装成这么一句话。我的排查顺序固定是先确认容器运行时本身健康执行systemctl status containerd看进程和socket是否正常。接着用crictl而不是docker CLI跑crictl ps -a和crictl inspect containerId。再往后翻kubelet日志最后几十行journalctl -u kubelet -n 100。同时检查节点磁盘和inodedf -h和df -i磁盘满、inode耗尽这类问题会伪装成沙箱创建失败因为runc需要写临时目录。然后验证CNI网络插件查看/etc/cni/net.d下有没有配置确认calico或flannel的Pod是否Running网络插件异常时沙箱的网络命名空间也起不来。最后如果错误信息里带permission denied去查SELinux和AppArmor有没有拦截runc写操作。几个典型case备忘failed to start shim: ... permission denied多半是SELinux或安全上下文问题exec: runc: executable file not found说明runc被删了或版本不匹配需要重装运行时相关组件no such file or directory可能是CNI配置目录或临时目录缺失尝试重建/var/lib/cni/networks。删除Pod重建后恢复说明是临时状态残留但别把这个当常态必须追根因。这类问题最好的预防方式是升级到稳定版containerd并做好节点磁盘监控。5.2 高频命令速查表日常最常用的K8s命令分类整理成一份清单给你集群状态kubectl get nodes -o wide、kubectl cluster-info、kubectl get cs工作负载kubectl get pods -A -o wide、kubectl describe pod name、kubectl logs -f pod container、kubectl exec -it pod -- bash事件排查kubectl get events --sort-by.lastTimestamp资源列表kubectl api-resources切换NSkubectl config set-context --current --namespacens另外分享一个小技巧快速浏览Pod列表时可以用自定义列格式kubectl get pod -o custom-columnsNAME:.metadata.name,IP:.status.podIP,NODE:.spec.nodeName,STATUS:.status.phase这条命令在排查Pod分散情况时会比默认输出直观很多。5.3 三个值得记住的小经验关于如果给K8s Deployment一个中文名字这个热词其实很多企业都希望用中文命名资源但K8s资源名字本身只支持小写字母、数字和中横线直接写中文会被拒绝。如果想在界面上显示友好名称靠Rancher的项目名和标签体系就能实现底层标识符还是保持英文更稳妥。集群里一定要约定所有工作负载都写清requests和limits不给limits的Pod等于裸奔一个异常流量就能把整节点拖垮。学习路径上《K8s权威指南》这类书适合通读原理但命令行和实战必须亲手敲一遍。书建议买正版别迷信pdf下载这类捷径一个更好的做法是遇到问题直接查官方文档加kubectl help再结合自己集群的真实状态去验证这样建立的记忆最深。最后分享一个我保持了很多年的习惯碰到K8s的诡异问题第一件事不是翻搜索引擎而是按runtime链路走一遍用crictl确认容器运行时状态再配合kubectl get events --sort-by.lastTimestamp看时间线。因为容器世界的问题很少只有一个根因往往是一条链路上多个节点同时退化。理解了Pod从pause容器到runc创建沙箱的完整过程再用Rancher把多集群入口收拢起来K8s这个领域的所谓复杂其实很快就能变成肌肉记忆。希望这篇能把你的踩坑时间压缩一点下次再看到failed to create pod sandbox至少知道该先敲哪条命令。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询