
一、前言
在“云-边-端”三级架构成为工业互联网、车路协同、智慧零售等新场景默认范式的今天,边缘网关既是流量的第一站,也是算力的第一站。传统做法把网关当作“黑盒路由”,升级靠刷固件、扩容靠换整机,既慢又贵。容器与 Kubernetes 的出现,让我们可以把边缘网关当成“一朵很远的小云”来管理:在同一套编排体系里,既跑轻量路由,又跑 AI 推理,还能像云侧一样灰度发布、弹性伸缩。本文记录我们在某省级车联网项目中将 300 台 x86 工控机升级为“容器化边缘网关”的全过程,分享踩坑与解法。
二、需求与约束
- 业务:每节点需同时承载流量网关(Envoy)、本地消息总线(EMQX)、AI 车牌识别(YOLOv5)以及 OTA Agent。
- 资源:工控机 4C8G、128 GB SSD,无 UPS,现场经常掉电。
- 网络:4G/5G 双网卡,内网网段 172.31.0.0/24,云端通过 VPN 管控。
- 规模:全省 300 台,分批交付,首期 50 台两个月上线。
- 合规:须离线交付镜像包,现场不允许公网 pull。
三、技术选型
- OS:Ubuntu 22.04 LTS + 5.15 RT 内核,裁剪后镜像 1.2 GB。
- 容器引擎:containerd 1.7(比 Docker 省 30 MB 内存)。
- 编排:K3s(单二进制 60 MB,自带 sqlite 省 etcd)。
- 网络:Multus + macvlan 让业务 Pod 直接暴露到二层物理交换机,降低网关转发时延 0.8 ms。
- 镜像分发:基于 Dragonfly P2P 的“离线种子包”,现场 USB 拷入后自动导入 containerd。
- 监控:Prometheus + node-exporter + kube-state-metrics,边缘侧只存 6 小时数据,云侧 Thanos 长期留存。
- OTA:基于 OpenKruise 的 Advanced DaemonSet,支持分批、暂停、回滚。
四、落地步骤
- 镜像工厂
在 GitLab CI 中构建多架构镜像(amd64/arm64),通过 ORAS 把镜像和 Helm Chart 打包为“离线种子包”。一个种子包就是一个 tar.zst 文件,内附 manifest.json,现场解包后自动 ctr images import。 - 系统裁剪
用 Ubuntu Core + cloud-init 无人值守安装;systemd 只保留 12 个服务,内存占用从 350 MB 降至 180 MB。 - K3s 启动参数
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="
--disable traefik
--disable servicelb
--disable metrics-server
--kubelet-arg feature-gates=GracefulNodeShutdown=true" sh -
关闭用不到的组件,单进程即可跑 50 Pod。
- 网络与存储
- 创建 NetworkAttachmentDefinition 把 eth0 和 eth1 分别映射为“lan”和“wan”。
- 用 OpenEBS-hostpath 做本地卷,掉电重启后 fsck 自动修复。
- 业务编排
每个节点运行一个 DaemonSet:gateway-ds,内含四个 container:
- envoy:共享 hostNetwork,监听 80/443。
- emqx:挂载 hostPath 持久化 retained 消息。
- yolo:GPU 版通过 nvidia-device-plugin 暴露 /dev/nvidia0。
- otap:负责回连云侧,上报心跳。
通过 PodAntiAffinity 保证同一城市三个节点不会同时升级。
- 灰度发布
利用 Kruise Rollout,将升级分为 10%→30%→100% 三阶段,每阶段观察 30 min 内 P99 时延和 GPU 利用率。若异常,一键 rollback 只更新 image tag,无需重建节点。 - 现场掉电测试
用 ipmitool 循环硬关机 100 次,验证 sqlite WAL 日志无损坏,Pod 重启时间 8~12 s,满足车联网“秒级自愈” SLA。 - 安全
- 证书:K3s 自动生成 10 年有效期 CA,现场无需再签。
- 镜像签名:cosign + Kyverno 拒绝未签名镜像。
- OTA 加密:种子包 AES-256 加密,USB 交付后现场输入口令解包。
五、踩坑与反思
- containerd 与 kubelet cgroup driver 不统一导致节点 NotReady,解决:/etc/containerd/config.toml 中 SystemdCgroup=true。
- macvlan 在 5.15 内核下与 NetworkManager 冲突,关闭 nm 接管即可。
- YOLO 容器在 35℃ 机箱内触发 CPU 降频,最终通过把推理切到 GPU、CPU 降功耗解决。
- 4G 网络 MTU 1500 导致 VPN 隧道内 TCP 握手失败,改为 1400 后恢复。
- OpenEBS-hostpath 在 ext4 上偶发 “input/output error”,改用 xfs 后消失。
六、性能与收益
- 端到端时延:物理机裸跑 3.2 ms → 容器化 4.1 ms,仍在 5 ms SLA 内。
- 升级时长:传统刷固件 30 min/台 → Kruise 灰度 5 min/台。
- 故障自愈:人工到场 2 h → 30 min 内自动重启 Pod。
- 资源利用率:CPU 从 30% 提升到 65%,单节点每月节省云侧 GPU 费用 480 元。
七、结语
把边缘网关塞进 Kubernetes 并不是“为了技术而技术”,而是让 OT 与 IT 在统一的语言里对话:运维同学用 kubectl get node 就能看到全省 300 台“小云”,研发同学用 Helm upgrade 就能把 AI 模型像更新网页一样推到路口。下一步,我们计划引入 WebAssembly 做“热插拔”协议解析插件,让边缘网关从流量转发器进一步进化为“业务计算节点”。愿本文的实践,能为更多走向云-边协同的团队提供一条可复制的路径。