沙箱底层机制
一轮源码级的沙箱引擎调研沉淀。从隔离、缺页、逃逸讲到资源、存储、镜像、网络、调度,最后收敛到一个判断:七个选型角度其实是「共享不共享内核」这一个决策的七个投影。
共 14 篇
01 给 AI Agent 选沙箱:先决定是否共享内核 启动、资源、存储、网络和调度看似是不同问题,背后首先取决于是否与宿主机共享内核。先做隔离决策,再比较其他指标。 02 沙箱系列(二):缺页如何支撑快照与 CoW 缺页异常把内存访问变成可拦截事件,CoW、快照懒加载与按需映射因此能够延迟复制和恢复成本。 03 沙箱系列(三):三类逃逸对应三类防线 沙箱逃逸分别来自过度配置、运行时组件漏洞和共享内核漏洞;不能用同一种加固措施概括。 04 沙箱系列(四):声明式控制面保存的是期望状态 CRD 定义 Sandbox 的期望状态,Controller 持续对比现实并收敛;可靠性来自重复 Reconcile,而不是一次创建命令。 05 沙箱系列(五):Wasm、eBPF 与 GPU 需要三种独立判断 Wasm 用能力接口限制宿主访问,eBPF 通过加载前验证获得内核执行权,GPU 则依赖设备与驱动隔离;三者不能套用同一种沙箱模型。 06 Agent Runtime 落地:稳定边界在会话与执行合同 沙箱引擎负责隔离与资源,Agent Runtime 负责会话、工具和恢复;统一 Facade 应建立在多 Runtime 需求上,而不是提前抽象单一引擎。 07 沙箱系列(六):「2 核 4G」对应两种资源模型 容器通过 cgroup 实施可调整的共享限额,microVM 在启动时定义虚拟硬件;相同规格具有不同保证与弹性。 08 沙箱系列(七):Warm Pool 与持久挂载存在身份矛盾 Warm Pool 要在用户到来前创建实例,持久挂载却需要先知道用户与 Workspace;两者不能同时作为无条件前置步骤。 09 沙箱系列(八):镜像分层是不是引擎的原生能力 OCI 在文件级原生分层,Firecracker 只接收完整块设备,Kata 则分开提供系统镜像与容器内容;三者的复用成本不同。 10 沙箱系列(九):域名级出口控制属于协议层 容器、gVisor 与 microVM 都不能仅靠隔离引擎表达域名白名单;连接时只剩 IP,需要代理或域名感知策略维护域名与连接的绑定。 11 沙箱系列(十):强隔离会同时增加调度与观测成本 microVM 依赖 KVM、块设备与本地快照,无法像普通容器一样任意放置;Guest 内外还需要两条观测链。 12 沙箱系列(十一):七个工程角度源于同一个隔离决定 隔离、启动、资源、存储、镜像、网络与调度不是独立参数;是否共享宿主内核会沿整条实现链产生后续约束。 13 AgentENV 案例:训练环境为什么选择 microVM 与快照 Agentic RL 需要大量同起点、可分叉且隔离的环境;AgentENV 用 Firecracker、快照与远端块存储组合解决这一约束。 14 沙箱系列(十三):整机分叉的成本由后续写入决定 从运行中 VM 创建多个分支,本质是快照恢复加内存与磁盘 CoW;创建可以很快,长期成本取决于每个分支的脏页和身份重建。
Agent 工程
怎么设计一个 agent 服务。从 loop 内部机制、工具边界、状态持久化,讲到上下文工程、评估、安全、规划模式、可观测与记忆分层。贯穿全系列的判据只有一条:模型只能看到本次请求塞给它的内容,其余必然在 harness。
共 16 篇
01 Agent 工程(一):模型之外,都是 Harness 的职责 模型只处理本次输入,记忆、工具执行、重试、权限和恢复都发生在外部。理解这条边界,才能判断 Agent 功能应该写在哪里。 02 Agent 工程(二):专用工具是在给 Harness 建立可管控边界 是否把一个动作设计成专用工具,取决于 Harness 是否需要识别、拦截、审计或调度它,而不是这个动作能否用 bash 完成。 03 Agent 工程(三):Checkpoint 是执行历史,不是状态备份 Checkpoint 必须记录状态之间的因果关系,才能区分安全续跑与可能重复副作用的重放。 04 Agent 工程(四):只追加存储如何保住 Checkpoint 因果链 Checkpoint 采用只追加记录,是为了保留父子关系、并发顺序和恢复证据;代价是存储增长与版本迁移。 05 Agent 工程(五):上下文工程是在分配注意力预算 上下文不是越完整越好;每条指令和材料都会与已有信息竞争,应根据违反代价、命中率和获取成本决定是否进入。 06 Agent 工程(六):Prompt Cache 优化的是稳定前缀 Prompt Cache 按前缀复用计算;稳定内容必须靠前,动态工具、时间戳和非确定序列化会让后续缓存静默失效。 07 Agent 工程(七):Agent 可靠性的上限取决于目标能否验证 Harness 无法直接理解“完成”,但可以把语义目标转换为退出码、产物校验和评分标准,并据此检测停滞与拒绝错误完成。 08 Agent 工程(八):评估集用于防回归,不用于证明质量 Agent 评估是带噪声的测量;固定样本适合比较改动前后,系统质量仍需由业务结果、线上数据和人工校准共同定义。 09 Agent 工程(九):Prompt Injection 的防线是能力边界 指令与数据进入同一模型通道后,注入无法仅靠文本检测根治;更可靠的策略是限制凭据、工具与网络能力。 10 Agent 工程(十):规划的核心决策是何时重新观察 ReAct、Plan-and-Execute 和 ReWOO 的主要差异,可以归结为执行一步后是否需要回到模型观察结果并重新决策。 11 Agent 工程(十一):一次运行应当记录为因果树 Agent 包含模型、工具、子任务和重试分支;只有保留父子关系的 Trace,才能解释一次运行为何变慢、失败或偏离目标。 12 Agent 工程(十二):记忆应统一接口,而不是统一存储 工作、情景、语义和程序记忆具有不同生命周期与检索方式;统一召回接口可以降低使用成本,但不应抹平存储差异。 13 Agent 工程(十三):用故障合同比较 Agent 架构 功能清单只能说明系统具有什么,故障场景才能说明架构是否可靠。用四个生产问题比较两类 Agent 架构,并给出我的演进判断。 14 Agent 工程(十四):Harness 是逻辑架构,不是部署单元 Harness 描述围绕 Agent Loop 的职责和合同,不规定部署拓扑;Runtime、Memory、Tool、Sandbox 与状态服务可以独立演化。 15 Agent 工程(十五):恢复旧 Run 前必须固定执行合同 Checkpoint 只记录执行位置;跨版本恢复还需要不可变的 AgentVersion、完整的 RunRecord、显式 Migration 与副作用 Reconcile。 16 Agent 工程(十六):多副本执行需要四种秩序标识 消息重复、状态乱序、旧 Owner 回写与稀缺资源重复分配是四类故障,必须分别使用 event_id、status_version、owner_epoch 和 Resource Token。
AgentScope 源码调研
沿着 AgentScope 源码分析服务端会话、工具执行与模型协议适配等关键模块,关注实现证据、职责边界,以及可以迁移到其他 Agent 系统的工程判断。
共 12 篇
01 AgentScope 源码调研(一):Session 为什么不能依赖原进程 服务端会话要跨重启、跨副本继续运行,必须把状态、工作区和唤醒机制移出进程。本文从 AgentScope 源码提炼这条边界。 02 AgentScope 源码调研(二):工具 Schema 为什么不是执行边界 AgentScope 用 Schema 向模型描述工具,却由函数签名、状态注入和执行器决定真实行为;两层不能合并判断。 03 AgentScope 源码调研(三):Formatter 稳定的是内部消息语义 AgentScope 先统一 Msg 与 ContentBlock,再由 Formatter 适配模型协议;抽象价值在于阻止供应商差异进入 Agent Loop。 04 AgentScope 源码调研(四):锁只决定谁能执行 Session Lock 回收执行资格,Checkpoint 保存停留位置,Tool 状态说明外部动作进度;三者共同决定恢复路径。 05 AgentScope 源码调研(五):Event 如何归并为可恢复消息 AgentScope 先把流式 Event 归并到稳定 AssistantMsg,再发布与持久化快照,使刷新和同轮恢复不必重放完整事件。 06 AgentScope 源码调研(六):Session 与 Message 为什么分开存储 Session 是当前状态快照,Message 是按会话增长的有序集合;StorageBase 统一业务语义,但不抹平数据模型差异。 07 AgentScope 源码调研(七):锁之外还需要可验证的执行所有权 Session Lock 控制准入,但旧 Worker 恢复后仍可能写入;Owner Epoch 与 Store Fence 才能让各写入面拒绝过期执行者。 08 AgentScope 源码调研(八):SSE 重连只恢复观察 浏览器断线不应重新运行 Agent;共享事件流、单调游标和消息快照共同恢复客户端观察位置。 09 AgentScope 源码调研(九):工具可见不等于执行授权 Tool Visibility 只限制模型候选动作;可信执行还需要 Policy、HITL、受控 Executor 与独立 Verifier。 10 AgentScope 源码调研(十):Memory 不等于历史消息 AgentState 保持当前执行连续,Long-term Memory Middleware 跨会话检索与写回;两者生命周期和治理要求不同。 11 AgentScope 源码调研(十一):Memory 不能由模型直接判定生效 模型可以从对话中提取记忆候选,但来源、可信度、作用域和有效期必须由确定性 Policy 裁决。 12 AgentScope 源码调研(十二):Memory 召回先做权限过滤 向量分数只表示语义相关;Memory 检索必须先限定租户与用户,再判断可信度、有效期和本轮使用价值。
Agent Sandbox 工程实践
从状态收敛、动作恢复、隔离选型与冷启动优化出发,分析 Agent Sandbox 控制面如何把底层机制组织成可恢复、可运营的平台能力。
共 5 篇
01 Agent Sandbox 工程实践(一):Sandbox 消失后为什么不能直接重建 控制面看到 Sandbox 不存在时,仍需结合任务与外部动作状态判断恢复、失败还是等待确认。资源存在性不能替代业务语义。 02 Agent Sandbox 工程实践(二):创建成功必须拆成四个边界 从业务请求到 Pod 与 execd,创建链路经历多次语义转换;Accepted、Provisioned、Connected 和 Agent Ready 不能共用一个成功状态。 03 Agent Sandbox 工程实践(三):总创建耗时无法定位性能问题 Ready Latency 只能描述用户等待,必须拆分队列、资源创建、调度、容器启动和健康检查,才能形成可治理 SLO。 04 Agent Sandbox 工程实践(四):Command 超时不等于 Sandbox 回收 Command timeout 只应终止本次执行的进程集合;Sandbox 回收处理整个运行载体,PID 1 则负责容器内的进程生命周期。 05 Agent Sandbox 工程实践(五):进程终止不等于文件回滚 Signal 只能终止进程,不能撤销已经发生的文件写入;可恢复的 Sandbox 必须同时设计写入提交协议、挂载边界与完整性校验。
和 AI 协作
怎么指挥 AI 干活。统计下来,我的任务指令几乎不描述「要做什么」,而是描述「不许怎么做」——九条评审以「你对开发过程一无所知」开场,七条禁止读实现代码。贯穿全系列的判断是:刻意制造信息缺口能换到更真的结论,前提是每条禁令都配一份补偿。
共 10 篇
01 编号提问是检查表,不是排版习惯 把问题写成编号列表,等于在回答交付前就加上一张可逐条核对的检查表;它解决的是「哪一条没被回应」这个靠重读答案很难发现的问题。 02 评审的价值来自不知情,不是知情 给评审 agent 补充背景会让它从判断行为转向确认意图。切断过程信息是质量手段,但必须同时补足客观事实,否则它会自行构造一个意图再照着评。 03 禁止读实现代码,才能发现代码里根本没写的分支 边界用例由谁设计决定了它能发现什么:读过实现的设计者只会复述已有分支。禁读实现加手写契约,再与白盒用例求差集,才能暴露契约要求了而代码没做的缺口。 04 给子代理的 prompt 是契约,不是说明 把 424 条派给子代理的任务指令导出来数了一遍:占篇幅最多的是禁令,不是任务描述。描述「要做什么」会让它漂移,描述「不许怎么做」才封得住——前提是每条禁令都配一份补偿,补偿写错了,禁令会把错误原样放大。 05 AI 复核应当要求推翻,而不是要求确认 让模型确认一条结论的成本远低于推翻它,因此复核指令必须把默认立场设为不成立,并用三票里两票反驳的多数表决筛掉站不住的结论。 06 对抗复核的信息量在推翻,不在确认 让模型去驳倒结论比让它确认有用得多,但我用 84 个子代理做过头了——编排规模按发现条数线性放大,等于花钱把已经实测确认的事实降级回概率。 07 grep 不到只能证明你搜过的文件里没有 全仓 grep 一个权限标识只命中一处废弃注释,我据此断定权限没发放,结论错了。权限数据活在身份服务的库里,根本不在任何仓库中。否定性证据按强度分四档,「日志里没有」和「grep 不到」是最弱的两档。 08 文档可读性只能由没有上下文的读者判定 作者读自己的文档时会自动补上纸面上没有的背景,所以自评测不出缺口。可读性要用「只读这一份、没有任何背景」的冷读角色去测,逐题标清楚/模糊/没写,并强制列出犹豫点和依赖的背景知识。 09 证明「没漏代码」,只有合完之后重新比一次 git log、branch --contains、diff --stat 都会在包含关系上给出错的答案。实测三种错法的成因,以及我自己那条「必须空 diff」的规则在三分支场景下为什么不成立。 10 做得久不是资源不够,是工具链在中断 一轮实验花了 77 小时,其中 56 小时是断网等人工重连,真正跑实验的时间在一条线上只有 9.3 分钟。只记总时长会把工具链不稳定归因成资源不够,而加机器一分钟都省不下来。
实测与判据
一个数字能不能用来做决定。先量机器自己抖多少,再看样本量和适用边界——同一份报告里 21% 能当结论,3% 只能写「没测出差异」。另一半是「决定不做」:技术上做得到,实测之后判定不做,并写清理由。
共 8 篇
01 差值小于噪声时,只能说没测出差异 实验集群 etcd 写盘常停顿 5 到 12 秒、最长 18.9 秒,被测时间在几十秒量级,噪声占信号 10% 到 20%。在这个噪声底上,21.7 对 21.1 秒只能写「没测出差异」,44.3 对 56.0 秒才算结论。一个性能数字能不能用来做决定,取决于它的噪声底、样本量和适用边界。 02 3.79 倍只在一个前提下成立:模拟节点把镜像下载从分母里删掉了 同一个控制面在两组基准里给出 3.79 倍和不到 5% 两个结论,差别在于快的那组用模拟节点剔除了镜像下载。性能倍数能不能用来改架构,取决于它的分母里省掉了哪段真实开销。 03 只有结构性的慢才是换掉组件的理由 经引擎建沙箱 45.0 秒、直接建 Pod 22.6 秒,预设的「快 30% 就考虑绕开」门槛达标,结论却是不绕开:差距全来自 init 容器少写的一行资源声明。改配置能消掉的慢不构成换掉一个组件的理由。 04 一轮测试全绿,先是测试设计的结论,不是系统的结论 一轮沙箱压测 12 批负载里 10 批全绿,而唯一能证明限流生效的是被拒的那 30/58。从实测数据讲怎么设计一轮能证伪自己的测试:注定被拒的那一批、阴性结果的阳性对照、写在测之前的判据。 05 全绿的那轮测试其实什么都没测到 4 个样本全部通过、对照组 0 通过,但样本的入口根本没进入被测代码。绿灯成立的前提是先证明样本走到了那段代码,这要靠阳性对照单独确认,不能由通过率代劳。 06 8.7 倍的加速,我决定不要 实验集群上一个绕过 Kubernetes 的原型把冷建沙箱做到了 8.7 倍快,但真实训练时序能提前建沙箱,每步只省不到 1 秒。技术可行只是入场券,收益落点、代价归属和有没有人要才决定做不做。 07 Kubernetes 里没有「暂停」,能还回内存的暂停都是退出 约 307 MiB 的沙箱只冻结 CPU,机器可用内存反而少 1 MiB;能还回内存的那种暂停,最后一步是进程真的结束,而 Kubernetes 的生命周期里没有「挂起」这一档。要内存回收,就得放弃一个沙箱一个 Pod。 08 共享 GPU 省下的一半卡,是原本留给突发的余量 模拟测下来,多团队共用一批 GPU 跑同一条任务时间线比专给只慢 0.5%,占卡量只有专给的 47%。但省下的 53% 是专给模式的空转,而空转正是突发缓冲;70% 占用下的「不变慢」,是停掉别队 21 个任务换来的。
排障举证
交付物是根因,不是补丁。环境问题和代码问题落到现象上常常是同一句话,分开它们靠的是时间线对不对得上、对照组差几个变量、以及那条证据到底排除了什么。最弱的一档是「日志里没有」,它什么都证明不了。
共 11 篇
01 静默失败比报错难查,所以宁可显式拒绝 cpu 写成 500M 是 5 亿核,每一层都放行,只表现为创建挂住 120 秒。同一条失效在能力矩阵丢字段、query 参数被忽略、Map 列放错、枚举静默透传上重复出现。报错当场有现场,静默要等到结果不对才发现,那时现场已经没了。 02 日志里的「已取消」是一句局部真话 kubelet 打印 Cancelling current pod sync 时,它说的是自己那个调谐循环,不是下游的镜像拉取。一行日志的作用域只有写它的那个函数知道,要确认信号传到了哪里,得去读调用链。 03 你删了 Pod,镜像还在下 删除 Pod 撤回的是期望状态声明,不是停止指令:kubelet 下发给容器运行时的 context 被 context.WithoutCancel 剥掉了取消能力,正在进行的镜像拉取收不到信号。要让调用方放弃时下载立刻停,拉取必须由平台自己发起。 04 一句报错的字节数比它的文字更能定位抛出点 三句失败文案共用一个 401,响应体 content-length 分别是 37、55、52 字节。减掉 13 字节信封再除以 3,得到 8、14、13 个字;信封长度和字符编码的四种组合里,只有这一种让三个数全部整除。截图能给字数,实测能给字节数,长度是这两种证据唯一能换算的共同单位。 05 证明「不是 Pod 的问题」,靠的是时间线对得上 一个评测服务一天重启三次,我最初用「日志里没有 OOM 记录」当证据,站不住:内存超限是内核直接杀,进程来不及写日志。换成四条能分辨机制的——打分结束那一刻积压的健康检查几毫秒内全部返回 200、三次重启时刻和探针式子算出来的误差都在 1 秒以内、两次重启前打出完整关停日志、同配置的另外两个副本当天零重启。最后一环我没闭上:「被存活探针杀掉」到交付时仍是算出来的,不是读出来的。 06 存活探针超时证明的是答不上话,不是进程死了 一个评测服务的打分代码在 async 函数里直接调同步模型客户端,单次 20 到 45 秒,事件循环被连续占住 60 到 190 秒;探针 30 秒一次、连续 6 次失败才算死,阻塞要越过约 160 秒才触发重启,所以看起来像偶发。「日志里没有 OOM」排除不了内存问题,真正站得住的那条是打分结束瞬间 9 个积压的健康检查在几毫秒内全部返回。 07 select 的 1024 是位图宽度,不是配置项 线上创建 100% 失败、93–110ms 返回,fd 用量 1043 对上限 1048576 只占 0.1%,水位全绿。根因是 select.select 的 fd_set 只有 1024 位,卡的是 fd 编号:进程只剩 2 个 fd、编号 1025,select 照样抛 ValueError。换成 selectors 的代价是状态管理,外加一处新的静默。 08 no healthy upstream 的根因是部署策略,不是探针参数 网关偶发 503 而 CI/CD 显示发布成功,我第一版结论是改就绪探针时间参数,被打回。按秒录 Service 端点列表才看到:Recreate 下端点列表空了 101 秒,2595 次探测抓到 840 个 no healthy upstream;换成 RollingUpdate + maxUnavailable 0 后新旧端点重叠 16 秒,752 次探测 0 个 503。摘端点发生在 Pod 进入 Terminating 的那一秒,当时探针还在返回 200。只测好配置证明不了因果,所以把坏配置临时改回去又跑了一轮。 09 静默降级把 46 次失败变成 46 个坏沙箱 读镜像启动命令失败时原来是「当没事发生继续建」,9-13 这天 46 次读取全失败、46 次创建全部返回成功。读不到就该当场报错,配上创建阶段码和带 code/retryable/executed 的错误体,失败才会暴露在它发生的地方。 10 脱敏挡住的是明文,不是凭证 详情接口把凭证掩码成六个星号,编辑弹窗把出参原样填回表单提交,用户只改了个名字,库里的真 token 就被覆盖成字面量 ******,沙箱带着星号去请求直接 401。服务端补上按 key 还原之后出来第二个问题:同组织成员只改 url、占位符不动,还原逻辑会把真凭证填进去发往他的服务器,他全程没见过明文。 11 以为有网络隔离的集群,实查 0 条规则 生产集群一直被当成有网络隔离,实查一条 NetworkPolicy 都没有。缺规则和规则生效在外部看起来完全一样,所以安全配置只能实地核验;而堵住一条路径,必然连带伤到共用这条路径的东西。
服务设计
一个平台服务该留什么、不该留什么。判据是「绕过它会不会失效」——砍掉六成代码之后只剩五件事:认人、翻译、排队、防重复、转发。其余是这五件事各自的坑:幂等键要带租户、进程内状态锁死副本数、契约里的「做不到」只能有一个出处。
共 13 篇
01 服务该留什么,判据是绕过它会不会失效 一个沙箱服务内置的 7 种 agent 运行框架约占 60% 代码,全部删除,使用方按官方示例自己装;小工具接口 15 天内每项调用 0–7 次,先从 SDK 文档移除、确认无调用再删。留下的五件事是认人、翻译、排队、防重复、转发,共同点是绕过服务就不成立。原型 1818 行标准库 Python,转发层自身开销 2.6 毫秒。 02 限流器在拒绝它本该排的队 一个沙箱服务半个月返回了 4.7 万次 503,99.9% 在 2 秒内。容量不够时,拒绝和排队是两种语义,选错了,调用方拿到的是立刻失败而不是稍后成功。 03 幂等键必须带上租户,否则会把别人的工作区交出去 幂等键是调用方自己取的,两个调用方各按确定性规则取键很容易撞上。只用键算摘要时,后来的请求会认领到前一个正在跑的沙箱,而它挂的是别人的工作目录。摘要里要拼进租户并带长度前缀,占位表用同一个摘要索引,认领前自己再核一遍元数据——服务端的过滤参数写错不会报错,只会放行。 04 进程内状态是单副本的隐性前提 建沙箱幂等表、熔断计数、排队数都在进程内存里,这个沙箱服务的生产副本数因此从 2 降到 1。把幂等的真源写进沙箱自己的 metadata、把 Pod 归属改读控制器写在 CRD 注解里的结果之后,五项状态逐件列表,只剩两项有缺口——当初写进文档的「前置是上 Redis」根本不成立。 05 契约里的「做不到」,在代码里只能有一个出处 七种运行时包成一套 API,能力缺口先写进文档的表、代码里再各写一份判断,核对时发现表里有一条从没成立过。缺口要分真适配、降级加 notice、自动改路三档;判定写成单个常量,同时驱动路由和文案;查询参数的合法集读框架自己的声明;跨服务那份副本只能靠下游回传实跑值来消。 06 取消请求和回收资源是两件事 让客户端只等 50 毫秒就放弃,经引擎建的放弃请求里 16.4% 服务端照样把沙箱建了出来,直接建 pod 时 25.5%。现网一晚多出 49 个没人删的沙箱。客户端断开只结束自己的等待,已写进集群的创建记录要靠补删、对账和「收到报错也当可能已建成」三条一起收。 07 客户端放弃不等于服务端回滚 一晚多出 49 个没人删的沙箱。让客户端只等 50 毫秒就断开,被放弃的请求里仍有 16.4% 到 25.5% 在服务端建成了资源。取消请求和回收资源是两件事,不配补偿机制就会漏。 08 同步等长命令,等的是连接不是结果 一个实验集群 64 并发下跑 72 条长命令,17 条已经结束却没有返回。改法是提交拿编号、按游标读输出,让结果不再依赖那条连接;代价是轮询放大和一张只在单副本下成立的幂等表。 09 沙箱死了,它的 IP 还在为别人服务 转发前只确认「沙箱还活着」挡不住 IP 复用:沙箱死后 Pod IP 几秒内被同节点的新沙箱拿走,发给死沙箱的请求返回 200、执行在别人的容器里。要核对的是 Pod 名、uid、IP 三者,确认目标还是原来那个。 10 灰度能覆盖多少,取决于同一个判定有几份副本 灰度判定接好,真集群上点取消,接口返回成功、任务照常跑完。另一组对外接口自己写了一份取消实现,不读已解析的路由决定、直接去查容器。文件接口是第二处同类缺口。两处都靠真实使用撞出来,单测和本地验证够不着。 11 存活探针查依赖,等于把下游故障翻译成自己的重启 一个看板服务连着 PostgreSQL、ClickHouse 和 Kubernetes API,/healthz 一个都不查,只回答进程还能应答;依赖状态另开 /readyz 给人看,不接任何探针。依赖挂掉时服务要降级,重启和摘流量都只会让它更没用。另一半是探针和安全策略撞车:给机器加防火墙挡住宿主访问容器端口后,kubelet 的 TCP 就绪探针被一起挡住,只能换 exec probe,而判据要重新定。 12 采集间隔该由被观测对象的最短寿命倒推 后台任务每 30 秒扫一次 pod,这个数从沙箱创建接口 60 秒的 TTL 下限倒推。连带定下的还有两个参数:连续 2 轮扫不到才判删、删除时间取最后一次确认存在的时刻而不是当前时刻。 13 你给 gVisor Pod 设的 limits 可能根本没生效 限额写在 Pod spec 里不等于内核会执行它:gVisor 的 sentry 与 stub 进程落在 Pod 的 cgroup 之外,上限完全失去约束力且不报任何错。隔离运行时的资源上限必须实测,并由节点组件在接受业务之前自检。