Comment créer un module Azure IoT Edge ?

Article co-écrit par Taha SNOUSSI et Jérémie LALANNE
Depuis quelque temps, nous entendons de plus en plus parler d’Azure IoT Edge, ce service qui faciliterait grandement la gestion, le développement, et la maintenance des flottes d’appareils IoT dans le monde entier. Mais qu’en est-il, comment l’utilise-t-on ?
Nous vous proposons aujourd’hui de faire le point sur cette technologie.
Azure IoT Edge : kézako ?
Azure IoT Edge, ce service tout droit sorti des laboratoires de Microsoft il y a quelques années, est utilisé pour moderniser les installations et logiciels IoT dans les industries. Il permet de conteneuriser les charges utiles applicatives des appareils de manière à les rendre entièrement pilotables à distance, les mettre à jour mondialement à distance, grandement faciliter la maintenance (il y a très peu de besoins d’action sur place), et le développement de nouvelles fonctionnalités.
Quoi de plus qu’Azure IoT classique ?
Le service Azure IoT Hub, gestionnaire des appareils IoT, permet, de manière globale, de :
- gérer les appareils à distance ;
- grouper les messages entrants ;
- communiquer avec les appareils;
- connecter différents services ;
- gérer l’approvisionnement de nouveaux appareils ;
- internaliser la gestion de leur configuration ;
- etc.
Ces services peuvent, entre autres, être utilisés par les appareils pour échanger des informations, notamment grâce au SDK Azure IoT. Azure IoT Edge est une fonctionnalité supplémentaire d’Azure IoT Hub, un sous-service. Les appareils utilisent également le SDK Azure IoT, mais différemment, et peuvent avoir des fonctionnalités supplémentaires. Une chose cruciale qu’Azure IoT Edge permet de faire, en plus, c’est de gérer à distance le comportement de l’appareil, les applications qui tournent dessus, de manière dynamique. Plus besoin d’intervenir sur site pour remplacer l’appareil pour le mettre à jour, ou pour de la maintenance logicielle, ou encore pour débugger l’appareil.
Quelles contraintes pour IoT Edge ?
La contrainte principale reste la RAM. Conteneuriser des applications est assez gourmand en ressources. Par exemple, difficile de le faire sur un système à batterie qui doit tenir longtemps. C’est également de la complexité supplémentaire niveau logiciel et développement, mais on s’y fait très rapidement lorsqu’on comprend le principe.
Contexte de l’exemple
Pour cet article, mettons en place un contexte d’exemple pour le développement de votre première solution Azure IoT Edge. Reprenons donc l’exemple très simple fourni par défaut par Microsoft : un système de deux modules IoT Edge, contenant un module du marché (donné sans le code source, accessible publiquement sur les sources de Microsoft) qui génère aléatoirement des données de température ; et un module dit « custom », c’est-à-dire que l’on développe nous-mêmes, qui est par défaut chargé de retransmettre les données venant du module de température, à Azure IoT Hub.
Exemple d’architecture globale

