把边缘设备(udev/ONVIF/OPC UA)发现并暴露成Kubernetes原生资源的框架
Akri 是 CNCF Sandbox 项目,微软主导,自我定位是「A Kubernetes Resource Interface for the Edge」。它解决的问题是:边缘设备(USB 摄像头、IP 摄像机、PLC、传感器)不是 Kubernetes 资源,业务 Pod 想用它们只能靠 hostPath、特权容器或写死 IP,既不可移植也无法共享。
Akri 的做法是把设备发现与使用声明化:你写一个 Configuration 说明「我要找什么样的设备」,Akri 自动发现设备、为每个设备创建一个 Instance 对象,并按需为它拉起一个 broker Pod;业务 Pod 则像申请 CPU 一样申请设备资源。
当前版本 v0.14.0(2026-09-01),项目仍在维护。但要注意它的发布节奏偏慢:上一个正式版本 v0.13.8 发布于 2024-11-20,中间近两年没有正式发布,而 v0.14.0 是一次大规模的依赖与基线更新,带来了硬性破坏性变更,升级前必须确认集群版本(见下文)。
很多介绍把 Akri 描述成「接入 MQTT/ONVIF/OPC UA 的框架」,这是不准确的。Akri 内置的 Discovery Handler 只有四个:
udev 发现节点上本地连接的硬件(USB 摄像头、串口设备等)
ONVIF 发现网络中的 IP 摄像机(ONVIF 协议)
OPC UA 发现工业自动化服务端 / Local Discovery Server
debugEcho 调试用的假设备,用于验证链路,不做真实发现
没有内置的 MQTT Discovery Handler。 MQTT 在边缘场景里通常出现在数据上报环节(设备 → 边缘应用 → 云端),而不是设备发现环节 —— 例如 KubeEdge 的 EventBus 用 MQTT 对接 mosquitto。要接入 MQTT 设备,需要按 Akri 的 Discovery Handler 接口自己实现一个(官方提供 Rust 模板 project-akri/akri-discovery-handler-template)。
Discovery Handler 按协议发现设备,通过 Unix socket(默认 /var/lib/akri/agent-registration.sock)
向 Agent 注册,实现 gRPC 的 DiscoveryHandler 服务
Akri Agent 以 DaemonSet 运行在带设备的节点上,调用 Discovery Handler 做发现
为每个发现的设备创建 Instance 自定义资源
Akri Controller 监听 Instance,按 Configuration 中的模板部署 Broker Pod
Broker 每个设备(或每组设备)一个 Pod,业务通过它使用设备
例如摄像机 broker 负责拉流并对外提供视频接口
数据流是:Configuration(你要什么)→ Agent 发现 → Instance(发现了什么)→ Controller 创建 Broker → 业务 Pod 申请设备资源并使用。
CRD 的组/版本是 akri.sh/v0,Kind 是 Configuration 与 Instance:
# 注意:Kind 是 Configuration / Instance,
# 文档里的「Akri Configuration」「Akri Instance」是叙述用词,不是 Kind 名
kubectl get configurations.akri.sh -A
kubectl get instances.akri.sh -A
Instance 由 Agent 自动创建与维护,业务方不应手工编辑它;它的 deviceUsage 字段记录设备的占用槽位,是多个 Pod 共享同一设备时的协调依据。
apiVersion: akri.sh/v0
kind: Configuration
metadata:
name: akri-udev-video
spec:
discoveryHandler:
name: udev
discoveryDetails: |+
udevRules:
- KERNEL=="video[0-9]*"
brokerPodSpec:
containers:
- name: akri-udev-video-broker
# 占位镜像;实际部署换成协议对应的 broker
# 注意:v0.14.0 起样例 broker 迁至 project-akri/examples,
# 旧的 ghcr.io/project-akri/akri/<sample>:latest-dev 引用不再可解析
image: nginx
resources:
requests:
"{{PLACEHOLDER}}": "1"
securityContext:
privileged: true
instanceServiceSpec:
type: ClusterIP
ports:
- name: video
port: 80
targetPort: 8080
capacity: 1
discoveryDetails 的内容由各个 Discovery Handler 自己定义(udev 收的是 udev 规则,ONVIF 收的是探测网段等),写错不会报错,只会「什么都没发现」。
helm repo add akri-helm-charts https://project-akri.github.io/akri/
helm repo update
# 最小安装(仅控制器与 Agent)
helm install akri akri-helm-charts/akri
# 同时启用 udev 的发现与配置,并指定 broker 镜像
helm install akri akri-helm-charts/akri \
--set udev.discovery.enabled=true \
--set udev.configuration.enabled=true \
--set udev.configuration.discoveryDetails.udevRules[0]='KERNEL=="video[0-9]*", ENV{ID_V4L_CAPABILITIES}==":capture:"' \
--set udev.configuration.brokerPod.image.repository=nginx
# Agent 镜像中内置 udev/OPC UA/ONVIF 三个 handler,简化部署
helm install akri akri-helm-charts/akri --set agent.full=true
# 升级
helm upgrade akri akri-helm-charts/akri --set udev.discovery.enabled=true
# 卸载(注意 CRD 需要手动删除)
helm delete akri
kubectl delete crd instances.akri.sh
kubectl delete crd configurations.akri.sh
业务 Pod 像申请扩展资源一样申请设备:
resources:
limits:
akri.sh/akri-udev-video: "1" # 按 Configuration 名申请,由 Agent 分配具体设备
两种粒度:
实例级资源 名字形如 <configuration-name>-<instance-id>,直接锁定某个具体设备
配置级资源 名字就是 akri.sh/<configuration-name>,Agent 自行挑选空闲设备
capacity 决定一个设备能被多少个节点/负载同时使用。摄像机这类独占设备设为 1;串口之类的可共享设备可以调大,但要在 broker 里自行处理并发。
三者不是竞品:
KubeEdge / OpenYurt 解决「边缘节点如何被 Kubernetes 管理」—— 计算与网络的延伸
Akri 解决「边缘设备如何被 Kubernetes 使用」—— 设备与协议的接入
实际部署中常见组合是:边缘侧用 kubeedge 或 openyurt 管理节点,节点上跑 Akri 把摄像头、PLC 暴露给业务 Pod。Akri 自己只要求一个能跑 DaemonSet 与 CRD 的 Kubernetes 集群。
Akri 复用的是 Kubernetes 的设备插件(Device Plugin)机制 —— 通过 akri.sh/<configuration> 这种扩展资源名申请设备。而 Kubernetes 从 1.34 起把 DRA(Dynamic Resource Allocation)推到了 GA,并在 1.35 之后锁定特性门控,它被普遍视为设备插件机制在高级设备分配场景的长期方向。
设备插件(Device Plugin) 只支持整数计数的扩展资源,表达能力有限
仍是稳定机制,官方未宣布废弃
DRA(resource.k8s.io/v1) 支持设备属性、容量、共享、按条件筛选
Akri 社区已有与 DRA 结合的探索(KubeCon EU 2024 有专门分享)
同一节点上,DRA 驱动与设备插件不能同时管理同一类设备 —— 会导致静默的超分
对 Akri 的选型意味着两点:短期内设备插件机制仍然可用,Akri 现有写法不会立刻过时;但中长期要关注 Akri 是否跟随 DRA 演进,尤其是在需要「按属性筛选设备」「多容器共享同一设备配额」这类需求的场景。
k8s-openapi 固定到 v1_33,镜像在低于 1.33 的集群上无法正常工作。老边缘集群(常见 1.22-1.28)要么先升集群,要么停留在 v0.13.8。Configuration,不是 AkriConfiguration。网上不少文章写成 kind: AkriConfiguration / kind: AkriInstance,照着写会被 apiserver 拒绝。正确写法是 apiVersion: akri.sh/v0 配 kind: Configuration 或 kind: Instance。Instance 由 Agent 创建,不要手工改。它的 deviceUsage 是设备共享的协调状态,手工编辑会与 Agent 的期望状态冲突,导致设备「显示被占用但实际没人用」。discoveryDetails 写错不会报错。它是交给 Discovery Handler 自行解析的字符串,格式错误时表现为「Configuration 状态健康、但一个 Instance 都没有」,排障要看 Agent 与对应 handler 的日志。securityContext.privileged: true 与宿主机路径挂载是必需的;这在受限的 Pod Security 策略下会直接被拦。project-akri/examples,原先固定的 ghcr.io/project-akri/akri/<sample>:latest-dev 引用不再可解析,照旧文档拉镜像会 ImagePullBackOff。helm delete 不会删除 CRD。instances.akri.sh 与 configurations.akri.sh 需要手动清理,否则重新安装时会带着旧的设备记录;彻底卸载后残留的 Instance 对象还会让新装的 Agent 误以为设备已被占用。opcua 0.12 冻结版本带来若干未清除的 RUSTSEC 告警,官方计划迁移到 async-opcua。用 OPC UA 的场景应关注这一进度,或把 OPC UA 的接入放在隔离的网络段内。Instance 出现之间会有延迟;把它当作「实时」的能力来设计业务流程会踩坑。kubectl — Kubernetes集群管理工具helm — 安装 Akri 的 chartkubeedge — 边缘节点管理,可与 Akri 组合openyurt — 存量集群的边缘改造,可与 Akri 组合k3s — 边缘侧轻量发行版crictl — 排查 broker 容器multus — 多网卡场景下常与设备接入配合device-plugin — Akri 复用的 Kubernetes 设备插件机制