問題描述
對KubeEdge整體框架了解之后,對于mapper有幾個細(xì)節(jié)上的問題還不清楚
- 對于多個同類型的device,是共用一個mapper還是會起多個mapper實例
- cloud如何下發(fā)device profile、更新profile到mapper
官方文檔說明

The idea behind using config map to store device properties and visitors is that these metadata are only required by the mapper applications running on the edge node in order to connect to the device and collect data. Mappers if run as containers can load these properties as config maps . Any additions , deletions or updates to properties , visitors etc in the cloud are watched upon by the downstream controller and config maps are updated in etcd. The existing edge controller already has the mechanism to watch on config map updates and push them to the edge node. A mapper application can get these updates and then adjust the data collection process. A separate design proposal can be prepared to illustrate the details of how mappers can leverage these config maps.
If the mapper wants to discover what properties a device supports, it can get the model information from the device instance. Also , it can get the protocol information to connect to the device from the device instace. Once it has access to the device model , it can get the properties supported by the device. In order to access the property , the mapper needs to get the corresponding visitor information. This can be retrieved from the propertyVisitors list. Finally , using the visitorConfig, the mapper can read/write the data associated with the property.
下面是官方給的configMap的例子
apiVersion: v1
kind: ConfigMap
metadata:
name: device-profile-config-01 // needs to be generated by device controller.
namespace: foo
data:
deviceProfile.json: |-
{
"deviceInstances": [
{
"id": "1",
"name": "device1",
"protocol": "modbus-rtu-01", // needs to be generated by device controller.
"model": "SensorTagModel"
}
],
"deviceModels": [
{
"name": "SensorTagModel",
"description": "TI Simplelink SensorTag Device Attributes Model",
"properties": [
{
"name": "temperature",
"datatype": "int",
"accessMode": "r",
"unit": "Degree Celsius",
"maximum": "100",
},
{
"name": "temperature-enable",
"datatype": "string",
"accessMode": "rw",
"defaultValue": "OFF",
}
]
}
],
"protocols": [
{
"name": "modbus-rtu-01",
"protocol": "modbus-rtu",
"protocolConfig": {
"serialPort": "1",
"baudRate": "115200",
"dataBits": "8",
"parity": "even",
"stopBits": "1",
"slaveID": "1"
}
}
],
"propertyVisitors": [
{
"name": "temperature",
"propertyName": "temperature",
"modelName": "SensorTagModel",
"protocol": "modbus-rtu",
"visitorConfig": {
"register": "CoilRegister",
"offset": "2",
"limit": "1",
"scale": "1.0",
"isSwap": "true",
"isRegisterSwap": "true"
}
},
{
"name": "temperatureEnable",
"propertyName": "temperature-enable",
"modelName": "SensorTagModel",
"protocol": "modbus-rtu",
"visitorConfig": {
"register": "DiscreteInputRegister",
"offset": "3",
"limit": "1",
"scale": "1.0",
"isSwap": "true",
"isRegisterSwap": "true"
}
}
]
}
從官方的說明看,cloud是通過config map將device profile傳遞給mapper的。
從官方給的config mapper的例子看,deviceInstances、deviceModels這些都是以List形式出現(xiàn)的,說明一個config map應(yīng)該是能描述多個device profile的。這一點在官方的Scability說明中其實也有提到
Currently, we have only one config map per node which stores all the device instances, device models, protocols and visitors for all the devices connected to the edge node. Mappers running on an edge node managing different devices now need to access one global configmap in order to extract information about the device properties and visitors. What should be the best way to partition a monolithic config map into smaller config maps ? Should the partitioning be based on the protocol type or based on device model ?
twin
這里注意下device instance中的twin沒有被放到configmap中,這就導(dǎo)致了mapper在report property的值的時候,不會考慮這個值是否在twin中。少了一個篩選的過程。
Mapper代碼分析
DockerFile
COPY src/ /opt/src
COPY conf/ /opt/src/conf
COPY scripts/ /opt/scripts
這里看到src目錄被放到了/opt/src下
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: modbus-device-mapper-deployment
spec:
replicas: 1
selector:
matchLabels:
app: modbus-mapper
template:
metadata:
labels:
app: modbus-mapper
spec:
hostNetwork: true
containers:
- name: modbus-mapper-container
image: <your_dockerhub_username>/modbus_mapper:v1.0
env:
- name: CONNECTOR_MQTT_PORT
value: "1883"
- name: CONNECTOR_MQTT_IP
value: 127.0.0.1
- name: CONNECTOR_DPL_NAME
value: dpl/deviceProfile.json
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
volumeMounts:
- name: dpl-config-volume
mountPath: /opt/src/dpl
nodeSelector:
modbus: "true"
volumes:
- name: dpl-config-volume
configMap:
name: device-profile-config-<edge_node_name>
restartPolicy: Always
這里注意下volumes和volumeMounts的配置,可以看出,dpl-config-volume這個config map會被掛載到/opt/src/dpl目錄,結(jié)合config profile中的key:deviceProfile.json,因此,edge core會在dpl目錄下生成并更新deviceProfile.json文件
src/index.js
function(callback) {
WatchFiles.loadDpl(options.dpl_name, (devInsMap, devModMap, devProMap, modVistrMap)=>{
devIns = devInsMap;
devMod = devModMap;
devPro = devProMap;
modVistr = modVistrMap;
callback();
});
},
options.dpl_name配置的就是dpl/deviceProfile.json,因此,modbus_mapper初始化的時候,就加載了deviceProfile.json文件。
WatchFiles.watchChange(path.join(__dirname, 'dpl'), ()=>{
async.series([
function(callback) {
WatchFiles.loadDpl(options.dpl_name, (devInsMap, devModMap, devProMap, modVistrMap)=>{
devIns = devInsMap;
devMod = devModMap;
devPro = devProMap;
modVistr = modVistrMap;
callback();
});
},
...
除了啟動的時候,一次性讀取deviceProfile.json以外,還創(chuàng)建了一個線程用于監(jiān)測deviceProfile.json文件的更新(刪除并重新添加),如果檢測到更新,那么用新的config map來更新本地緩存,然后新建一個和mqtt broker的連接,監(jiān)聽并處理消息。
如何處理消息見《KubeEdge分析-mapper與deviceTwin交互流程》