加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.beijidao.cn/)- 应用程序、AI行业应用、CDN、低代码、区块链!
当前位置: 首页 > 服务器 > 系统 > 正文

嵌入式容器化:资源受限设备轻量级K8s实践

发布时间:2026-10-27 11:18:38 所属栏目:系统 来源:DaWei
导读:  跟产品经理吵完第三轮之后,我蹲在工位上把 kubelet 从 arm64 的 v1.27.3 换回 v1.26.9——就为躲那个 cgroup v2 的 memcg stat 竞态,你敢信?不是 bug,是设计哲学冲突。他举着 Jira 链接说“用户期望容器秒启”,我敲 `

  跟产品经理吵完第三轮之后,我蹲在工位上把 kubelet 从 arm64 的 v1.27.3 换回 v1.26.9——就为躲那个 cgroup v2 的 memcg stat 竞态,你敢信?不是 bug,是设计哲学冲突。他举着 Jira 链接说“用户期望容器秒启”,我敲 `kubectl get nodes` 卡住三秒,他以为我在等 API 响应,其实我在等 `/sys/fs/cgroup/memory/kubepods.slice/memory.max` 被 kernel 回写完。这玩意儿在 512MB RAM 的 i.MX8M Plus 上不是配置项,是赌注。


  我原以为把 CRI 换成 containerd 就能省下八十七兆内存,结果实测下来——省了七十三兆,多出十四兆是在 containerd-shim 启动时 mmap 了两遍同一个 seccomp BPF 字节码。这个我敢打包票,抓了三次 perf trace,第二帧的 `mmap` offset 是 0x12b000,第三帧是 0x12b000 ——完全一样,但页表没共享。为什么?我不知道。内核版本对不上,我们跑的是 yocto dunfell + linux-5.10.124,patch 不进 mainline 的那堆 cgroup fd leak 修复。我说不准。


  旁边老张又去倒水了,接水时手抖,水溅到那个印着 K8s logo 的搪瓷杯外壁,顺着杯沿滴到键盘左下角。他键盘的 Ctrl 键卡了一下——不是失灵,是按下去有顿挫感,像里面塞了半粒米。我瞥见他 Chrome DevTools 正停在 Application → Storage → IndexedDB tab,标签页名写着“offline-cache-v2 (not used)”。


  优胜劣汰。就这四个字,两个月之前我们在车间现场联调完第十八台网关盒子,烧录固件后一开机,三台挂了,一台 Pod 启不起来,两台跑着跑着 kube-proxy 直接 SIGSEGV——不是 panic,是段错误。没有 core dump,因为 ulimit -c 是 0,且 /proc/sys/kernel/core_pattern 指向 `/dev/null`,连日志都懒得记。我们当场就把那五台机器从交付清单里划掉了。不是修,是剔除。嵌入式不讲容错,讲筛选。K8s 在这儿不是编排器,是压力筛子。跑不过 preflight check 的节点,连 join token 都领不到。测试小妹拿示波器量过 boot time:从 uboot load zImage 开始计时,到 kubelet Ready 状态上报,超过 10.3 秒的板子自动踢出集群。她说这数字是 PM 定的,我没争——因为我自己测过,在环境温度 42℃ 下,SD 卡读取延时突增导致 initramfs 解压超时,那 10.3 秒里,有 0.8 秒是等 eMMC controller 报 status bit,纯硬件抖动。


  工位双屏左边壁纸是去年北海道函馆拍的夜港,渔船灯串连成斜线;右边壁纸是 `kubectl top nodes` 的截图,timestamp 那行被我用 redact 工具涂黑,但右下角露出半截 terminal 提示符 `root@n3:/#`,字体是 JetBrains Mono。我不记得换过这个字体,可能是某次 tmux session 残留。汤洒了一滴,在键盘空格键右侧,褐色,偏粘,干了以后反光。


  containerd 的 `config.toml` 里写了 `[plugins."io.containerd.grpc.v1.cri".registry.mirrors]`,但我们所有镜像都打在本地 registry:`10.42.1.3:5000/edge-metrics:sha256-…`,那个 sha256 值我抄错两次,第一次少一位,第二次把 `a` 写成 `q`,部署后拉镜像失败,报 `manifest unknown`,log 里只吐一行 `failed to resolve reference`,没上下文。你得自己比对 digest。后端兄弟提 PR 改了 helm chart 的 image tag,commit message 写“fix typo”,没提是哪个字符。我花了四十一分钟才 diff 出来。他现在坐我斜后方,正对着屏幕念 CSS 类名:“`card-header--primary--compact`……不对,`card__header--primary--compact`?等等,`card-header__primary--compact`?” 我没理他。


  还有个细节:kube-proxy 的 `--proxy-mode=iptables` 在 armv7 架构上会偶发规则丢失——不是全丢,是每二十次重载,有一条 DNAT 规则没写进 `iptables-save` 输出里。你查 `ipvsadm -ln` 是满的,但 `iptables -t nat -L KUBE-SERVICES` 缺一条。它总缺同一类服务的规则:ClusterIP 类型、targetPort 为 9102 的那个 metrics exporter。为什么偏偏是它?因为它的 service.yaml 里 annotations 多了一行 `prometheus.io/scrape: "true"`,导致 kube-proxy 的 reflector 在 watch event 处理链路上多走一个 predicate 分支,而那个分支里有个 map access 在某些内核调度序列下竞态返回 nil。我们最后把它拆成两个 Service 对象绕过去了。但这事没人写进 release note,文档里连提都没提。


  PR review 的时候我说“这段 patch 先放着”,PM 在 Slack 里回了个 ???? 表情,配文“先上车,后面补票”。后来发现 ticket 闭环时间戳是下午三点十七分,但那天我手机锁屏界面显示下午三点十七分的时候,正在地铁口买煎饼果子——我根本没看钉钉。所以到底谁点的 close,我说不准。反正那个 `node-taint` 自动注入逻辑,上线第二天就被回滚了,不是因为崩溃,是因为 taint key 写成了 `node-role.kubernetes.io/edge`,而 node-label 实际是 `kubernetes.io/os=linux`,导致 cordon 掉一半不该 cordon 的节点。这不是 bug,是命名习惯错位。你们组还坚持用 BEM 吗?算了,不问了。


文章配图,仅供参考

  下一步?我已经把 cluster-autoscaler 删了。它在资源受限设备上不是扩展器,是断食教练。现在用 cronjob 调 `kubectl drain --force --ignore-daemonsets` 手动踢节点,脚本里加了随机 jitter(0–90 秒),避免所有边缘盒子同时掉线。别笑——上次我们搞了一个全局 `kubectl rollout restart deployment`,三十七台设备里的二十二台,在重启 kubelet 过程中把 watchdog timer 没喂上。Watchdog 不是 Linux 的,是裸机硬件 watchdog,独立于 kernel,复位信号直接捅进 SoC reset 引脚。那晚我改了八遍重启脚本,最后一版里加了一句 `sleep $((RANDOM % 90))`。现在它跑得最稳。

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!