期望三与一个观测单位、两个缺失数量位置并列。箭头比较目标和数量差距,不表示已具备就绪容量。

Kubernetes Deployment 描述期望状态

与其描述步骤,不如描述终态。这条思想支撑起副本、滚动更新与回滚的一切机制。 数量序列解释原文的本地算术模型。真实控制器各有职责,异步协调也可能受阻。历史模型通过记录保持不变;本次未重跑示例。 声明规范胜过过程脚本 一份 Deployment 是「终态」的陈述,而不是一张命令清单:多少副本、哪个镜像、哪条 tag、什么标签。操作者写下「要什么」,控制器这位 reconcile 循环决定「怎么要」。区别在于资源所有权,而不是有没有使用命令行。kubectl run 通常创建独立 Pod,kubelet 可以重启其中容器,但这个 Pod 消失后,没有 ReplicaSet 负责补足一组替代对象。Deployment 同样可以通过一条命令创建,客户端退出之后,存储下来的规范仍会持续指导控制器。中断客户端并不能可靠说明 API 是否已经接纳请求;重试或诊断收敛之前,先查看实际存储的对象,区分请求传递状态与控制器执行状态。 由控制器填补差距 Deployment 控制器管理 ReplicaSet,再由副本集控制器维持 Pod 数量。容器崩溃时,kubelet 可以在同一个 Pod 内重启容器;删除或丢失 Pod 后创建替代对象,则是另一条协调路径。它们会配合工作,但不能都说成同一个控制器每隔几秒创建一个 Pod,否则无法区分实例身份、重启与替换。 ...

八月 19, 2027 · 2 分钟 · XB Field Notes
Pod 使用绑定 PV 的 PVC;恢复仍取决于后备存储与拓扑。

PVC 为 Pod 提供容器之外的持久存储

PersistentVolumeClaim 把存储的生命周期与重建的 Pod 分开,但不保证一定能恢复数据。PersistentVolume 描述存储,声明请求存储,由控制器安排绑定或供应。真正的恢复仍取决于后备存储、可用拓扑与备份;有了 StorageClass,可以由 provisioner 动态供应,而不必预先建好每块卷。 声明与卷各自有独立的生命周期。finalizer 可以推迟对象删除,回收策略决定释放后的存储如何处理。维护前应核对两者:处理失误可能留下持续 Terminating 的声明、删掉本想保留的数据,或留下一份没人在用却仍在计费的存储。 保护机制推迟删除,不证明控制器健康。Retain 需要核对归属、备份并按提供方流程决策。保留诊断仍受阻,本轮未重跑。 声明、卷与绑定 普通匹配会检查容量、访问模式、存储类、volumeMode、选择器及既有归属。不匹配的声明可以停在 Pending,应检查事件与 StorageClass,不能只猜一个原因。绑定不证明拓扑可用:显式指定 PV 时,即使节点亲和性冲突也可能绑定成功,后续调度与挂载仍需各自成功。已释放但尚未回收的 Retain 卷也不会自动成为新声明的可用备件;旧 claimRef 可能仍然存在。 accessModes 没有默认值。ReadWriteOnce 允许单节点读写挂载,该节点上的多个 Pod 仍可能共用它,不是单 Pod 独占。ReadWriteOncePod 才为受支持的 CSI 卷提供单 Pod 约束;访问模式本身并不在挂载后执行写保护。Immediate 不等待消费者就开始绑定或供应,受拓扑限制的存储可能因此无法使用。受支持的 WaitForFirstConsumer 则结合消费 Pod 的调度约束协调存储,之后才完成放置;它不是先完成调度再随意创建卷。 ...

八月 13, 2027 · 1 分钟 · XB Field Notes
相同单容器 Pod 各请求 200m CPU、目标 60% 时,简化目标为 120m;三个副本各用 160m,未经修正的计算建议四个副本。

HPA 按负载缩放 Deployment 的副本

