KubeEdge边缘设备管理系列(六):Mapper-Framework开发示例

作者:王彬丞&杨志佳&刘家伟

针对新版本 Device-IoT 领域的更新,我们计划推出一系列的文章对这些特性进行详细的介绍,大致的文章大纲为:

1. 基于物模型的设备管理 API 设计与实现

2. DMI 数据面能力设计与实现

3. Mapper 开发框架 Mapper-Framework 设计与实现

4. 如何使用 Mapper 完成视频流数据处理

5. 如何使用 Mapper 实现设备数据写入

  1. 如何从头开发一个 Mapper(以 modbus 为例)

在本系列的前几篇文章中,我们详细介绍了基于物模型的设备管理 API、DMI 数据面能力的增强、Mapper-Framework 开发框架的原理、使用 Mapper 进行视频流数据采集上报以及设备数据写入等核心特性,作为系列文章的最终部分,我们将展示如何从零开始开发一个 Mapper 工程,并通过该工程实现对边缘设备的管理。

定义Device CRD

用户需要按照 KubeEdge v1beta1 版本的 Device CRD 定义,以物模型的形式构建 device-model 与 device-instance,具体的定义细节可以参考本系列的第一篇文章

👇🏻 以下是一个具体的示例:

vbnet 复制代码
apiVersion: devices.kubeedge.io/v1beta1kind: DeviceModelmetadata:  name: temperature-modelspec:  properties:    - name: temp                      # define device property      description: The temperature collected by the sensor      type: INT                       # date type of device property      accessMode: ReadWrite  protocol: modbus                    # protocol for device, need to be same with device instance

首先,我们定义了一个名为 temperature-model 的 device-model,该模型用于定义一类温度传感器的共同特性。在这个示例中,temperature-model 描述了温度传感器的一个重要属性 temp。该属性表示温度传感器采集到的温度值,数据类型为 int。此外,设备的通信协议采用了 Modbus 协议,并且 temp 属性的访问方式被设置为"读写"模式。这意味着,Mapper 将会对从设备采集到的数据进行归一化或其他处理后,返回标准化的结果。

bash 复制代码
apiVersion: devices.kubeedge.io/v1beta1kind: Devicemetadata:  name: temperature-instance-01  labels:    model: temperature-modelspec:  deviceModelRef:    name: temperature-model  protocol:    protocolName: modbus    configData:      serialPort: '/dev/ttyS0'      baudRate: 9600      dataBits: 8      parity: even      stopBits: 1  nodeName: edge-node  properties:    - name: temp      visitors:        protocolName: modbus        configData:          register: HoldingRegister          offset: 2          limit: 1          scale: 1          isSwap: true          isRegisterSwap: true      reportCycle: 10000      collectCycle: 10000      reportToCloud: true      pushMethod:        mqtt:          address: tcp://127.0.0.1:1883          topic: temperature          qos: 0          retained: false

接下来,我们定义了一个名为 temperature-instance-01 的 device-instance,代表一个实际的 Modbus 温度传感器设备。在定义中,spec.protocol 字段需要具体说明设备的通信协议参数,在示例中使用 Modbus 协议,并为其定义了典型的通信参数,如串口、波特率等。Mapper 将根据这些参数与设备进行通信,完成数据的采集与交互。

在 spec.properties 字段中,我们定义了与设备模型中一致的 temp 属性,并进一步细化了访问方式。在 visitors 字段中,我们详细列出了 temp 属性的访问方式,包括寄存器类型、寄存器地址以及偏移量等信息。根据这些定义,Mapper 会准确地访问设备的寄存器,从而获取所需的数据。

最后,在 spec.properties.pushMethod 字段中,我们定义了设备数据的推送方式。DMI 数据面支持将设备数据推送到多种目标,包括数据库、用户应用等。具体的推送方式可以参考本系列的第二篇文章

构建Modbus Mapper工程

如果开发者需要构建自定义的 Mapper 插件,可以通过 KubeEdge 的 Mapper-Framework 子仓库生成 Mapper 工程模板。接下来,开发者只需根据设备的具体信息,填充设备初始化、数据采集等功能,即可完成自定义 Mapper 插件的构建。

👇🏻 以下是相关示例:

1、生成 Mapper 工程

