1. 这道升级题真正卡人的地方不在命令本身k8s 升级这道题在 CKA 里属于“看起来最简单、实际最容易丢分”的那一类。题目往往只给你一句话把某个节点上的 kubeadm、kubelet、kubectl 升到指定版本然后确认节点回到 Ready。很多人第一反应是翻文档抄命令apt-get install kubeadm1.xx.x-00敲下去终端甩回来一句The following packages have been kept back或者干脆报找不到版本人当场就懵了。问题的根子几乎从来不是命令写错而是没搞明白 kubeadm、kubelet、kubectl 这三个东西在升级链路里的角色分工也没搞明白apt-mark hold这个动作到底在跟谁较劲。我见过不少人卡在第一步apt-mark unhold kubeadm这行没执行后面所有 install 全被包管理器拦下来。也有人反过来unhold 完装完就跑了忘了重新 hold 回去结果第二天节点的 kubelet 被系统的自动升级顺手带到了一个新版本整个集群的版本偏差瞬间超标。这两个错误方向相反但本质是同一个认知缺口——你把包管理器的行为当成了黑盒而它其实是整个升级流程里唯一一个有“记忆”的环节。这一节我想先把三件套的关系和 hold 机制的底层逻辑摊开讲清楚。搞懂这部分后面所有命令你都不需要背顺着因果关系推就能推出来。1.1 三件套版本关系为什么 kubeadm 必须先动手kubeadm、kubelet、kubectl 虽然经常被一起提起但它们是三个完全独立的二进制包各自有独立的版本号也各自被不同的东西管理。kubeadm是一次性工具负责“生成配置、拉取镜像、引导集群、执行升级编排”。它不常驻不跑在 systemd 里你敲完命令它就退出了。kubelet是节点上的常驻守护进程负责跟容器运行时打交道、汇报节点状态、拉起 Pod它被 systemd 管理。kubectl只是一个客户端负责把你的意图翻译成 HTTPS 请求发给 apiserver。三者升级的先后顺序不是随便定的而是由依赖关系倒逼出来的。kubeadm upgrade apply这个动作会重写控制平面组件的静态 Pod 清单、更新证书、迁移 etcd 的配置格式它本身的行为是由 kubeadm 的版本决定的。如果你用旧版 kubeadm 去升级一个目标版本它压根不认识新版本的配置字段和镜像 tag生成出来的清单会直接让 apiserver 起不来。所以顺序必须是先把 kubeadm 换成目标版本再用新版 kubeadm 去驱动控制平面升级最后把节点上的 kubelet 和客户端 kubectl 换成目标版本。组件升级载体升级时机忘记升级的后果kubeadmapt/yum 包全流程第一步upgrade plan报未知版本配置字段不识别控制平面apiserver 等由 kubeadm 驱动镜像形式kubeadm upgrade apply版本停留在旧版与新 kubelet 偏差超标kubeadm 节点配置kubeadm upgrade node每个节点执行一次节点上的 kubelet 配置不同步重启失败kubeletapt/yum 包 systemd 重启控制平面升级完成之后节点实际运行的容器引擎版本没变kubectlapt/yum 包任意时机建议紧跟 kubelet命令行报版本偏差警告部分子命令行为异常这里有个容易被忽略的点控制平面的组件apiserver、controller-manager、scheduler、etcd不是通过包管理器升级的它们是静态 Pod镜像 tag 由 kubeadm 写进/etc/kubernetes/manifests/下的 yaml 文件里。你在节点上apt list --installed | grep kube看到的包列表里根本没有 apiserver。所以“升级 k8s”这件事必须拆成两半一半是包管理器的活三个二进制一半是 kubeadm 编排的活控制平面和节点配置。把这两半混为一谈就会出现“我明明装了新版本为什么kubectl get nodes还是显示旧版本”的困惑——因为节点上报的 version 字段来自 kubelet而 apiserver 的版本来自镜像。1.2 apt-mark hold 与 unhold被“锁住”的包到底锁的是什么apt-mark hold做的事情非常朴素在 dpkg 的状态数据库里给某个包打一个标记告诉 apt“这个包你别碰不管依赖怎么变、不管有没有新版本都不许自动动它”。它不改版本不卸包只改一个状态位。你可以用apt-mark showhold随时查当前有哪些包被锁住。集群安装完成后初始化脚本或者 kubeadm 安装文档通常会把kubeadm、kubelet、kubectl、kubernetes-cni这几个包全部 hold 住。这么做的理由很实在k8s 的版本偏差策略是有硬性上限的kubelet 最多只能比 apiserver 落后三个小版本kubectl 只能偏差一个小版本。如果放任包管理器跟着系统更新走某天一次apt upgrade就可能把节点上的 kubelet 顶到最新版整个集群瞬间变成不受支持的组合而且这种漂移是静默发生的等你发现时往往是某个节点莫名其妙 NotReady。所以升级时的动作就变成了一个“解—装—锁”的三段式# 1. 解锁让 apt 允许改动这个包 apt-mark unhold kubeadm # 2. 安装指定版本 apt-get install -y kubeadm1.30.2-1.1 # 3. 立刻锁回去防止后续误升级 apt-mark hold kubeadm这三步里的第三步最容易被漏。很多人觉得“我在考试环境里就操作这一次锁不锁无所谓”但考试评分脚本经常会在升级完成后跑一次apt-mark showhold来确认你没有破坏集群的版本锁定策略。更实际的是如果你在同一台机器上还要继续装 kubelet 和 kubectl那么保持 kubeadm 处于 hold 状态能防止apt-get install kubeletxxx时 apt 顺手把 kubeadm 的依赖关系重算一遍。还有一个小细节值得说unhold和install之间不要夹apt-get update之外的多余操作也不要在这中间跑apt-get upgrade。因为一旦解了锁又跑了全量升级apt 会把你解开的那个包直接顶到源里的最新版你再想装指定版本就得先降级而降级在 apt 里是个麻烦事需要显式指定版本并处理依赖回退。提示如果apt-get install kubeadm1.30.2-1.1报Version 1.30.2-1.1 for kubeadm was not found八成是你没把目标版本的软件源加进来或者apt-get update没跑。这不是 hold 的问题别在这儿死磕。2. 动手之前把版本账算清楚升级这种事最贵的成本永远是“做到一半发现前提不成立”。我在实际环境里踩过最难受的一次坑是目标版本号抄错了一位kubeadm upgrade apply跑到一半报镜像拉取失败控制平面处于半升级状态apiserver 起不来kubectl 直接失联只能靠crictl和静态 Pod 的日志一点点往回捞。那次之后我养成了一个习惯任何升级动作之前先花三分钟把版本账算清楚把三条信息确认到位——当前版本、目标版本、源里到底有没有目标版本。这三分钟不是浪费时间它能把后面 80% 的失败概率直接掐掉。2.1 当前状态勘察节点版本、可用版本、源配置第一步是摸清现状。不要凭记忆直接查。# 看节点上报的版本这个数字来自 kubelet kubectl get nodes -o wide # 看客户端和服务端的完整版本信息 kubectl version --outputyaml # 看 kubeadm 自己的版本 kubeadm version -o short # 看已安装的包版本 dpkg -l | grep -E kubeadm|kubelet|kubectl这四条命令输出的是四份不同的账。kubectl get nodes里的 VERSION 列是 kubelet 上报的kubectl version里的 Server Version 是 apiserver 报的kubeadm version是本地二进制自己的版本。三者不一致是常态尤其在刚装完还没升级的机器上——apiserver 可能已经是新版但 kubelet 还停在旧版。搞清楚哪个是哪个你才知道下一步该动谁。第二步是确认目标版本在源里存在。这一步用apt-cache madison最直接apt-get update apt-cache madison kubeadm输出会列出该包在已配置源里的所有可用版本形如kubeadm | 1.30.2-1.1 | https://pkgs.k8s.io/core:/stable:/v1.30/deb/ Packages kubeadm | 1.30.1-1.1 | https://pkgs.k8s.io/core:/stable:/v1.30/deb/ Packages kubeadm | 1.29.6-1.1 | https://pkgs.k8s.io/core:/stable:/v1.29/deb/ Packages如果目标版本不在这份列表里说明对应的软件源没配。k8s 从 1.24 之后官方源迁移到了独立的仓库地址每个小版本一个路径。你需要检查/etc/apt/sources.list.d/下的配置文件确认里面指向的是目标小版本的源。改完源必须重新apt-get update否则apt-cache madison读的还是旧索引。检查项命令期望结果节点当前版本kubectl get nodes记录每个节点的 VERSION客户端/服务端版本kubectl version --outputyaml确认 skew 是否已在边界kubeadm 版本kubeadm version -o short与控制平面版本对齐包是否被锁apt-mark showhold确认三件套在 hold 列表里目标版本是否可得apt-cache madison kubeadm列表中出现完整版本串源配置ls /etc/apt/sources.list.d/存在指向目标小版本的源文件2.2 小版本跨度与组件版本偏差的硬约束k8s 的版本号是major.minor.patch三段式升级策略对这三段的处理完全不同。patch 版本之间可以随便跳1.30.1 到 1.30.6 直接升没有任何限制。minor 版本之间不能跳1.28 想到 1.30必须先升到 1.29 再升到 1.30kubeadm upgrade apply会明确拒绝跨 minor 的请求。这是一条硬约束考试里如果题目要求从 1.28 升到 1.30你必须老老实实走两轮每轮都要完整跑一遍 kubeadm、控制平面、kubelet 的流程。major 版本目前不存在k8s 还没到 2.0所以不用操心。除了 kubeadm 的跳跃限制组件之间还有版本偏差version skew策略这个在考试里不一定直接考但它决定了你升级过程中集群会不会短暂进入不受支持的状态kubelet 相对 apiserverkubelet 可以比 apiserver 旧最多三个 minor 版本但绝对不能比 apiserver 新。这就是为什么必须先升控制平面再升 kubelet反过来的话新版 kubelet 会拒绝连接旧版 apiserver。kubectl 相对 apiserver允许上下浮动一个 minor 版本。超了不会报错但会打警告个别子命令的行为可能有差异。kube-controller-manager / kube-scheduler 相对 apiserver必须同版本因为它们是一起被 kubeadm 管理的静态 Pod。把这些约束串起来升级顺序就被唯一确定了kubeadm 先换 → 控制平面跟着 kubeadm 走 → 各节点 kubelet 跟上 → kubectl 最后换。这条链路里任何一步乱序都会撞上 skew 边界。注意kubeadm upgrade plan输出的表格里会明确列出“可以升级到哪些版本”以及“当前集群各组件版本”。这个输出在考试里是免费的提示先跑一次再决定装哪个版本比直接抄题目里的版本号稳妥得多。3. 控制平面节点的升级链路控制平面节点的升级是整条链路上唯一会短暂影响集群可用性的环节。kubeadm upgrade apply执行期间apiserver 会被反复重启具体表现为静态 Pod 的清单文件被逐个重写、容器被逐个重建。这个过程通常持续几十秒到一两分钟期间kubectl可能报连接拒绝属于正常现象不需要慌张。但“正常现象”和“真出问题了”在终端上的表现很像所以这一节我想把每个阶段的预期输出和判读方法讲透让你在命令跑的时候心里有底知道什么该等、什么该断。3.1 kubeadm 自身的替换与 upgrade plan 的判读第一步永远是把 kubeadm 二进制换成目标版本。这一步只影响本地工具不影响运行中的集群所以可以放心操作。apt-mark unhold kubeadm apt-get install -y kubeadm1.30.2-1.1 apt-mark hold kubeadm kubeadm version -o short最后一行输出v1.30.2就说明替换成功了。如果输出还是旧版本检查一下which kubeadm是不是指向了/usr/local/bin下的旧二进制——有些环境里手工下载过 kubeadmPATH 的优先级会让 apt 装的/usr/bin/kubeadm被覆盖掉。这种情况要么删掉旧二进制要么把 PATH 顺序调整过来。接下来跑计划。kubeadm upgrade plan是个只读操作它不会改任何东西但会做几件事检查当前集群版本、检查 kubeadm 自身版本、拉取目标版本的镜像元信息、列出可用的升级目标、检查证书是否即将过期。kubeadm upgrade plan输出里要重点看三块。第一块是Components that must be upgraded manually它会列出每个节点当前的 kubelet 版本和目标版本这是你后续操作的清单。第二块是Upgrade to the latest stable version给出建议的目标版本号。第三块是各组件etcd、CoreDNS、kube-proxy的版本变化。如果输出里出现证书过期的警告别急着往下走先处理证书否则升级完 apiserver 会直接起不来。这里有个很实际的坑kubeadm upgrade plan会尝试访问镜像仓库拉取元数据如果节点出不了网或者镜像仓库不可达它会卡住或者报错。考试环境一般不会有这个问题但真实环境里很常见。遇到这种情况可以加--allow-experimental-upgrades之类的参数绕过一部分检查或者提前把镜像拉好。3.2 kubeadm upgrade apply 之后kubelet 与 kubectl 的接力确认计划没问题执行升级kubeadm upgrade apply v1.30.2 -y-y是跳过交互确认。整个过程会输出大量日志关键节点有这么几个[upgrade/staticpods]表示正在重写静态 Pod 清单[upgrade/etcd]表示在迁移 etcd 数据格式[upload-config]表示在更新集群里的 kubeadm 配置对象ConfigMap 形式。最后出现SUCCESS! Your cluster was upgraded to v1.30.2就说明控制平面这一半完成了。但这时候节点还没升级完。kubectl get nodes看 VERSION 列还是旧的因为 kubelet 还没动。升级输出里会明确提示你[kubelet] Downloading configuration for the kubelet from the kubelet-config ConfigMap [upgrade/successful] SUCCESS! Your cluster was upgraded to v1.30.2. [upgrade/kubelet] Please manually upgrade the kubelet package on each node.接下来是 kubelet 和 kubectl 的接力。这两个包可以一起装但顺序上建议先 kubelet 再 kubectl因为 kubectl 只是客户端晚一点换不影响什么。apt-mark unhold kubelet kubectl apt-get install -y kubelet1.30.2-1.1 kubectl1.30.2-1.1 apt-mark hold kubelet kubectl systemctl daemon-reload systemctl restart kubeletdaemon-reload这行绝对不能省。apt 安装新版 kubelet 时会替换/usr/lib/systemd/system/kubelet.service或对应的 drop-in 文件如果不重新加载 systemd 的单元定义restart跑的还是缓存在内存里的旧定义可能指向一个已经不存在的配置路径。这个坑在真实环境里非常隐蔽——systemctl restart kubelet返回成功systemctl status kubelet显示 active但kubectl get nodes里节点就是不 Ready日志里报failed to load bootstrap kubeconfig之类的错。重启完之后验证一下systemctl status kubelet --no-pager kubectl get nodes -o wideVERSION 列变成v1.30.2就说明这台机器走完了全程。3.3 静态 Pod 的滚动与 apiserver 短暂不可用的窗口kubeadm upgrade apply期间集群会发生什么值得单独说一下因为这段窗口里的现象很容易让人误判成故障。kubeadm 升级控制平面的方式不是“停掉旧的、启动新的”而是逐个重写/etc/kubernetes/manifests/下的 yaml 文件里的镜像 tag。kubelet 监听这个目录文件一变就重建对应的静态 Pod。所以实际过程是apiserver 的新旧两个实例短暂共存然后旧的退出controller-manager 和 scheduler 跟着滚动etcd 视版本跨度可能会做数据迁移。这段窗口期里你的kubectl命令可能出现三种表现连接超时、连接被拒绝、或者返回部分结果。这些都是正常的。判断是否真出问题的标准只有一个——等待时间。正常滚动一般 30 到 90 秒内完成如果你的kubectl get nodes连续三分钟以上都连不上那就要开始排查了先看静态 Pod 的容器状态# 静态 Pod 不走 apiserver需要用容器运行时直接查 crictl ps -a | grep -E kube-apiserver|etcd|kube-controller|kube-scheduler crictl logs 容器ID 21 | tail -50这里crictl是容器运行时的命令行工具静态 Pod 在 apiserver 不可用时是查不到kubectl get pods的因为 kubelet 自己都连不上 apiserver。这是排查控制平面故障的关键路径很多人在这一步死磕kubectl get pods -n kube-system然后被“连接拒绝”绕进死胡同。etcd 的迁移是另一个需要留意的点。如果新旧版本跨度较大kubeadm upgrade apply会做 etcd 的数据格式迁移这期间 etcd 会短暂只读甚至不可用表现是 apiserver 报etcdserver: request timed out。这个同样属于预期行为等它跑完就行。4. 工作节点的升级与调度腾挪控制平面升完剩下的工作节点升级在技术上是同一套动作但多了一层调度层面的考虑节点上的 kubelet 一重启跑在上面的 Pod 会短暂失联如果这台节点上有单副本的有状态服务重启窗口里业务就直接断了。考试环境里通常不用管这些一道题给你一个 worker 节点上面可能就跑着几个系统组件。但既然这篇是给真实场景写的调度腾挪这部分还是得讲因为它决定了你是“无感升级”还是“制造事故”。4.1 drain 的时机、参数与 PDB 的干扰标准动作是先标记不可调度再驱逐 Pod再升级最后恢复。kubectl cordon node-01 kubectl drain node-01 --ignore-daemonsets --delete-emptydir-data两个参数的含义要搞清楚。--ignore-daemonsets是必须的因为 DaemonSet 的 Pod 本来就是要跑在每个节点上的你不忽略它drain 会直接报错拒绝执行。--delete-emptydir-data是另一回事它允许删除使用了 emptyDir 卷的 Pod这个卷的数据在 Pod 重建后就没了所以这个参数本质上是一次数据丢失的授权加之前要想清楚上面跑的是什么。真实环境里最容易卡住的是 PodDisruptionBudget。如果某个应用配了 PDB 且要求最少可用副本数等于当前副本数drain 会一直卡在“等待 Pod 被驱逐”的状态直到超时。这时候不是命令写错了是你不能在不影响业务的前提下驱逐这个 Pod。处理方式要么是临时扩容副本数要么是接受一次短暂的可用性下降把 PDB 临时放宽。还有一个细节drain默认会设置一个超时时间卡住的时候不会永远等下去会报error when evicting pods退出。看到这个错别急着重跑先kubectl get pods -o wide | grep node-01看看还剩哪些 Pod 没走逐个确认原因。提示单节点集群或者控制平面同时承担工作负载的环境里drain控制平面节点会把核心组件以外的 Pod 全赶走如果上面跑着单副本的监控、日志组件驱逐之后它们会被调度到其他节点重新拉起。这个过程本身没问题但如果集群资源紧张可能出现 Pod Pending 的情况。升级前看一眼kubectl describe node的 Allocated resources 会更稳妥。4.2 工作节点上 kubeadm upgrade node 的差异工作节点不需要跑kubeadm upgrade plan也不需要kubeadm upgrade apply。它只需要一个命令kubeadm upgrade node这个命令做的事情和控制平面上的apply不一样。在控制平面节点上kubeadm upgrade node会做完整的控制平面升级在工作节点上它只做两件事从集群里拉取最新的kubelet-configConfigMap写到本地的/var/lib/kubelet/config.yaml更新本地 kubeadm 的集群配置对象。它不碰静态 Pod也不碰证书。这个差异带来一个很实际的问题工作节点升级时本地的 kubelet 配置文件会被覆盖。如果你之前手工改过/var/lib/kubelet/config.yaml比如调过maxPods、改过evictionHard阈值、或者加过自定义的resolvConf路径这些改动在升级后全部丢失。真实环境里这个坑相当致命因为丢的往往是之前为了解决某个特定问题打的补丁而且丢得悄无声息直到某天节点因为资源压力开始乱杀 Pod 才被发现。所以正规做法是把自定义配置放到/var/lib/kubelet/config.yaml之外的 drop-in 目录里或者通过 kubeadm 的KubeletConfigurationpatch 机制管理。考试环境不用管这么细但知道这个差异至少能让你在kubeadm upgrade node之前先备份一下原文件cp /var/lib/kubelet/config.yaml /root/kubelet-config.yaml.bak kubeadm upgrade node完整的工作节点流程串起来是这样# 在控制平面节点上执行 kubectl drain node-01 --ignore-daemonsets --delete-emptydir-data # 登录到工作节点执行 apt-mark unhold kubeadm apt-get install -y kubeadm1.30.2-1.1 apt-mark hold kubeadm kubeadm upgrade node apt-mark unhold kubelet kubectl apt-get install -y kubelet1.30.2-1.1 kubectl1.30.2-1.1 apt-mark hold kubelet kubectl systemctl daemon-reload systemctl restart kubelet # 回到控制平面节点 kubectl uncordon node-01 kubectl get nodes -o wide注意uncordon这一步必须回控制平面节点执行在工作节点上跑kubectl也可以只要 kubeconfig 配好了。但考试里经常出现的情况是工作节点上根本没有 kubeconfigkubectl一跑就报The connection to the server localhost:8080 was refused。这不是权限问题是它不知道去哪找 apiserver。解决办法要么把控制平面的/etc/kubernetes/admin.conf拷过来要么回控制平面节点执行。别在这儿浪费时间去改 kubeconfig 的 server 地址。5. 升级后的验证清单与常见翻车现场命令跑完、节点显示 Ready很多人到这儿就交卷了。但 CKA 的评分脚本往往不只查版本号它还会检查节点状态、系统组件 Pod 是否全部 Running、kubelet 服务是否 enabled。我见过版本号明明对了却被判错的案例根因是 kubelet 服务虽然跑起来了但没有设成开机自启或者某个系统组件 Pod 卡在 CrashLoopBackOff。这一节把验证拆成五层每一层的检查目的和常见异常都写清楚。5.1 五层验证节点、组件、Pod、kubelet、证书第一层节点版本与状态。kubectl get nodes -o wide看两列STATUS 必须是 ReadyVERSION 必须是目标版本。如果 STATUS 是 NotReady先别看别的直接上节点systemctl status kubelet和journalctl -u kubelet -n 100。第二层系统组件 Pod。kubectl get pods -n kube-system里所有 Pod 应该都是 Running。重点看kube-apiserver-*、kube-controller-manager-*、kube-scheduler-*、etcd-*、kube-proxy-*、coredns-*。控制平面的静态 Pod 名字里带节点名如果你的节点名改过这里可能对不上。第三层kubectl 版本。kubectl version --outputyaml里 Client 和 Server 的 minor 版本差距不能超过 1。第四层kubelet 服务状态。这个必须上节点查因为 apiserver 只能看到 kubelet 上报的结果看不到服务本身的状态systemctl is-active kubelet systemctl is-enabled kubelet两个命令都要看。is-active返回active说明在跑is-enabled返回enabled说明开机自启配着。真实环境里出现过升级后is-enabled变成disabled的情况节点当前没问题但机器一重启就下线。第五层证书有效期。升级过程会顺带续期一部分证书但 kubelet 的客户端证书和 apiserver 的 serving 证书不一定覆盖到kubeadm certs check-expiration输出表格里如果有个别证书剩余时间不足 30 天趁这次机会一起续了别等到下次。把这五层做成一张检查表升级完照着过一遍比凭感觉靠谱得多层级检查命令通过标准不通过时的第一反应节点kubectl get nodes -o wideReady 目标版本查 kubelet 日志组件 Podkubectl get pods -n kube-system全部 Runningkubectl describe看事件客户端kubectl version --outputyamlminor 差距 ≤ 1确认装的是哪个二进制kubelet 服务systemctl is-active/is-enabledactive enabledsystemctl enable --now证书kubeadm certs check-expiration剩余 30 天立刻续期5.2 几个真实感很强的失败场景与处置场景一apt-get install报held back。终端输出类似The following packages have been kept back: kubeadm kubelet。这就是 hold 没解。回去补apt-mark unhold再装。注意三个包都要解只解一个另一个照样被拦。场景二kubeadm upgrade apply报版本不匹配。输出the desired version v1.31.0 is not supported或者提示跨 minor 不允许。这说明你要么跳了 minor要么本地 kubeadm 版本和目标版本不一致。先kubeadm version -o short确认再决定是换版本号还是先升 kubeadm。场景三节点升级完变 NotReady日志报failed to run Kubelet: misconfiguration: kubelet cgroup driver: systemd is different from docker cgroup driver: cgroupfs。这是 cgroup driver 不一致的经典报错。新版 k8s 默认用 systemd 驱动但容器运行时如果配的是 cgroupfs 就会冲突。处置方式是改容器运行时的配置让它也用 systemd然后重启容器运行时和 kubelet。这个坑在从旧版本升上来的环境里特别常见。场景四kubectl get nodes一直显示旧版本但节点上kubelet --version已经是新的。这说明 kubelet 重启后上报的新版本没被 apiserver 接受通常是 kubelet 和 apiserver 的 skew 超了。回到版本偏差策略那一节检查是不是顺序搞反了——先升了 kubelet 后升控制平面。场景五apiserver 起来但一直 CrashLoop。常见原因是升级过程中证书出了问题或者 etcd 的数据格式没迁移成功。crictl logs看 apiserver 容器的日志如果是证书相关kubeadm certs renew all然后重启静态 Pod如果是 etcd 相关可能需要从备份恢复。我在实际操作中体会最深的一点是升级这件事的最大风险不在命令在于你动手前没有把“如果失败怎么回退”想清楚。控制平面节点的/etc/kubernetes/manifests/和/var/lib/etcd是必须提前备份的两个目录备份一次只要几秒钟但出了事能不能救回来全看这两份东西在不在。考试环境有快照可以重置真实环境没有。
阅读完成 · 觉得有帮助?