嵌入式工程师建站踩坑实录:裸机到高可用运维全链路
|
去年六月,我替老张盯他那个嵌入式团队搭的监控平台——就那种裸机焊死在机柜里、启动脚本还带 printf(“\\033[2J”) 清屏的玩意儿。他们连 NTP 都没校,系统时间比 GPS 授时慢四十一秒,但偏偏日志轮转切分逻辑是按小时硬切,结果凌晨两点零三的告警,全堆进 01:00 的归档里。我盯着 kibana 里那团乱麻,听见隔壁机房空调漏水滴在 UPS 散热片上的声音,“嗒、嗒、嗒”,十七下。 我原以为只是 nginx upstream 配得潦草,结果一翻 systemd-unit,发现他们把 supervisor.py 写成 root 运行的 daemon,而这个 Python 脚本居然还 import pexpect —— 用来模拟串口调试器交互。你敢信?一个生产环境 Web 服务进程,自己 spawn 个伪终端去 telnet 自己的串口设备?我截图发群里问是不是测试代码忘删了,小李回:“删了会断温控。” 我当时端着泡面盒,热汤溅到左手虎口,烫得一哆嗦,面条全掉在键盘缝里。那盒泡面是黄焖鸡口味,塑料盖上印着“扫码抽现金”,我扫了,中了十八块七。
文章配图,仅供参考 WAF 规则加了一条又一条还是压不住。不是 CC,是真实用户疯狂点刷新——因为前端拿 setInterval 每八秒轮询 /api/status,后端每轮都重新 mmap 一块 4MB 的共享内存段做环形缓冲,而 mmap 不配 munmap。三天后,OOM Killer 认准了 PID 713 —— 就是那个 supervisor.py。杀它之前,还顺手干掉了 snmpd 和 sshd。整栋楼的安防探头黑了四十秒。运维部老赵冲进来拍我肩膀,说:“邵工,你看看这事儿……” 他衬衫第三颗扣子松了,晃荡着。我没接话,顺手拧紧他扣子。他愣了两秒,转身去翻灭火器年检标签——那标签背面印着去年双十一的促销码,过期了。 弱口令整改?他们后台有个 /debug/hw_info 页面,没关,没鉴权,直接输出整个 SoC 的寄存器快照。密码?是“123456”,明文写在 startup.sh 里第二百三十四行。但最绝的是——他们改完密码,顺手把 auth.conf 备份成 auth.conf.bak,扔进 /var/www/html 下,Apache 默认开放目录遍历。所以攻击者根本不用爆破,直接 GET /auth.conf.bak。我们查日志时发现,七月十二号那天有三百七十二次下载请求,其中一百一十五次来自同一个 ASN,源 IP 全是云厂商的 BGP 中继节点。我说不准是蜜罐还是真肉鸡池,反正那 IP 段下午三点后就没再动过,像被谁掐断了。 那天暴雨。我蹲在四楼弱电间门口换光模块,雨水从吊顶缝隙往下渗,在防静电地板上积成浅洼,倒映着天花板上晃动的应急灯。光模块型号是 SFP-GE-LX,但实际插进去的是千兆多模短距的,眼见着 link up,link down,up,down……反复十九次。旁边实习生小陈举着测光笔,手抖得厉害,汗顺着鬓角往下淌,滴在光纤插头上。我说:“别擦,水膜对衰减有补偿作用。” 他抬头看我,眼神像在确认我是不是喝多了。其实我没喝,但桌上午餐的辣子鸡丁外卖盒还在地上没收,盒盖开着,辣椒皮飘在油花上,像微型红船。 高可用?他们搞了双机热备,主从之间用 UDP 心跳包同步状态。UDP 包长固定六十四字节,前四字节是 magic number(0xDEADBEAF),后面跟个 uint32_t 时间戳。问题出在:时间戳是 uptime 秒数,不是 wall clock。主节点重启后 uptime 归零,从节点收包一看 magic 对、时间戳骤降,立刻触发“主异常”,自己升主。然后两台全当主用——串口指令发双份,继电器咔哒咔哒响得像打桩机。客户投诉说“温控箱温度曲线锯齿状波动”。我没告诉他们这是设计缺陷,只让他们把 magic number 改成 0xC0FFEE00。小李当场在笔记本上画了个咖啡杯涂鸦,杯子冒着热气,气是三条斜线,我敢打包票那三条斜线角度完全一致,48.2 度——我量过。 还有个事不重要,但老堵我心口。六月二十八号,凌晨一点零七分,所有设备突然掉一次电——其实是大楼总闸跳了,消防演练误触联动开关。备用电源撑了四十七秒,够他们保存寄存器,但不够跑完一个完整 HTTP 响应。结果所有未完成的 WebSocket 连接卡在 CLOSE_WAIT 状态,直到超时释放。而他们没设 TCP keepalive,那些连接挂着,足足挂了七十三分钟。期间新连接全被 reject,nginx 错误日志里塞满 “no live upstreams while connecting to upstream”。我那时正往嘴里塞最后一块西瓜,籽吐在右手手背上,没擦。 数据泄露惊魂那次,不是 SQL 注入。是他们把 sqlite 数据库文件放在 /var/www/db/ 下,webroot 可读,而 SQLite 文件名是 device_20240628.db,规律太好猜。拖走的是固件升级日志表,里面存着所有设备最后一次成功握手的 MAC + 固件版本号 + 签名摘要。不算敏感,但够做精准供应链投毒。后来查来源,IP 属于某高校实验室出口网段,访问 User-Agent 是 curl/7.64.0,没有 Referer。老邵你猜怎么着?他们服务器时间比 NTP 慢四十一秒这事,导致数据库里 timestamp 字段全晚了四十一秒,结果那所高校的爬虫程序本地时间没校准,抓下来的日志时间戳全错位——反倒帮我们反向锁定了他们脚本的 sleep 间隔:四点三秒一次请求。这个我敢打包票,因为他们日志里有一行 debug print 是“sleep(4.3)”。 现在那套系统还在跑。没重构,没重写,就修。每次修,都在补丁上叠补丁。我昨天看见他们在 config.h 里加了 #define OVERRIDE_NTP_SYNC_DELAY_MS 30000。注释写着:“给温感模块多三十秒喘息”。我不屑。但上周四我老婆生日,我加班到九点,回去路上看见地铁广告屏在推新 Wi-Fi 标准,帧聚合机制图示里那个 buffer descriptor layout,跟他们串口驱动里的 ringbuf 描述符结构一模一样。我就站那儿看了半分钟,地铁门关了三次。 优胜劣汰?不是优的活下来,是还没崩的苟着。等哪天他们用 RTOS 替掉裸机,用 gRPC 替掉那个自己写的二进制协议,用 cert-manager 替掉 openssl req -x509 -days 3650 -nodes 手动生成证书——我就去申请调岗,去守 CDN 边缘节点。至少那里,故障还能看到 traceroute 跳点。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |




