作者:
涂家英,SUSE 资深架构师,专注 Cloud-Native 相关产品和解决方案设计,在企业级云原生平台建设领域拥有丰富的经验。
写在前面
k3s 是 SUSE 推出的为物联网和边缘计算构建的经过认证的 Kubernetes 发行版,它可以帮助用户在资源受限的场景下使用 kubernetes,并结合 SUSE Rancher 实现云边协同。
将 k3s 与微软开源的 kubernetes 边缘项目 Akri 结合使用,用户就拥有了在边缘环境发现和使用各种 IOT 设备的能力。
架构
Akri 目前是 CNCF 的一个开源项目,其功能简单地说就是可以根据配置自动地寻找到相应的 iot 设备,为其创建关联的工作负载,并且通过不断地检测实现工作负载的动态变化。引用一句官方的描述为:You name it, Akri finds it, you use it.
架构如下:
包含了 Controller 服务、Agent 服务和 Discovery Handlers 服务以及两个 CRD 资源。
具体的组件解析可以查看官方文档:https://docs.akri.sh/architecture/architecture-overview
下面我们通过一个示例来更好地理解 Akri 的工作方式。
体验
示例使用了官方提供的一个 OPC UA 温度计 Demo,OPC UA 是现在使用比较广泛的工业自动化通信协议,我们可以通过 Akri 自动发现使用 OPU CA 协议的温度计设备,并为其创建工作负载,采集和使用其产生的温度数据。
示例中体现的大致工作流程如下:
首先需要模拟出两台 OPC UA 的服务设备,然后在 k3s 集群上部署 Akri 服务,基础工作完成后:
- 向集群配置用于发现 OPC UA 设备的 CRD(Configuration)
- CRD 下发后,Akri 的相应 Discovery 服务会按照规则寻找 OPC UA 设备
- 在找到 OPC UA 设备后,Agent 服务会生成设备对应的 CRD(Instance),Controller 服务查看到 Instance CRD 资源后,将创建对应的工作负载
OPC UA 设备模拟
使用了一个.NET 类型的开源项目模拟实现 OPU CA 设备,项目地址为:https://gitee.com/leotuss/opcua-donet
克隆到本地后,需要修改以下文件:
# /opcua-dotnet/Applications/ConsoleReferenceServer/Quickstarts.ReferenceServer.Config.xml文件第76、77行
将<node-ip style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">替换为节点地址
#/opcua-dotnet/Applications/ReferenceServer/Quickstarts.ReferenceServer.Config.xml文件第77、78行
将<node-ip style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">替换为节点地址</node-ip></node-ip>`
Linux 要运行这个程序,需要安装.NET core 的 SDK 和 runtime
可以使用以下命令运行此程序:
dotnet run --project /opcua-dotnet/Applications/ConsoleReferenceServer/NetCoreReferenceServer.csproj
运行后,可以看到如下提示:
root@edge-iot1:~/opcua-dotnet/Applications/ConsoleReferenceServer# dotnet run --project NetCoreReferenceServer.csproj
.Net Core OPC UA Reference Server
opc.tcp://192.168.6.151:62541/Quickstarts/ReferenceServer
https://192.168.6.151:62540/Quickstarts/ReferenceServer/
Server started. Press Ctrl-C to exit...
至此程序运行成功,应用可以通过订阅opc.tcp://:62541/Quickstarts/ReferenceServer
获得数据
安装 Akri
可以通过 Helm 安装 Akri:
# 添加Akri repo
helm repo add akri-helm-charts https://project-akri.github.io/akri/
# 部署Akri
helm install akri akri-helm-charts/akri\
--set kubernetesDistro=k3s \
--set opcua.discovery.enabled=true
关于 kubernetesDistro 配置,Akri 依赖 crictl 跟踪 pod 信息,所以必须知道容器运行时 socket 的位置。目前 Akri 支持四种类型:
- 标准 kuberentes,对应配置为:
--set kubernetesDistro=k8s
- k3s,对应配置为:
--set kubernetesDistro=k3s
- microk8s,对应配置为:
--set kubernetesDistro=microk8s
- 其它,对应配置为:
--set agent.host.containerRuntimeSocket=/container/runtime.sock
关于 xxx.discovery.enabled 配置,Akri 目前支持三种设备发现:
- onvif:IP Cameras 的主流协议
- opc ua:工业自动化通信协议
- udev:linux 设备管理器
如我们需要 Akri 发现 onvif 设备,就可以配置 --set onvif.discovery.enabled=true
,配置后 Akri 会在集群中部署相应的 Discovery 服务,以 Daemonset 的方式运行,支持叠加部署,如需要发现上述三种类型设备,部署命令可以修改为:
helm install akri akri-helm-charts/akri\
--set kubernetesDistro=k3s \
--set opcua.discovery.enabled=true \
--set onvif.discovery.enabled=true \
--set udev.discovery.enabled=true
部署完成后查看集群 Pods 可以看到:
root@edge-k3s:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
akri-controller-deployment-d4f7847b6-rlgrr 1/1 Running 11 (25h ago) 4d2h
akri-agent-daemonset-9s9m9 1/1 Running 10 (25h ago) 3d23h
akri-opcua-discovery-daemonset-tv84d 1/1 Running 8 (25h ago) 3d17h
部署 CRD
使用 Akri 发现设备需要部署类型为 Configuration 的 CRD:
apiVersion: akri.sh/v0
kind: Configuration
metadata:
name: akri-opcua-monitoring
namespace: default
spec:
brokerProperties:
IDENTIFIER: Thermometer_Temperature
NAMESPACE_INDEX: "2"
brokerSpec:
brokerPodSpec:
containers:
- image: ghcr.io/project-akri/akri/opcua-monitoring-broker:latest
name: akri-opcua-monitoring-broker
resources:
limits:
'{{PLACEHOLDER}}': "1"
cpu: 30m
memory: 200Mi
requests:
'{{PLACEHOLDER}}': "1"
cpu: 9m
memory: 76Mi
capacity: 1
configurationServiceSpec:
ports:
- name: grpc
port: 80
protocol: TCP
targetPort: 8083
type: ClusterIP
discoveryHandler:
name: opcua
discoveryDetails: |+
opcuaDiscoveryMethod:
standard:
discoveryUrls:
- opc.tcp://192.168.6.151:62541/Quickstarts/ReferenceServer/
- opc.tcp://192.168.6.152:62541/Quickstarts/ReferenceServer/
applicationNames:
action: Exclude
items: []
name: opcua
instanceServiceSpec:
ports:
- name: grpc
port: 80
protocol: TCP
targetPort: 8083
type: ClusterIP
需要关注的配置:
- spec.brokerProperties: 用于定义需要采集数据的 ID 信息,本演示中 opcua 程序中添加了
IDENTIFIER:为Thermometer_Temperature
和NAMESPACE_INDEX: "2"
的数据输出,数据输出内容为 70-80 的随机数,并且在随机到 75 时,将 75 替换为 120 - spec.brokerSpec.brokerPodSpec.containers.image: 设备对应工作负载的镜像,演示使用的是官方提供的镜像,作用是订阅 opcua 所产生的相应数据,此镜像是可以自定义的,实现更多可能
- spec.capacity:针对设备的工作负载副本数量,用于实现工作负载高可用
- spec.discoveryHandler: 这部分主要定义了发现 opuca 设备的规则,支持一些过滤规则
- spec.configurationServiceSpec:Akri Controller 服务会为所有设备的工作负载创建一个总 svc,这段用于定义相应的 svc 的配置
- spec.instanceServiceSpec: Akri Controller 服务会为每一个工作负载创建 svc,这段用于定义相应 svc 的配置
示例中可以看到 opuca 的发现规则是具体的服务地址,如果要支持批量的 opuca 设备发现,可以使用 Local discovery server(LDS),将 opcua 的设备注册到 LDS 中,然后在 discoveryUrls 配置中使用 LDS 的地址。采用 LDS 方式的话,可以实现过滤能力,如排除掉哪些 opcua 服务或者包含哪些 opcua 服务,示例如下:
# 发现LDS中的所有opcua设备,除了<someserver style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">以外</someserver>
discoveryDetails: |+
opcuaDiscoveryMethod:
standard:
discoveryUrls:
- opc.tcp://<lds服务器地址 style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">:4840</lds服务器地址>
applicationNames:
action: Exclude
items:
-
将 akri-opcua-monitoring 的 crd 部署到集群后,可以通过 kubectl get akric
查看:
root@edge-k3s:~/akric-crd# kubectl get akric
NAME CAPACITY AGE
akri-opcua-monitoring 1 2m13s
查看 Discovery 的服务日志可以看到,两个 opcua 设备已经被发现:
[2022-11-10T08:26:26Z TRACE akri_opcua::discovery_impl] get_discovery_url_from_application - found server : Quickstart Reference Server
[2022-11-10T08:26:26Z TRACE akri_opcua::discovery_impl] get_discovery_url_from_application - server has [UAString { value: Some("https://192.168.6.151:62540/Quickstarts/ReferenceServer/discovery") }, UAString { value: Some("opc.tcp://192.168.6.151:62541/Quickstarts/ReferenceServer") }] DiscoveryUrls
[2022-11-10T08:26:26Z TRACE akri_opcua::discovery_impl] get_discovery_urls - Server at opc.tcp://192.168.6.152:62541/Quickstarts/ReferenceServer/ responded with 1 Applications
[2022-11-10T08:26:26Z TRACE akri_opcua::discovery_impl] get_discovery_url_from_application - found server : Quickstart Reference Server
[2022-11-10T08:26:26Z TRACE akri_opcua::discovery_impl] get_discovery_url_from_application - server has [UAString { value: Some("https://192.168.6.152:62540/Quickstarts/ReferenceServer/discovery") }, UAString { value: Some("opc.tcp://192.168.6.152:62541/Quickstarts/ReferenceServer") }] DiscoveryUrls
[2022-11-10T08:26:26Z TRACE akri_opcua::discovery_handler] discover - found OPC UA server at DiscoveryURL opc.tcp://192.168.6.151:62541/Quickstarts/ReferenceServer
[2022-11-10T08:26:26Z TRACE akri_opcua::discovery_handler] discover - found OPC UA server at DiscoveryURL opc.tcp://192.168.6.152:62541/Quickstarts/ReferenceServer
可以通过 kubectl get akrii
查看由 Agent 自动生成的 opcua 的 instance crd 资源:
root@edge-k3s:~/akric-crd# kubectl get akrii
NAME CONFIG SHARED NODES AGE
akri-opcua-monitoring-7aa6fb akri-opcua-monitoring true ["edge-k3s"] 5m10s
akri-opcua-monitoring-20f7e0 akri-opcua-monitoring true ["edge-k3s"] 5m9s`
于此同时,使用 kubectl get pods
可以查看到为设备自动创建的工作负载:
NAME READY STATUS RESTARTS AGE
akri-controller-deployment-d4f7847b6-rlgrr 1/1 Running 11 (27h ago) 4d4h
akri-agent-daemonset-9s9m9 1/1 Running 10 (27h ago) 4d1h
akri-opcua-discovery-daemonset-tv84d 1/1 Running 8 (27h ago) 3d19h
edge-k3s-akri-opcua-monitoring-7aa6fb-pod 1/1 Running 0 6m44s <---
edge-k3s-akri-opcua-monitoring-20f7e0-pod 1/1 Running 0 6m43s <---
部署数据展示服务
部署数据展示服务查看效果:
kubectl apply -f https://raw.githubusercontent.com/project-akri/akri/main/deployment/samples/akri-anomaly-detection-app.yaml
部署完成后,查看一下展示服务 SVC 的 NodePort 端口:
root@edge-k3s:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 5d6h
akri-opcua-monitoring-7aa6fb-svc ClusterIP 10.43.152.214 <none> 80/TCP 13m
akri-opcua-monitoring-svc ClusterIP 10.43.242.118 <none> 80/TCP 13m
akri-opcua-monitoring-20f7e0-svc ClusterIP 10.43.22.196 <none> 80/TCP 13m
akri-anomaly-detection-app NodePort 10.43.248.164 <none> 80:32007/TCP 7s <---
访问 NodePort 端口,查看效果:
这个展示服务原理是通过连接工作负载的 SVC 获取工作负载采集到的设备数据,当值为 70-80 中任意数值时表示正常,用黑体展示;当值为 120 时表示异常,用红体展示
当设备下线时,Akri 会自动删除设备对应的工作负载,删除的时间大约为 5 分钟,以便应对可能出现的临时网络故障。
总 结
Akri 其实可以理解为是一种设备自动发现的框架,它可以通过云原生的方式帮助我们发现并使用 IOT 设备,目前支持 onvif、udev、opcua 三种类型。其它包括 Bluetooth、CoAP、IP、LoRaWAN、Zeroconf、acpid、MQTT 也正在开发中。
使用 k3s 可以帮助用户实现在边缘侧使用 kubernetes 的能力,通过 Akri 可以解决边缘场景下发现和使用设备的问题,这样用户就能将更多的精力专注在数据处理的应用上。