Figure 1: Architecture simple Azure IoT Edge (source: Le démarrage rapide crée un appareil Azure IoT Edge sur Linux | Microsoft Learn)
Deux services Azure sont indispensables pour faire fonctionner un appareil Azure IoT Edge :
- Un Azure IoT Hub (gestion globale)
- Un Azure Container Registry (stockages des images Docker)
En embarqué sur l’appareil, nous avons donc le service Azure IoT Edge installé, et notre module de capteur de température auquel vient s’ajouter le module custom que nous allons déployer, en intermédiaire pour transmettre les données de température à l’Azure IoT Hub.
Dans un article précédent, nous vous avons présenté l’architecture d’un appareil IoT Edge.
Rappelons ici que chaque module est en réalité une virtualisation de sa fonction associée dans une image de conteneur Docker. Comment ça marche alors ?
Exemple d’architecture matérielle
Partons ici sur quelque chose de très simple et très courant de nos jours : un Raspberry Pi.
Pour faire tourner Azure IoT Edge, comme dit précédemment, il faut un nombre important de ressources : un minimum de 2Gb de RAM est donc à prévoir si l’appareil n’embarque qu’un à trois modules très simples (c’est difficile à estimer, parfois moins parfois plus, selon la charge). 4Gb de RAM sont toutefois conseillés pour un bon fonctionnement pour une charge de travail plus lourde.
Nous allons donc choisir un Raspberry Pi 4 à sa version de minimum 2Gb de RAM ici (la Raspberry Pi 3B+ suffit pour cet exemple, c’est simplement qu’elle arrive rapidement à ses limites quand on monte dans les charges).
Il est également possible de partir sur d’autres technologies plus poussées comme Azure Sphere ou Windows IoT Core. Cela représente le niveau d’abstraction intermédiaire entre le matériel et notre applicatif.
Approche conventionnelle/moderne de développement
Nous pourrions développer une application monolithique qui s’occupera de récupérer la température du capteur et la transmettre directement par API à l’Azure IoT Hub. Cela parait évident a priori. Mais imaginons que nous souhaitons ajouter à notre appareil une fonction supplémentaire telle que le traitement d’alerte quasi-temps réel de cette température, la modification du programme en fonction de données de capteur de présence disponible à proximité, et tant d’autres fonctionnalités… Nous aurons à tout redévelopper pour faire cohabiter ce nouveau code avec l’existant, et ne parlons même pas du déploiement mondial.
Lorsque nous construisons un ensemble Lego® de Poudlard, il peut arriver qu’une pièce casse (même si on sait qu’un Lego® ne casse jamais…), ou qu’il y ait un défaut (ça n’arrive pas non plus), et il faut la remplacer, soit par une nouvelle pièce, soit par une amélioration, peu importe. Mais nous ne souhaitons pas avoir à recommander un nouvel ensemble. Azure IoT Edge nous permet de faire cela, et c’est tout l’intérêt d’une architecture conteneurisée. Lorsque nous avons une fonctionnalité qui crashe, ou que nous voulons simplement l’améliorer, la remplacer, la solidifier, il ne s’agit après tout que de conteneurs. Ils sont, dans leur principe même, indépendants les uns des autres. Alors pour développer des modules Azure IoT Edge, inutile de se préoccuper des autres tâches, nous pouvons le développer individuellement, dans un autre langage si nous le souhaitons. Il en va de même pour le déploiement : aucun besoin de se soucier de savoir s’il va bien fonctionner avec le reste.
Fonctionnement d’un module Azure IoT Edge
Un module IoT Edge est un conteneur qui est démarré par le runtime d’IoT Edge grâce à un fichier de configuration qu’on appelle « manifeste de déploiement ». Le runtime se compose des modules systèmes Edge Hub et Edge Agent, qui se chargent respectivement de gérer la communication entre les différents modules et IoT Hub, gèrent le fonctionnement de tous les modules et s’assurent qu’ils respectent tous le contenu du manifeste.
Ce manifeste précise le contexte d’exécution des conteneurs :
- Les variables d’environnement spécifiques à chaque conteneur (en plus des quelques-unes rares héritées du Runtime)
- La configuration particulière lors du déploiement de l’appareil, qui lui permettra d’accéder à certaines fonctionnalités du système d’exploitation hôte, telles que :
- Les drivers des capteurs
- Les sockets réseau
- L’espace de stockage des données
Le module lui-même devra respecter quelques spécifications afin d’interagir avec les modules systèmes et les autres, en configurant par exemple son comportement lors d’interactions spécifiques à IoT Edge : quoi faire en cas de réception d’un message venant d’un autre module, en cas d’appel de méthode distant (méthode directe), etc.
Types de communications
D2C/D2D
Dans l’exemple de cet article, c’est de cette manière dont le module custom enverra à l’IoT Hub les données reçues du module de température. Pratiquement tous les messages que l’appareil peut envoyer à l’IoT Hub font partie de cette catégorie. C’est une des fonctionnalités phares du module Edge Hub.
Qu’en est-il du C2D ?
Nous en parlons rarement, car il est difficile de considérer ce type de communication. En effet, dans le cas d’Azure IoT Edge, il ne s’agit pas à proprement parler de message directement envoyé au sens propre du terme, mais plus d’une série de communications. Soit l’IoT Hub envoie des configurations (c’est plutôt le module Edge Agent qui capte qu’il y a une différence, et demande le nouveau manifeste), soit il fait appel aux méthodes directes.
Méthodes Directes
Il s’agit d’un principe bien connu, et d’une fonctionnalité appréciée et très utilisée. Une méthode directe consiste à appeler, à distance, une fonction bien particulière de l’appareil. Ou plutôt, nous dirons qu’il s’agit de demander une action de la part de l’appareil. L’une des configurations à faire dans le module lors du développement sera de prendre en compte ces possibilités : dans notre cas, il s’agira par exemple d’intégrer la possibilité pour le module de modifier le seuil de température avant alerte, ou la fréquence d’envoi, sur demande de l’IoT Hub ou d’un autre module (d’un autre appareil aussi, c’est possible).
Premiers pas dans le développement
Microsoft fournit une documentation détaillée sur le développement des modules IoT Edge et des exemples d’implémentations. Nous allons ici vous donner d’autres exemples de modules que vous pouvez réaliser rapidement.
Outils
Pour notre exemple, et selon les préceptes de base de développement de modules Azure IoT Edge recommandés par Microsoft, nous utilisons Visual Studio Code, qui contient l’intégralité de toutes les fonctions dont on pourrait avoir besoin pour ce genre de développements. Il faudra également installer l’extension Azure IoT Edge for Visual Studio Code, ainsi que Docker sur son poste.
Création d’une solution
L’extension installée précédemment nous donne accès à une palette de commandes utiles pour développer, ou commander des appareils distants.
Pour ouvrir cette palette et créer une nouvelle solution Azure IoT Edge :
View > Command Palette (Ctrl + Shift + P)
Puis choisir la création d’une nouvelle solution en utilisant l’extension comme suit :