开发者首先通过 git clone 命令克隆 KubeEdge 的 Mapper-Framework 仓库[1] ,随后使用 git checkout 指令切换到稳定版本(目前支持的版本为1.16至1.20)并执行 make generate 命令,输入自定义 Mapper 的名称及是否处理流数据等信息,最终生成 Mapper 工程:

生成的 modbus mapper 工程将会被构建到 Mapper-Framework 的同级目录,工程结构可以参考本系列的第三篇文章中提供的详细说明。

2、实现设备驱动功能

在大多数情况下,开发者需要填充 Mapper 工程中的 driver 目录下的两个文件以及 Mapper 的配置文件。

主要的工作集中在 devicetype.go 和 driver.go 文件中。在 devicetype.go 文件中,开发者需要填充设备协议的配置信息及属性访问的字段,而在 driver.go 文件中,需要实现设备初始化、数据获取等具体功能。

👇🏻 以下是相关文件的示例:

lua 复制代码
ype ProtocolConfig struct {    ProtocolName string `json:"protocolName"`    ConfigData   `json:"configData"`}type ConfigData struct {    // TODO: add your protocol config data    SerialPort string `json:"serialPort"`    DataBits   int    `json:"dataBits"`    BaudRate   int    `json:"baudRate"`    Parity     string `json:"parity"`    StopBits   int    `json:"stopBits"`}type VisitorConfig struct {    ProtocolName      string `json:"protocolName"`    VisitorConfigData `json:"configData"`}type VisitorConfigData struct {    // TODO: add your visitor config data    DataType       string  `json:"dataType"`    Register       string  `json:"register"`    Offset         uint16  `json:"offset"`    Limit          int     `json:"limit"`    Scale          float64 `json:"scale"`    IsSwap         bool    `json:"isSwap"`    IsRegisterSwap bool    `json:"isRegisterSwap"`}

在 devicetype.go 文件中,开发者需要填充协议参数(如 ConfigData)和属性访问参数(如 VisitorConfigData)。这些定义必须与 device-instance 中的字段保持一致,以确保 Mapper 能正确解析来自 device-instance 配置文件的参数值,从而实现设备与应用之间的数据交互。

vbnet 复制代码
var clients *sync.Mapvar clientInit sync.Oncefunc initMap() {    clientInit.Do(func() {        if clients == nil {            clients = new(sync.Map)        }     })}func NewClient(protocol ProtocolConfig) (*CustomizedClient, error) {    client := &CustomizedClient{        ProtocolConfig: protocol,        deviceMutex:    sync.Mutex{},        // TODO initialize the variables you added     }     return client, nil}func (c *CustomizedClient) InitDevice() error {    initMap()    klog.Infoln("SerialPort : ", c.ProtocolConfig.SerialPort)    v, ok := clients.Load(c.ProtocolConfig.SerialPort)    if ok {        c.ModbusClient = v.(modbus.Client)        return nil    }    handler := modbus.NewRTUClientHandler(c.ProtocolConfig.SerialPort)    handler.BaudRate = c.ProtocolConfig.BaudRate    handler.DataBits = c.ProtocolConfig.DataBits    handler.Parity = parity(c.ProtocolConfig.Parity)    handler.StopBits = c.ProtocolConfig.StopBits    client := modbus.NewClient(handler)    clients.Store(c.ProtocolConfig.SerialPort, &client)    c.ModbusClient = client    return nil}func (c *CustomizedClient) GetDeviceData(visitor *VisitorConfig) (interface{}, error) {    c.deviceMutex.Lock()    defer c.deviceMutex.Unlock()    var results []byte    var err error    switch visitor.Register {    case "CoilRegister":        results, err = c.ModbusClient.ReadCoils(visitor.Offset, uint16(visitor.Limit))    case "DiscreteInputRegister":        results, err = c.ModbusClient.ReadDiscreteInputs(visitor.Offset, uint16(visitor.Limit))    case "HoldingRegister":        results, err = c.ModbusClient.ReadHoldingRegisters(visitor.Offset, uint16(visitor.Limit))    case "InputRegister":        results, err = c.ModbusClient.ReadInputRegisters(visitor.Offset, uint16(visitor.Limit))    default:        return nil, errors.New("Bad register type")    }    klog.V(2).Info("Get result: ", results)    return results, err}func (c *CustomizedClient) StopDevice() error {    // TODO: stop device    // you can use c.ProtocolConfig    err := c.ModbusClient.Close()    if err != nil {        return err    }    return nil}

在 driver.go 文件中,开发者根据 devicetype.go 中解析得到的协议配置字段和属性访问参数,实现设备驱动的具体功能。例如,在上面的示例中,我们实现了 Modbus 设备的初始化、数据获取以及设备停止等功能。具体实现需要根据所使用设备的协议和操作需求进行定制。

除了设备驱动的实现外,开发者还需要修改 Mapper 的配置文件 config.yaml。一般来说,开发者只需填充 Mapper 的协议名字段(protocol)即可:

javascript 复制代码
grpc_server:  socket_path: /etc/kubeedge/modbus.sockcommon:  name: Modbus-mapper  version: v1.13.0  api_version: v1.0.0  protocol: modbus # TODO add your protocol name  address: 127.0.0.1  edgecore_sock: /etc/kubeedge/dmi.sock

部署自定义Mapper插件

完成自定义 Mapper 工程的构建后,接下来就可以进行编译并将其部署到 KubeEdge 集群中。目前,推荐使用两种部署方式:二进制部署和 Deployment 部署。

➤ 二进制部署

二进制部署适合在开发和调试阶段使用。这种方式操作简便,适合快速运行和排查错误。通过以下命令,开发者可以直接在本地编译并运行 Mapper 插件:

css 复制代码
go run cmd/main.go --v <log level,like 3> --config-file <path to config yaml>

在这条命令中,--v 参数用来设置日志级别,日志级别越高,输出的信息越详细;--config-file 参数则指定了 Mapper 配置文件的路径。

➤ Deployment 部署

当 Mapper 插件经过充分调试并能够稳定运行后,建议将其以容器的形式部署到 KubeEdge 集群中。通过使用 Mapper-Framework 生成的 Dockerfile,开发者可以构建 Docker 镜像并创建 Kubernetes Deployment,以便在生产环境中稳定运行。

👇🏻 以下是一个示例 Deployment 配置:

javascript 复制代码
apiVersion: apps/v1kind: Deploymentmetadata:  name: modbus-mapperspec:  replicas: 1  selector:    matchLabels:      app: demo  template:    metadata:      labels:        app: demo    spec:      nodeName: edge-node # replace with your edge node name      containers:        - name: demo          volumeMounts: # Required, mapper need to communicate with grpcclient and get the config            - name: test-volume              mountPath: /etc/kubeedge          image: modbus-mapper:v1.0.0 # Replace with your mapper image name          imagePullPolicy: IfNotPresent          resources:            limits:              cpu: 300m              memory: 500Mi            requests:              cpu: 100m              memory: 100Mi          command: ["/bin/sh","-c"]          args: ["/kubeedge/main --config-file /kubeedge/config.yaml --v 4"]      volumes:        - name: test-volume          hostPath:            path: /etc/kubeedge            type: Directory

完成自定义 Mapper 插件的部署后,用户可以向集群创建 device-model 和 device-instance 资源,随后 Mapper 将收到通知并开始进行设备的管理,定期获取设备数据并进行推送。这样,就完成了边缘设备的云原生化管理,使设备的生命周期、数据采集、处理和推送过程都能够在云原生架构下高效、可靠地进行。

通过本系列技术文章的深入探讨,我们全面分析了 KubeEdge 在 Device-IoT 领域的创新与实践,重点涵盖了基于物模型的设备管理 API、DMI 数据面能力的增强、Mapper-Framework 的设计与实现、使用 Mapper 完成视频流数据处理、设备数据写入以及自定义 Mapper 工程开发的实际案例。这些内容充分展示了 KubeEdge 如何有效推动边缘计算与物联网技术的融合,为边缘设备的云原生化管理提供了切实可行的解决方案。

随着物联网设备的日益普及以及边缘计算需求的持续增长,KubeEdge 在设备管理和数据处理方面的独特优势将愈发突出。通过这一系列功能的实现,KubeEdge 为物联网设备的管理、数据流的处理以及边缘计算任务的执行提供了强大支持。我们期待更多开发者加入 KubeEdge 社区,共同为全球的边缘计算生态贡献力量。

相关链接:

1\] Mapper-Framework 仓库:[github.com/kubeedge/ma...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fkubeedge%2Fmapper-framework "https://github.com/kubeedge/mapper-framework") \*\*【更多KubeEdge资讯推荐】\*\*玩转KubeEdge保姆级攻略------环境搭建篇 **玩转KubeEdge保姆级攻略------环境搭建篇** 《玩转KubeEdge保姆级攻略------环境搭建篇》课程主要介绍如何通过华为云服务快速搭建一套KubeEdge边缘计算开发平台及部署Sedna、EdgeMesh等KubeEdge生态组件。 [课程免费学习链接](https://link.juejin.cn?target=https%3A%2F%2Fconnect.huaweicloud.com%2Fcourses%2Flearn%2Fcourse-v1%3AHuaweiX%2BCBUCNXNX022%2BSelf-paced%2Fabout "https://connect.huaweicloud.com/courses/learn/course-v1:HuaweiX+CBUCNXNX022+Self-paced/about"):[connect.huaweicloud.com/courses/lea...](https://link.juejin.cn?target=https%3A%2F%2Fconnect.huaweicloud.com%2Fcourses%2Flearn%2Fcourse-v1%3AHuaweiX%2BCBUCNXNX022%2BSelf-paced%2Fabout "https://connect.huaweicloud.com/courses/learn/course-v1:HuaweiX+CBUCNXNX022+Self-paced/about") \*\*KubeEdge社区介绍:\*\*KubeEdge是业界首个云原生边缘计算框架、云原生计算基金会(CNCF)唯一毕业级边缘计算开源项目,社区已完成业界最大规模云原生边云协同高速公路项目(统一管理10万边缘节点/50万边缘应用)、业界首个云原生星地协同卫星、业界首个云原生车云协同汽车、业界首个云原生油田项目,开源业界首个分布式协同AI框架Sedna及业界首个边云协同终身学习范式,并在持续开拓创新中。 KubeEdge网站 : [kubeedge.io](https://link.juejin.cn?target=https%3A%2F%2Fkubeedge.io "https://kubeedge.io") GitHub地址 : [github.com/kubeedge/ku...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fkubeedge%2Fkubeedge "https://github.com/kubeedge/kubeedge") Slack地址 : [kubeedge.slack.com](https://link.juejin.cn?target=https%3A%2F%2Fkubeedge.slack.com "https://kubeedge.slack.com") 邮件列表 : [groups.google.com/forum/#!for...](https://link.juejin.cn?target=https%3A%2F%2Fgroups.google.com%2Fforum%2F%23!forum%2Fkubeedge "https://groups.google.com/forum/#!forum/kubeedge") 每周社区例会 : [zoom.us/j/416723730...](https://link.juejin.cn?target=https%3A%2F%2Fzoom.us%2Fj%2F4167237304 "https://zoom.us/j/4167237304") Twitter : [twitter.com/KubeEdge](https://link.juejin.cn?target=https%3A%2F%2Ftwitter.com%2FKubeEdge "https://twitter.com/KubeEdge") 文档地址 : [docs.kubeedge.io/en/latest/](https://link.juejin.cn?target=https%3A%2F%2Fdocs.kubeedge.io%2Fen%2Flatest%2F "https://docs.kubeedge.io/en/latest/")

相关推荐
阿里云云原生2 分钟前
十几行代码实现 Manus,Spring AI Alibaba Graph 快速预览
云原生
andrew_121910 分钟前
docker底层原理简述
linux·docker·容器
Ares-Wang12 分钟前
kubernetes》》k8s》》证书有效期
云原生·容器·kubernetes
庸子15 分钟前
Docker镜像与容器概念解析
运维·docker·容器
李菠菜26 分钟前
配置Docker国内镜像加速
docker·容器
阿里云云原生29 分钟前
OpenManus:开源版 Manus,无需邀请码,5 分钟极速体验!
云原生
CheungChunChiu1 小时前
Qt 容器类使用指南
linux·开发语言·c++·qt·容器
满怀10152 小时前
【计算机网络】现代网络技术核心架构与实战解析
网络协议·tcp/ip·计算机网络·架构·云计算·网络工程
网络风云2 小时前
云计算领域需掌握的核心技术
云计算
庸子3 小时前
解析虚拟机与Docker容器化服务的本质差异及Docker核心价值
运维·docker·容器