
1. 为什么我在生产环境里最终选了 Rancher这个系列写到第五篇前面几篇我们把集群怎么搭、kubectl 怎么用、Service 有哪些类型、Ingress 怎么配都过了一遍。按道理说命令行玩得转集群也能跑起来是不是就够了如果你是自己学习、只有一两套环境那确实够了。但一旦你手上有三套、五套集群或者要交给团队里其他同事一起维护天天靠 kubectl 在黑窗口里敲命令效率会变得很难看。我印象特别深的一件事情有一年我们测试环境同时跑着 dev、staging 两套集群另外还有一套给数据分析团队临时申请的小集群。每次有人要部署一个服务我就得在终端里先切 kubeconfig 上下文再检查节点状态再看 namespace然后才是 apply yaml。操作本身不难但特别琐碎而且不同成员之间沟通成本很高经常出现我这个应用怎么起不来你帮我看看是不是资源不够这种对话。后来我被问烦了决定把 Rancher 引入进来这一换就是三年多再也没有回去过纯命令行管理。Rancher 是什么简单说它就是一个 Kubernetes 的多集群管理平台给你一个 Web 界面在界面上可以创建集群、导入已有集群、部署应用、查看 Pod 日志、管理配置项和密钥、给团队成员分配权限甚至能监控集群状态。它的本质是把 K8s 那套繁琐的 YAML 和 kubectl 操作封装成可视化操作但不是替你把 K8s 藏起来反而让你在界面上看到的东西都能对应回 CLI 里的对象。不需要把 Rancher 想象得多神秘它就是跑在你集群里的一个应用自己也要吃资源自己也有 Pod 和命名空间。理解这一点后面部署和排错会顺畅很多。如果你现在面临的选择是团队里已经有 K8s 集群了但缺少统一管理手段或者想给同事一个不用学 kubectl 也能看懂集群状态的可视化入口那 Rancher 基本就是最主流的那条路。如果你只是单机 k3s 自己玩那也可以装只是收益没那么明显。2. Rancher 部署实操两条路径和一个最容易出错的点2.1 准备环境节点规划和资源要求先说结论Rancher 本身不是重应用但它管理多个集群的时候内存和网络占用会明显上涨。我见过有人把 Rancher 直接塞在一个只有 2G 内存的节点上结果界面操作起来卡到怀疑人生。建议是单独给它一个节点4G 内存起步CPU 2 核起步如果后面还要接很多下游集群8G 内存会更稳妥。我自己当时是在已有的 K8s 集群里用 Helm 方式部署的但如果你不想让 Rancher 和你自己的业务集群耦合太深也可以单独准备一台虚拟机装上 Docker 后直接 docker run 跑一个 standalone 版 Rancher。这里我给两种方式你按自己的场景挑。先从 Docker 单机版说起这种方式适合快速体验也适合只管理一两个现有集群的场景docker run -d --name rancher \ --restartunless-stopped \ -p 80:80 -p 443:443 \ --privileged \ rancher/rancher:latest这行命令干了这么几件事拉取 rancher/rancher 镜像映射 80 和 443 端口设置重启策略开了 privileged 权限。其中 privileged 这个参数挺关键的因为 Rancher 内部要管理容器网络和策略权限不够会出各种莫名其妙的初始化问题。启动之后浏览器访问 https://节点IP 会看到首次初始化页面。注意是 https 不是 http因为 Rancher 默认就用自签名证书。2.2 初始化配置和 Rancher 内部结构登录之后第一步是设置 admin 密码然后会让你填写 Rancher Server URL。这个 URL 要填一个其他节点和集群都能访问到的地址不能填 localhost。如果你只是本机耍一下填 IP 就行如果是正经环境最好填一个域名后面导入集群的时候下游节点的 agent 要通过这个地址回连 Rancher Server。Rancher 初始化完成后它会自带一个叫 local 的集群这个 local 集群指的就是 Rancher Server 自己所在的那个集群。你可以在界面上看到 local 集群的状态。很多人第一次看到这个会有点懵我还没创建集群怎么就有了一个这是因为 Rancher 本身是跑在 K8s 之上的它把自己运行的集群纳管了。如果你是 Docker 单机方式部署的 Rancher它内部其实也内置了一个单节点 K8s 集群这就是 local 的由来。这个设计的好处是你打开 Rancher 第一眼就能看到一个活的集群可以立刻体验界面上部署应用、看 Pod 日志这些操作不需要先东拼西凑搞一个集群出来。2.3 从 Rancher 界面反向理解 Pod你如果点开 local 集群然后去工作负载Workload页面会看到 Rancher 后台自己跑了很多工作负载名字里都带 cattle 字样。Rancher 的底层组件都放在 cattle-system 这个命名空间里这个命名空间的 Pod 就是 Rancher 自身的组成部分不要乱删。界面上部署工作负载时你会看到一个表单其实这个表单背后生成的就是一个 K8s Deployment YAML。你可以这么理解界面上的每个字段对应着 YAML 里的某个字段。比如填容器镜像对应的是 spec.template.spec.containers[].image填环境变量对应的是容器里的 env。Rancher 只是把 YAML 转成表单表单再翻译回 YAML它在中间没有发明任何新东西。这个设计我觉得对新手来说反而是个学习 K8s 的捷径你在界面上改了某个参数按一下右上角的编辑 YAML就能看到对应的字段长什么样反过来你贴一段 YAML 进去Rancher 也会帮你渲染成表单。多切换几次Pod 的 YAML 结构就熟了。3. 导入已有集群Rancher 最实用的一个能力创建新集群不是 Rancher 最吸引我的地方最吸引我的是导入已有集群。你可以把任何一套 K8s 集群接入 Rancher 管理不管它是 kubeadm 装的、k3s 装的、还是云厂商托管的只要你有集群的 kubeconfig就能导进来。3.1 具体操作步骤在 Rancher 界面左上角切到更多集群点导入已有集群选通用选项Rancher 会给你一段 kubectl apply 的命令。这段命令本质上是往你的集群里安装 Rancher agent 组件agent 会负责把你的集群状态上报给 Rancher Server。执行完 apply 之后会创建 cattle-system 命名空间并在里面启动 rancher-cattle-agent 的 Pod。你可以等一两分钟刷新页面集群状态就会从 Provisioning 变为 Active。这里有一个坑就是 agent Pod 一直 CrashLoopBackOff。最常见的原因是 Rancher Server URL 填的是 localhost 或者一个下游集群访问不到的地址。你可以 describe 那个 agent Pod看日志里有没有连接超时的报错。有个判断的小技巧把 URL 里那个地址放到浏览器里从下游集群所在的那台机器上访问一下通不通一下就知道了。3.2 给 Rancher agent 分配权限的细节导入集群时Rancher 要求你提供一个拥有 cluster-admin 权限的 kubeconfig。这个要求让不少刚接触的人心里打鼓担心安全问题。实际上 Rancher 需要一个足够权限的账号来创建它自己的命名空间和 RBAC 规则否则它在下游集群里什么都干不了。如果你实在不放心可以在 apply Rancher 给的那段命令之前自己先建一个专门的 ServiceAccount绑定 cluster-admin 角色然后用这个 SA 的 token 生成一个临时 kubeconfig再用这个临时 kubeconfig 去导入。不过说实话对大多数场景来说直接用 admin kubeconfig 装完 agent 之后马上把权限回收掉也够用。Rancher 只是启动阶段需要这个权限agent 起来之后日常上报走的是它自己的服务账号。集群导入成功后你的收获是一个浏览器页面里能看到所有集群的节点 CPU、内存使用率、Pod 分布情况。这对团队协作的价值非常大再也不是每个人都得自己去配一遍 kubeconfig的状态了。4. Pod 详解它不是一个容器而是一组容器的盒子4.1 从一次部署事故说起讲一个我自己真实遇到的场景有个同事把 Nginx 和业务代码放在同一个 Deployment 里但是开了两个容器一个是 Nginx 反代一个是 Java 应用。他部署完发现只看到 Nginx 容器的日志业务代码的日志怎么都找不到。后来排了半天才发现他把两个容器放在了同一个 Pod 里而日志查询时默认只看第一个容器。这个经历恰好能引出 Pod 的一个核心概念Pod 是最小的调度单位但它可以包含多个容器。这些容器共享同一个网络命名空间和存储卷可以通过 localhost 互相访问也可以共享磁盘文件。也就是说Pod 是一个盒子盒子里的容器是室友关系住在同一个屋檐下。那什么时候应该一个 Pod 多个容器最经典的例子是 sidecar 模式主容器跑业务sidecar 容器负责收集日志、代理流量、或刷新配置文件。两个容器要紧密协作而且生命周期完全一致就该放进同一个 Pod。如果两个服务之间只是普通的服务调用关系那应该拆成两个 Deployment通过 Service 去访问。4.2 Pod 关键字段从一段 YAML 说起我们来看一段最基础的 Pod YAML把它彻底拆开apiVersion: v1 kind: Pod metadata: name: my-pod labels: app: demo namespace: default spec: containers: - name: demo-container image: nginx:1.25 imagePullPolicy: IfNotPresent ports: - containerPort: 80 env: - name: MY_ENV value: hello restartPolicy: Always这里面的字段我在实际工作中发现新手最容易忽略的是 imagePullPolicy。你不填这个字段K8s 会根据镜像 tag 推断如果 tag 是 latest默认总是拉取如果 tag 是具体的版本号默认只在本地没有时才拉取。这种推断逻辑坑过不少人明明改了镜像怎么 Pod 里跑的还是旧版本很可能就是因为你改的还是同一个 tag而 pullPolicy 是 IfNotPresent节点上已经有缓存了K8s 就不会重新拉了。还有一个字段是 restartPolicy。它有三个值Always、OnFailure、Never。如果你只是跑一个一次性批处理任务用 kubectl run 直接建 Pod默认的 restartPolicy 是 Always意味着任务跑完了还会被重新拉起。这时候正确做法是用 Job 资源或者在 Pod 里显式把 restartPolicy 设为 Never。4.3 Pod 的很多属性其实不是配置在 Pod 上这一节讲一个容易混淆的点很多人以为 Pod 的 YAML 里什么都该写但其实 nodeSelector、污点容忍、资源配额这些字段种在 Pod 这一层写的有些则在 Deployment 的 spec.template 里写。你如果手写一个裸 PodnodeSelector 确实可以直接写在 spec 里。但如果你用的是 Deployment你需要把它嵌套在 spec.template.spec 下面而不是 Deployment 的最外层。这个嵌套关系一旦搞错apply 的时候不报错但你会发现这个调度约束根本没生效Pod 还是被随机调度到别的节点去了。因为 Deployment 里真正描述 Pod 内容的字段都在 template 下面Deployment 自己那层的 spec 描述的是副本数、更新策略这些关于 Pod 集合的属性。我把这个对应关系列一个表方便你自查想要的效果裸 Pod 中的位置Deployment 中的位置容器镜像和启动命令spec.containersspec.template.spec.containers调度到指定节点spec.nodeName 或 nodeSelectorspec.template.spec.nodeSelector限制资源用量spec.containers[].resourcesspec.template.spec.containers[].resources注入环境变量spec.containers[].envspec.template.spec.containers[].env这个嵌套结构是整个 K8s 声明式设计的精髓你改任何 Pod 的模板都要去 template 下面改。理解了这一点很多我改了 YAML 为什么不生效的问题就解决一半了。5. 从创建到删除Pod 的生命周期和日常运维命令5.1 Pod 的五个阶段Pod 从创建到结束会经历几个固定的生命周期阶段。kubectl get pod 里看到的状态对应的就是这几个阶段的一种。PendingPod 已经被 API Server 接受但还没调度到节点上或者镜像还在拉取中。这个状态下如果长时间不变化大概率是调度失败或镜像拉不动。RunningPod 已经绑定到节点至少有一个容器在运行中或者容器处于启动或重启过程中。SucceededPod 里所有容器都成功执行完毕并退出不会再重启。一般出现在 Job 或一次性任务中。Failed至少有一个容器以非零状态退出。UnknownAPI Server 无法获取到 Pod 的状态。通常是节点失联或网络分区导致的。这里有个有价值的经验正常的 Web 服务Running 状态里也会出现 ContainerCreating 这种显示。注意 ContainerCreating 不是一个独立的阶段它属于 Running 大阶段内部的一个过渡子状态。如果新创建的 Pod 卡在 ContainerCreating 很久排错重点看两个地方一个是镜像能不能拉下来另一个是存储卷能不能挂载上。5.2 日常监控 Pod 的三个命令我在用 Rancher 之前每天盯着终端看 Pod最多的三个操作是 logs、describe、exec。如果你不记得别的先把这三个记牢。kubectl logs 看容器日志。一个 Pod 里有多个容器的话要加 -c 指定容器名否则会提示你选择。这个就是刚才 Nginx 那个事故里我们最后用到的命令。kubectl describe pod 看事件和状态详情。Pod 出问题的时候describe 是最有用的命令它会列出最近的事件包括调度成功没有、镜像有没有拉取、探针有没有失败。注意看 Events 那一部分前面的 STATUS 和容器状态只是结果原因都在 Events 里。kubectl exec -it 进入容器排查。生产环境一般不建议随便进容器但在测试环境进去看目录结构、手动执行脚本还是省时间的。如果你实在不想记命令Rancher 界面上也有对应的点按式入口点进 Pod 详情就能看到执行命令和查看日志的按钮。5.3 静态 Pod 这个概念知道一下不吃亏还有一个概念虽然日常写得少但在排查节点问题时会遇到就是静态 Pod。它不是通过 API Server 创建的而是由 kubelet 直接从指定目录下的 YAML 文件运行的 Pod。静态 Pod 创建出来之后你也可以在 API Server 里看到它但你不能从 API Server 这边删掉它删了 kubelet 又会按照文件重新给你拉起来。常见的静态 Pod 有 kube-apiserver、kube-controller-manager、kube-scheduler它们就是以静态 Pod 的方式跑在所有控制平面节点上的。如果你发现某个控制平面组件的状态不对别只盯着 Pod 看还要去 /etc/kubernetes/manifests 目录看对应的 YAML 文件有没有被改坏。这个目录里的文件一旦损坏Pod 删了也会反复重建而且重建的表现就是 CrashLoopBackOff。6. 实战排错Kubernetes Pod Sandbox 创建失败排查全链路先把一句话结论放在前面Pod 卡在 ContainerCreatingdescribe 之后看到 failed to create pod sandbox本质上是容器运行时containerd 或 Docker在创建 Pod 网络栈和沙箱环境的时候出了问题而不是你的应用镜像有问题。这个错误我翻来覆去遇到过很多次而且每次原因都可能不一样所以这里我把自己总结的排查链路完整写下来照着走一遍基本能定位到根因。6.1 先看错误原文和上下文首先还是那个老动作kubectl describe pod -n 。Events 区域如果出现类似下面这两行Failed to create pod sandbox: rpc error: code Unknown desc failed to create containerd task: failed to create shim task: ...或者Failed to create pod sandbox: rpc error: code Unknown desc networkPlugin cni failed to set up pod xxx network: failed to set bridge addr: ...注意区分两类一类是 containerd 根本起不来容器另一类是 CNI 网络插件配置网络失败。这两类的下一步检查方向完全不同。6.2 如果是 containerd 起容器失败这种情况优先怀疑节点上的磁盘空间、inode 耗尽、或者 containerd 服务状态异常。用 df -h 看磁盘用 df -i 看 inode。我遇到过一次特别典型的故障某个节点跑了日志采集程序但没有设置轮转策略/var/log 直接把磁盘撑满了。结果是所有新 Pod 都卡在 sandbox 创建阶段错误里面有一句 failed to create containerd task。另一层原因是容器镜像拉取失败但错误信息是包含在 sandbox 失败里的有时候 describe 显示的 still pulling 或者 manifest unknown 会被淹没。你可以在节点上直接用 crictl images 看看本地有没有目标镜像没有就 crictl pull 手动拉一次排除镜像仓库连通性问题。6.3 如果是 CNI 网络配置失败这类错误跟节点上的 CNI 插件有关。常见的 K8s 网络方案是 Calico、Flannel、Cilium。一旦节点上的 CNI 配置文件损坏或者网桥 IP 冲突都会导致 sandbox 创建失败。排查顺序是这样先检查 CNI 配置文件。默认路径是 /etc/cni/net.d/里面应该有一个 .conf 或 .conflist 文件。如果里面内容为空或者配置的插件路径不对节点上所有新 Pod 都可能起不来。再检查节点上的 CNI 插件二进制是否存在。一般默认路径是 /opt/cni/bin/里面至少有 bridge、loopback、portmap 这些二进制。有人升级过系统之后这个目录被清理过结果踩了一个大坑报错里看不到任何网络插件的字眼只是说 sandbox 创建失败。然后是看 kubelet 日志。journalctl -u kubelet -f 实时跟一下通常会打印比 describe 更详细的网络配置错误原因。比如网桥重名、子网冲突这种只有在 kubelet 日志里才看得到。6.4 最容易被忽略的一个点节点路由表和防火墙有一回我排一个 sandbox 创建失败的故障所有常规项都检查了一遍磁盘没问题、镜像没问题、CNI 文件没问题最后发现是节点上的 fail2ban 把容器网段的流量给拦了。CNI 插件创建 veth 设备、分配 IP、设置路由结果到打通网络那一步流量在出口被防火墙策略丢弃整个网络初始化判定失败。这种问题从错误信息上看永远是 networkPlugin cni failed但根因可能五花八门。遇到 CNI 报错别急着重装插件先把 iptables -L 和 ip route 看一眼。生产环境里顺手加个防火墙策略然后整个节点上所有新 Pod 都起不来的案例不是一例两例了。6.5 恢复手段快速定位到根因之后恢复手段一般两种如果只是节点上某个组件的状态不对比如磁盘清理后、防火墙规则修正后通常不需要重启整个节点重启 containerd 或者 kubelet 就行systemctl restart containerd systemctl restart kubelet如果是 CNI 插件的状态彻底乱了最稳妥的办法是删除这个节点上的所有相关 Pod让 K8s 重新调度重建。操作前一定要确认你对业务影响的评估不要在生产直接批量删。需要说明的是以上排查链路是基于我在实际环境中多次踩坑后的总结具体到不同版本的 containerd、K8s 或网络插件错误措辞可能会有细微差异但检查顺序和思路是一致的。7. 结合 Rancher 界面做日常管理的几个加分实操前面讲完 Rancher 部署和 Pod 原理这里再补充几个我在日常管理里觉得特别好用的组合玩法。Rancher 的日志查看页面比 kubectl logs 舒服的地方在于它支持在界面上直接按时间范围过滤日志还能同时看多个容器的日志。要知道用命令行看一个 Deployment 下多个副本的日志你得先 kubectl get pods 拿到所有 Pod 名再一个个加 -c 参数去追体验实在一般。Rancher 的工作负载页面里点某个 Deployment切到日志页签直接就能流式查看该工作负载下所有 Pod 的日志聚合。这个场景用在排查分布式应用联调问题时省下的是大量的上下文切换时间。另一个特别好用的点是Rancher 的编辑 YAML按钮。你在 Rancher 里创建的任何工作负载、Service、ConfigMap都可以随时切换到 YAML 模式直接修改而且它会在你保存之前做一次校验如果 YAML 格式有问题界面直接报错不会像 kubectl apply 那样把错误的对象提交到集群里再失败。这对刚开始学 K8s 的人来说是个非常好的保护层。你还可以把 Rancher 里写好的 YAML 导出存到 Git 仓库里做版本管理。Rancher 并不强制你绑定 GitOps 流程但你可以自己约定环境手动调整通过 Rancher最终版本以 Git 里为准。这样既享受了界面的便利又没有被锁定在某个私有配置格式里。8. Rancher 部署之外还要注意版本和升级策略最后想提醒一下版本相关的事情。Rancher 版本迭代速度不慢v2.7 是一个分水岭从 v2.7 开始Rancher 不再默认强制捆绑 Istio整个界面和底层代码结构也有不少调整。如果你在网上下载到一些教程看到界面长得跟你装的不太一样很可能就是版本差异不用慌。升级 Rancher 本身如果 Docker 方式安装直接拉新镜像重启容器。docker pull rancher/rancher:最新版本 docker stop rancher docker rm rancher docker run -d --name rancher \ --restartunless-stopped \ -p 80:80 -p 443:443 \ --privileged \ rancher/rancher:最新版本这里有个极其重要的注意点Rancher 的数据都在容器的 /var/lib/rancher 目录里如果你不带任何数据卷直接升级数据会全部丢失。正确做法是先把数据目录挂出来或者至少先做一次备份。如果你升级后起不来回头看第一步大概率就是数据没挂载。我自己在升级方面吃过一次类似的亏因为没保留数据卷整个集群的所有管理配置、项目权限、导入的集群信息全部重置后来花了半天时间重新配置。所以这里特意多写一句防止再有人踩。9. 最后关于 Rancher 和 Pod 的一个学习建议写到这里这篇的内容基本覆盖了 Rancher 的部署、导入集群、Pod 的定义、生命周期和常见排错链路。如果让我给一个学习路径上的建议我会说不要一开始就追求把所有 K8s 对象都在界面上点一遍而是先在命令行里把 Pod 的几个核心命令用熟然后再用 Rancher 去对照界面上的信息。原因很简单命令行培养你对底层事实的感觉Rancher 界面培养你的操作效率。两种技能不能互相替代。你如果只会界面出了问题很难真正定位根因你如果只会命令行日常管理的效率上不去。最理想的状态是看到界面上一个 Pod 的状态你能立刻在脑子里映射出背后的 YAML 和事件反过来也一样。这个映射能力没有捷径就是多写多删多排错。我也是从把一个 Deployment 改了十几遍反复滚动更新、回滚、看事件才慢慢把 Pod 的各种行为模式记在脑子里的。希望这篇能帮你在这个过程里少走几步弯路。