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