Управление устройствами интернета вещей через Kubernetes

от автора

Kubernetes последовательно захватывает все новые ниши для декларативного описания ожидаемого состояния и теперь ресурсами Kubernetes можно управлять облачными провайдерами (например, через Crossplane), создавать и масштабировать функции (KNative) и многим другим. И кажется интересной идея конфигурирования через Kubernetes физических устройств, имеющих механизм удаленного управления и отправки информации о текущем состоянии. В CNCF был зарегистрирован проект (сейчас находится в sandbox) Akri, который предлагает модель унифицированного управления устройствами умного дома и в этой статье мы рассмотрим основные аспекты конфигурирования Akri на примере udev и OPC UA.

Akri определяет два типа ресурсов: описание устройства и описание экземпляра Akri для управления устройством. Для обнаружения устройств Akri поддерживает протоколы udev (универсальный механизм обнаружения для Linux), ONVIF (для обнаружения IP-камер), OPC UA (промышленный стандарт для взаимодействия с датчиками и управляющими устройствами), в работе поддержка Bluetooth, LoRaWAN, CoAP и других, при этом можно создать собственное расширение для обнаружения устройств по специальному протоколу, который описан в документации на основе шаблона на Rust. Мы будем использовать udev и будем обнаруживать существующую веб-камеру на компьютере, но разумеется здесь можно было бы использовать любую другую конфигурацию (например, управлять GPU или другими устройства, в том числе подключенными через USB).

Для установки будем использовать Helm, это поможет сразу настроить необходимую конфигурацию обнаружения. Для получения информации о состоянии pod будет использоваться crictl, которая доступна по умолчанию в Kubernetes 1.24+. Важно при установке указать расположение socket-файла для cri в переменной agent.host.containerRuntimeSocket (например, при установке с Containerd расположение будет /run/containerd/contained.sock, для Docker + Mirantis cri-dockerd: /run/cri-dockerd.sock)

helm repo add akri-helm-charts https://project-akri.github.io/akri/ helm install akri akri-helm-charts/akri \      --set agent.host.containerRuntimeSocket=/run/cri-dockerd.sock \      --set udev.discovery.enabled=true \      --set udev.configuration.enabled=true \      --set udev.configuration.name=akri-udev-video \      --set udev.configuration.discoveryDetails.udevRules[0]='KERNEL=="video[0-9]*"' \      --set udev.configuration.brokerPod.image.repository="ghcr.io/project-akri/akri/udev-video-broker"

При установке мы указываем способ обнаружения устройств, дополнительные настройки для поиска устройств (здесь мы ищем все доступные видеоустройства в /dev). Также можно разрешить все доступные способы обнаружения через переменную agent.full=true. Для мониторинга в Prometheus можно разрешить экспорт метрик через prometheus.enabled=true, среди которых будет кроме обычных замеров rust-приложений значения количества обнаруженных устройств (akri_instance_count), запущенных брокеров (akri_broker_pod_count), а также метрики от брокеров (например, akri_frame_count от брокера udev-video).

При использовании сетевых методов обнаружения можно указывать список ip или MAC-адресов для отбора устройств и анонсированные возможности (например, scopes в ONVIF). Более подробно примеры конфигурации можно посмотреть в документации. Конфигурация discovery создает ресурс с типом Configuration (apiVersion: akri.sh/v0) со следующей спецификацией:

spec:   brokerProperties: {}   brokerSpec:     brokerPodSpec:       containers:       - image: ghcr.io/project-akri/akri/udev-video-broker:latest         name: akri-udev-video-broker         securityContext:           privileged: true   capacity: 1   configurationServiceSpec:     ports:     - name: grpc       port: 80       protocol: TCP       targetPort: 8083     type: ClusterIP   discoveryHandler:     discoveryDetails: |       udevRules:       - KERNEL=="video[0-9]*"     name: udev   instanceServiceSpec:     ports:     - name: grpc       port: 80       protocol: TCP       targetPort: 8083     type: ClusterIP

В спецификации указывается образ контейнера для брокера, который будет использоваться для взаимодействия с устройствами, и настройки discovery, которые применяются в discovery-daemonset для обнаружения новых устройств. Кроме пода обнаружения на узлы устанавливается агент, который реализует протокол Device Plugins для уведомления о доступных устройствах, устанавливается через DaemonSet на все узлы кластера. Для обнаруженных устройств создается экземпляр ресурса Instance (apiVersion: akri.sh/v0), который содержит информацию о доступе к устройству для брокера (brokerProperties). Также в brokerProperties может содержаться информация о настройках устройствах (например, частота кадров для камеры). Агент отслеживает изменения в списке устройств и соответственно создает, изменяет или удаляет ресурсы Instance.