Le menu vous proposera également de créer en même temps un nouveau module dans cette solution, ainsi que le choix de la technologie utilisée, et son emplacement de stockage (local par défaut). Nous partirons ici pour un module C# .NET.
Vous obtenez normalement cette arborescence :

À noter : précisons quand même qu’Azure IoT Edge est une technologie relativement récente, sujette à de nombreuses évolutions qui peuvent impacter ce qu’on considère comme la meilleure architecture possible de développement des modules. L’extension est donc souvent mise à jour avec de nouvelles façons de faire, qui peuvent différer de la méthode que nous allons voir selon le moment auquel vous lisez cet article.
Les deux fichiers « deployment.debug.template.json » et « deployment.debug.template.json » sont les deux variantes du manifeste que nous avons évoqué plus tôt dans l’article. Ils sont donnés pour tester localement et individuellement le module, ou à titre d’exemple pour permettre d’avoir facilement le format demandé par les modules système du Runtime : Edge Agent et Edge Hub.
Le dossier modules contient autant de dossiers que de modules à développer dans cette solution. Par défaut, nous trouverons un dossier SampleModule avec cette arborescence par défaut :

Comme vous le voyez, il y a dans ce module plusieurs Dockerfile que vous pouvez utiliser pour compiler ce module.
En plus, vous retrouverez la structure d’un projet .NET utilisant le modèle de projet aziotedgemodule. Ce projet implémente un service de longue durée (pour en savoir plus, consulter la documentation Microsoft).
Ce type de projet .NET avait été introduit par Microsoft à partir de .NET 6. Nous rappelons qu’avant cette version, les projets d’exemple utilisaient le modèle console. Mais rien ne vous empêchait d’utiliser d’autres modèles disponibles à l’époque, tels que les modèles API et webAPI.
Développement d’un nouveau module type Web
Si vous voulez créer votre propre module d’un autre type, dans cette même solution, il est possible de vous placer dans une console dans le dossier modules et de lancer cette commande (de nombreux paramètres supplémentaires sont disponibles) :

Si vous voulez connaitre les types de projets supportés par le Framework .NET, utilisez la commande ‘dotnet new list’:

Ensuite, il faut créer le fichier Dockerfile pour ce nouveau module. Puisque le type de projet choisi dans la précédente commande est « web », nous ne pourrons pas utiliser les fichiers DockerFile du module SampleModule existant. Malheureusement, à ce jour, Microsoft ne fournit pas encore d’option de création de fichier Docker avec le SDK .NET dans ce contexte (comme on l’a dit, la technologie est encore récente, et de nombreuses améliorations sont encore à venir).
Nous vous proposons d’utiliser l’outil Docker (version 4.23.0) pour simplifier et accélérer le process. Placez votre console dans le dossier WebModule et lancez la commande suivante ‘docker init’.

N.B. Précisons ici que l’utilisation de docker init fonctionne uniquement avec le type de projet « web API ».
Si vous choisissez par exemple le type de projet « console », il vous faudra utiliser un Dockerfile différent. Nous vous proposons d’utiliser ce contenu où « ConsoleModule » est le nom du module :
Une principale composante dans le modèle aziotedgemodule préconisé par Microsoft pour les modules IoT Edge est le service de longue durée. Ce modèle vous permet donc d’instancier un service worker qui hérite de BackgroundService. Il rajoute dans l’hôte .NET l’injection de votre service worker avec la méthode AddHostedService.
L’activation des spécificités du modèle Azure IoT Edge se fera par la surcharge de la méthode ExecuteAsync en y ajoutant les tâches permettant d’implémenter les réponses à l’invocation des méthodes directes par l’IoT Hub, ou les traitements des messages reçus par le module.
Si vous avez choisi d’utiliser un autre modèle de projet .NET, il suffira de suivre la même stratégie : créer une classe pour votre module et l’instancier dans l’hôte d’exécution .NET. Votre classe peut être :
- ModuleBackgroudService comme suit :
- IHostedService comme suit :
Il faudra alors rajouter ce service dans votre hôte .NET comme suit :
Aller plus loin sur Azure IoT Edge
Les possibilités de développement avec Azure IoT Edge sont immenses, du simple fait de rendre chaque « Lego® » indépendant les uns des autres. Que ce soit pour créer des applications Web, ou intégrer des modules d’Intelligence Artificielle (sujet qui fera l’objet d’un prochain article). À vous de voir de quoi vous avez besoin.
Nous vous invitons d’ailleurs à découvrir nos autres articles sur les sujets de l’IoT .
Vous souhaitez être accompagné dans votre projet d’IoT ? Contactez-nous !