HorizontalPodAutoscaler 是反馈控制器,不是容量规划器,默认同步间隔为十五秒。根据配置,它读取资源、自定义或外部指标,再更新工作负载的 scale 子资源。基本计算为 desiredReplicas = ceil(currentReplicas * currentMetricValue / desiredMetricValue),之后还要考虑缺失数据、就绪状态、容忍度、稳定窗口及上下界,不能只靠这一行公式预测全部实际行为。 一份看起来正确的 HPA 对象,不证明容量必然及时到位。指标可用性、请求、副本上限、调度及应用启动都会影响结果。应分别查看建议副本数与真实就绪容量;提高期望数量不会制造新节点,也不能自动修好受阻发布。判断伸缩是否有效,必须跟踪从指标到应用接流量的整段过程。 原文算术示意,不是观察到的伸缩事件。保留的 Kubernetes 只读诊断仍为受阻,本次未重跑。建议四个副本不证明四个 Pod 已就绪或应用容量充足。 比值与死区 CPU 利用率目标把实际 CPU 用量与相关请求比较,得到百分比,目标本身也是百分比。如果每个 Pod 只有一个容器,都请求 200m,目标为百分之六十,那么每 Pod 120m 是便于理解的简化等价值。它不是异构 Pod 或所有指标类型通用的分母;多个容器和不同请求会改变聚合结果。 集群默认容忍度为一附近的 0.1。Kubernetes 1.34 的分方向容忍度仍为默认关闭的 alpha 功能;不能假定每个 HPA 都能覆盖它,要先检查特性开关和控制器配置。应把它理解为控制死区,而不是承诺 132m 永不伸缩、133m 必然动作。指标聚合、整数利用率、就绪状态及实现中的算术都会影响边界。忽略其他修正时,三个副本以 160m 对比 120m 目标,会建议四个副本;舍入、速率策略与最终能否调度仍需分别观察,不能从一个毫核数字直接推出真实扩容时刻。 ...

八月 11, 2027 · 1 分钟 · XB Field Notes
配置 startup 探针时,启动成功分别启用两条独立支路:readiness 控制 Service 路由资格,liveness 对应容器恢复。

liveness 与 readiness 告诉 Kubernetes Pod 的状态

慢启动不等于进程已死。readiness 与 liveness 分别决定普通 Service 流量是否应该进入这个 Pod,以及终止容器是否有助于恢复,两项决策相互独立。readiness 失败不会暂停 liveness;需要配置 startup 探针,才能在启动阶段抑制另外两种检查。只把接口分成两个名字,不能自动解决这个时序问题。 本文关注健康信号的选择与接线错误的诊断。关键是每次检查实际测到了什么,而不是 URL 名称。共用一个接口可以合理;共用会因下游抖动而失败的检查,并据此触发不必要的重启,却可能扩大故障。设计时应验证具体故障模式与预期恢复动作,不能假定有两个接口就天然安全,也不能把“还没准备好”直接解释成“需要杀死重来”。 普通 Service 路由异步收敛;已有连接与 Pod 直连需要另行考虑。 Readiness 把流量挡在门外 连续 readiness 失败达到阈值,会让 Pod 失去普通 Service 路由资格,但 Pod 仍在运行,好让进程完成热身或自行恢复。端点条件与数据路径在失败、恢复两个方向都异步收敛;已有连接和 Pod 直连需要分别考虑。就绪失败不直接触发探针重启,却可能移除全部服务容量,不能无条件称为安全:缓存可以慢慢热,迁移可以跑完,下游依赖可以回来,全程不丢 Pod 的内存状态,也不付重启的代价。 ...

七月 14, 2027 · 1 分钟 · XB Field Notes
ConfigMap 修改后,普通投射文件最终更新,已有容器的环境快照保持不变。

ConfigMap 文件与环境变量有不同生命周期

修改 ConfigMap 首先改变的是 API 对象。运行中的应用是否改变行为,还取决于 Kubernetes 如何交付数据,以及应用如何读取它。环境变量注入、普通卷投射、subPath 挂载和已经打开的文件,分别拥有不同生命周期。排查时应找到真正影响业务的消费者,而不是把所有配置传递方式都看成同一种机制。 原文保留示例中的五类交付生命周期。文件刷新不证明应用已经采用配置。本轮集成验证仍受阻,未重跑示例,也未建立通用传播时限。 区分交付与消费 容器环境中的 ConfigMap 引用会在容器启动时解析。更新对象不会重写已有进程的环境,也不会改写同一容器后续 exec 进程所使用的配置环境。替换 Pod 并引用所需版本,可以建立新的环境快照,但这属于生命周期动作,不是修改 data 字段之后自然发生的结果。配置变更记录与进程替换记录应能够对应。 普通 ConfigMap 卷则不同,kubelet 可以在之后把新数据投射进去。延迟受到同步周期和变更发现策略影响,因此 API 修改成功与文件发生变化不是同时发生的事件。投射更新也不会自动调用应用的重新加载函数。只在启动时解析一次配置的程序,即使文件已经变化,也可能一直使用先前读入的值。 打开文件描述引用的是已经打开的文件,而不是每次都重新解析原路径。路径背后的文件被替换,不会迫使旧描述符自动跟随新文件。因此,关闭并重新打开投射路径的进程可能读取新内容,另一个保留的描述符却仍读取旧文件。即使文件系统视图已经刷新,应用自己的缓存还可能再增加一层滞后。 把投射内容复制到可写位置,又会创建一个独立快照。副本不是指向 ConfigMap 的实时链接。如果启动脚本采用这种复制方式,更新这个副本也需要单独实现,不能期待源文件变化自动传播到另一份普通文件。 ...