apiVersion: akri.sh/v0 kind: Instance metadata:   name: akri-udev-video-db97e3   namespace: default spec:   brokerProperties:     UDEV_DEVNODE: /dev/video0   configurationName: akri-udev-video   deviceUsage:     akri-udev-video-db97e3-0: mynotebook   nodes:   - mynotebook   shared: false

Брокер может изменять состояние устройства при изменениях в brokerProperties, а также предоставлять методы для получения информации от устройства через REST, gRPC или другие протоколы. Для udev-video-broker можно использовать клиент, который отображает полученные кадры в веб-интерфейсе:

kubectl apply -f https://raw.githubusercontent.com/project-akri/akri/main/deployment/samples/akri-video-streaming-app.yaml PORT=`kubectl get service/akri-video-streaming-app --output=jsonpath='{.spec.ports[?(@.name=="http")].nodePort}'` open http://localhost:$PORT

Исходные тексты приложения можно посмотреть здесь. Приложение запрашивает кадры с опубликованного grpc-сервиса (связан с соответствующим Instance и может быть найден по имени Instance и суффиксу -svc, grpc опубликован на порт 80), описание протокола выглядит следующим образом:

syntax = "proto3";  option csharp_namespace = "Camera";  package camera;  service Camera {   rpc GetFrame (NotifyRequest) returns (NotifyResponse); }  message NotifyRequest { }  message NotifyResponse {   bytes frame = 1;   string camera = 2; }

Рассмотрим теперь более сложный пример с использованием OPC UA. Для симуляции устройства будем использовать https://github.com/flopach/opc-ua-sensor-simulator. Установим симулятор и попробуем подключиться к нему через свободный клиент:

git clone https://github.com/flopach/opc-ua-sensor-simulator apt install libxslt-dev libxml2-dev libffi-dev cd opc-ua-sensor-simulator sudo add-apt-repository ppa:deadsnakes/ppa sudo apt install python3.8 python3.8-distutils sudo rm /usr/bin/python sudo ln -s /usr/bin/python3.8 /usr/bin/python pip3 install -r requirements.txt unzip sensor.csv.zip sed -i 's/127.0.0.1/0.0.0.0/ig' opc-ua-server.py python opc-ua-server.py

Установим свободный клиент:

snap install --edge opcua-client

Для получения информации о доступных устройствах и замеров датчиков подключимся к localhost:4840 и получим возможность просмотра списка зарегистрированных поставщиков данных и значения температуры и давления.

Теперь настроим подключение Akri к серверу. Для этого создадим конфигурацию обнаружения:

apiVersion: akri.sh/v0 kind: Configuration metadata:   name: akri-opcua   namespace: default spec:   brokerProperties: {}   brokerSpec:     brokerPodSpec:       containers:       - image: nginx:latest         name: akri-opcua-broker   capacity: 1   configurationServiceSpec:     ports:     - name: grpc       port: 80       protocol: TCP       targetPort: 8083     type: ClusterIP   discoveryHandler:     discoveryDetails: "opcuaDiscoveryMethod: \n  standard:\n    discoveryUrls:\n    -       opc.tcp://IP:4840/opcua/\napplicationNames:\n  action: Exclude\n       \ items: []\n"     name: opcua   instanceServiceSpec:     ports:     - name: grpc       port: 80       protocol: TCP       targetPort: 80     type: ClusterIP 

Вместо IP здесь необходимо подставить соответствующий внешний адрес узла. Для каждого обнаруженного устройства будет создан брокер (в нашем случае сервер nginx). Для разработки собственного брокера (например, получения температуры с датчиков) можно использовать свободные реализации gRPC и OPC UA (например, topic и opcua в crates для Rust, grpc и asyncua в python). Во второй части статьи мы рассмотрим пример обработки данных с датчика температуры через протокол спецификации OPC UA и их извлечения в веб-интерфейсе с построением графика истории изменения температуры (также будем использовать возможности обнаружения Akri), а также поговорим о возможностях интеграции системы обнаружения со свободными системами умного дома Majordomo и Home Assistant.

В преддверии запуска курса «Инфраструктурная платформа на основе Kubernetes» приглашаю всех на бесплатный демоурок, в рамках которого мои коллеги расскажут как шаблонизировать манифесты Kubernetes разными способами и не только.


ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/686332/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *