Pull to refresh
898.68
OTUS
Цифровые навыки от ведущих экспертов

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

Reading time6 min
Views3.3K

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 разными способами и не только.

Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
Total votes 8: ↑8 and ↓0+8
Comments0

Articles

Information

Website
otus.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
OTUS