七月 1, 2027 · 3 分钟 · XB Field Notes
启动门闩把就绪流量资格与存活重启处理作为两个独立分支放行。

探针告诉平台何时出手

探针结果是控制循环使用的证据,不是平台对应用健康的直接理解。Kubernetes 不会从 healthz 这个路径名称推断你希望怎样恢复服务;真正决定下一步的是探针类型、结果、阈值与容器生命周期。把每次失败都描述成“重启 Pod”,会抹掉直接影响可用性的关键区别。 三个问题,对应不同动作 启动探针为初始化提供独立的检测政策。配置后,在它成功之前,存活和就绪探针都不会执行。启动探针成功后,在当前容器生命周期内便不再持续检查;如果容器重新启动,则需要再次通过启动阶段,不能把上一次成功沿用到新生命周期。 存活检查用于识别适合通过重启当前容器恢复的状态。达到失败阈值后,kubelet 终止受到影响的容器,并应用对应的重启政策。这不是保证重建整个 Pod、改变其身份或修复外部数据库,也不意味着容器之间的依赖与在途工作都能自动安全恢复。 就绪失败则让容器继续运行,并持续检查是否恢复。它影响通常按就绪状态选择目标的 Service 流量,但不是防火墙,也不会取消已经通过连接到达的请求。直接访问实例的客户端和现有连接,仍需要自己的生命周期处理,不能把就绪状态误读成网络阻断保证。 阈值统计连续观察结果 failureThreshold 为三,不是从启动以来累计失败三次就动作,而是连续失败达到三次;一次成功会打断这段失败序列。就绪恢复可以要求多次连续成功,而启动和存活探针的 successThreshold 必须为一。阅读结果轨迹之前,应先明确进入失败和恢复成功两个方向的阈值。 超时、初始延迟、执行周期和终止宽限期同样影响实际表现。阈值乘周期可以辅助估算,但不能当成端到端故障切换的精确秒表;调度、探针执行和路由传播都参与其中。容器尚未就绪时,就绪探针还可能比配置周期更频繁地执行,以便更快恢复就绪。 实验选择四次启动失败、三次存活失败、两次就绪失败,并要求连续两次就绪成功才能恢复。这组数字只是为了看清不同计数器的边界,不是生产推荐。真实门槛应结合启动时间、检查成本、错误恢复方式以及误判代价确定,不能照搬实验参数。 检查机制决定你拿到了什么证据 HTTP 检查使用文档定义的 200 至 399 成功范围。即使响应正文写着“内部错误”,返回 200 也不会因为人类读出了坏消息,就自动变成失败探针。应沿实际探测路径检查认证和重定向,而不是默认平台与交互式浏览器具有完全相同的访问结果。 TCP 探针证明的是连接可以打开,不是查询或事务能够完成。exec 检查则需要镜像里确实存在相应命令,并且退出状态有明确含义;频繁创建进程还会消耗节点资源。应该选择能够回答当前问题的低成本机制,而不是认为检查越复杂、调用越多就越可靠。 就绪成功并不是存活执行的前提。没有启动探针隔离时,初始化较长的应用可能还没来得及就绪,就因为存活失败反复被终止。相反,启动容忍窗口过大,也会推迟发现真正无法完成的启动。两边都需要依据实际启动分布和恢复目标权衡。 探针失败与 Unknown 结果不是同一种状态。Kubernetes 文档规定 Unknown 不改变容器状态,之后继续检查。本例只接受成功与失败两个值,故意没有第三种结果,所以无法预测传输错误会如何分类。实际排查应检查 kubelet 事件和部署中的探针处理机制,先确认错误属于哪类,再解释是否应计入连续失败。 坏掉的样子 把外部依赖可用性直接作为存活条件,可能在共享故障期间不断重启健康进程;另一个独立线程上始终绿色的处理器,又可能遗漏业务工作线程的死锁。重启并不天然便宜,它会中断在途工作、重复初始化,也可能进一步增加故障依赖的压力。 ...

六月 18, 2027 · 3 分钟 · XB Field Notes
两条独立箭头分别将资源请求连到放置,将资源限制连到运行执行。限制不是调度预留。

资源限制约束运行,请求参与放置

Kubernetes 的资源 request 与 limit 属于不同决策。请求参与调度和资源共享,限制则配置运行时及操作系统支持的执行约束。把 limit 当成调度器预留的容量,会同时混淆这两个机制。有效的资源策略需要说明放置需求、可以接受的争用,以及运行中的工作负载到达边界后应该发生什么,不能只在清单上填写一组看起来合理的数字。 图示区分放置、记账、终止、重启策略与 Pod 驱逐。空闲邻居仅在历史最终观察时仍为 Ready,不能因此推导邻居延迟或完整隔离保证。本次未重跑示例。 CPU 与内存具有不同失败方式 在典型 Linux 环境中,CPU 限制会形成带宽约束,繁忙控制组可能被节流,而进程仍然存活。内存限制依赖内存记账和回收;受约束的分配无法满足时,可能触发控制组 OOM 处理。内核不会像推迟 CPU 使用那样,把所有超限内存申请都温和地放慢。两种资源因此需要不同的容量指标和故障判断方式。 内存执行机制具有反应性,不能描述成恰好达到某个字节就调用应用回调,也不能保证使用量绝对不会短暂超过配置值。应用可能收到分配失败,OOM 处理也可能终止进程。应先观察真实终止原因、容器状态和可用的内存事件,再给故障命名,避免仅因为配置了内存限制,就把所有异常退出都解释成越界。 限制覆盖的不只是应用打算保存的业务数据。运行时开销、其他进程,以及被记账的缓存或其他内存,都可能占用控制组额度。容器限制为六十四 MiB,并不意味着它能在已有开销之外,再安全创建同样大小的数据结构。内存支持的卷也可能贡献内存消耗,表现为文件存储并不会让这部分成本消失。 ...

六月 14, 2027 · 3 分钟 · XB Field Notes
十个期望副本加两个 surge,更新目标为十二;十减一个 unavailable,规划可用预算为九。单独画出的终止尾部可能使总量超过十二。这些预算不能保证不中断。

滚动更新分批换上新版本

滚动更新是一种受控替换,不是服务绝不中断的承诺。它的价值在于引入新副本时可以保留部分旧副本;用户能否平稳完成请求,还取决于资源余量、健康检查是否可信,以及应用如何退出。本文讨论已经选择滚动更新之后怎样调节节奏、怎样观察过程;姊妹篇讨论更靠前的问题:两个版本到底能不能同时运行。 十加二得到十二的目标,十减一得到九的规划预算。正在终止的 Pod、持续就绪与真实请求结果,需要分别核对。 浪涌与缺口 十个期望副本,配 maxSurge: 2,更新目标上限是十二,不是十一。maxUnavailable: 1 给控制器的可用性预算是九个。这不是「每一波最多删除一个旧 Pod」:只要已经有足够的新副本可用,控制器就能继续撤掉多个旧副本。正在终止的 Pod 还可能保留一段时间并继续消耗资源,因此十二也不是所有 Pod 对象或进程数量的绝对上限。 百分比必须先换算整数:surge 向上取整,unavailable 向下取整。三个副本使用默认的百分之二十五,实际就是一个 surge、零个 unavailable。Kubernetes 1.34.0 有一个边界例外:surge 为零、非零的 unavailable 百分比却向下取成零时,控制器会把有效 unavailable 调整为一,让替换能够推进。因此,不能从这个换算得到的零,推断更新一定不会主动减少可用副本。 两个参数都不会替你预留节点资源。选择速度之前,要把资源请求量与可调度容量、命名空间配额、放置约束以及旧 Pod 的退出耗时一起检查。账面上多出的两个位置,并不一定真有节点能承接;新 Pod 全部 Pending 时,调大 surge 也不会凭空生出机器。 ...

六月 7, 2027 · 2 分钟 · XB Field Notes