Compartir a través de


Tutorial: Creación e implementación de módulos personalizados de IoT Edge

Se aplica a: icono IoT Edge 1.1

Importante

IoT Edge 1.1: la fecha de finalización del soporte técnico fue el 13 de diciembre de 2022. Consulte la página del ciclo de vida de productos de Microsoft para obtener información sobre cómo se admite este producto, servicio, tecnología o API. Para más información sobre cómo actualizar a la versión más reciente de IoT Edge, consulte Actualización de IoT Edge.

En este artículo, crearemos tres módulos de IoT Edge que reciben mensajes desde dispositivos IoT de bajada, ejecutan los datos mediante un modelo de aprendizaje automático y, después, reenvían la información detallada a IoT Hub.

El centro de IoT Edge facilita la comunicación entre módulos. Al usar el centro de IoT Edge como un agente de mensajes, los módulos seguirán siendo independientes entre sí. Los módulos solo necesitan especificar las entradas en las que aceptan mensajes y las salidas en las que los escriben.

Queremos conseguir que el dispositivo IoT Edge haga cuatro cosas:

  • Recibir datos de dispositivos de bajada.
  • Prediga la vida útil restante (RUL) del dispositivo que envió los datos.
  • Envíe un mensaje con la RUL del dispositivo a IoT Hub. Esta función se puede modificar para enviar datos solo si la RUL se encuentra por debajo de un nivel especificado.
  • Guardar los datos del dispositivo de bajada en un archivo local en el dispositivo IoT Edge. Este archivo de datos se carga periódicamente en IoT Hub para refinar el entrenamiento del modelo de aprendizaje automático. El uso de la carga de archivos en lugar del streaming de mensajes constante es más rentable.

Para realizar estas tareas, usamos tres módulos personalizados:

  • Clasificador RUL: el módulo turboFanRulClassifier que creamos en Train and deploy an Azure Machine Learning model (Entrenar e implementar un modelo de Azure Machine Learning) es un módulo de Machine Learning estándar, que expone una entrada denominada "amlInput" y una salida denominada "amlOutput". La entrada "amlInput" espera que sus datos sean exactamente iguales a la entrada que se envía al servicio web basado en ACI. Del mismo modo, la salida "amlOutput" devuelve los mismos datos que el servicio web.

  • Escritor Avro: este módulo recibe mensajes en la entrada "avroModuleInput" y conserva el mensaje en formato Avro en el disco para su posterior carga en IoT Hub.

  • Módulo de enrutador: el módulo de enrutador recibe mensajes de los dispositivos de bajada y, después, da formato y envía los mensajes al clasificador. A continuación, el módulo recibe los mensajes desde el clasificador y reenvía el mensaje al módulo escritor Avro. Por último, el módulo envía simplemente la predicción de la RUL a IoT Hub.

    • Entradas:

      • deviceInput: recibe mensajes de los dispositivos de bajada.
      • rulInput: recibe mensajes de "amlOutput"
    • Salidas:

      • classify: envía mensajes a "amlInput"
      • writeAvro: envía mensajes a "avroModuleInput"
      • toIotHub: envía mensajes a $upstream, que pasa los mensajes a la instancia conectada de IoT Hub

En el diagrama siguiente se muestran los módulos, las entradas, las salidas y las rutas de IoT Edge Hub para la solución completa:

Diagrama de arquitectura de IoT Edge de tres módulos

Los pasos descritos en este artículo los realiza normalmente un desarrollador en la nube.

En esta sección del tutorial, aprenderá a:

  • Crear un módulo de IoT Edge a partir del código personalizado.
  • Generar una imagen de Docker a partir de un módulo personalizado.
  • Volver a configurar el enrutamiento de IoT Hub para que admita módulos personalizados.
  • Compilar, publicar e implementar módulos personalizados.

Requisitos previos

Este artículo forma parte de un tutorial sobre el uso de Azure Machine Learning en IoT Edge. Cada artículo de la serie se basa en el trabajo del artículo anterior. Si ha llegado a este artículo directamente, visite el primer artículo de la serie.

Crear una nueva solución de IoT Edge

Durante la ejecución del segundo de nuestros dos cuadernos de Azure Notebooks, creamos y publicamos una imagen de contenedor que contiene nuestro modelo RUL. Azure Machine Learning, como parte del proceso de creación de imágenes, empaqueta ese modelo para que la imagen se pueda implementar como un módulo de Azure IoT Edge.

En este paso, se va a crear una solución de Azure IoT Edge con el módulo "Azure Machine Learning" y, después, se orientará el módulo a la imagen que publicamos mediante Azure Notebooks.

  1. Abra una sesión de Escritorio remoto en la máquina virtual de desarrollo.

  2. Abra la carpeta C:\origen\IoTEdgeAndMlSample en Visual Studio Code.

  3. Haga clic con el botón derecho en el panel del explorador (en el espacio en blanco) y seleccione New IoT Edge Solution (Nueva solución de IoT Edge).

    Creación de la nueva solución de IoT Edge

  4. Acepte el nombre de la solución predeterminada EdgeSolution.

  5. Elija Azure Machine Learning como la plantilla del módulo.

  6. Asigne un nombre al módulo turbofanRulClassifier.

  7. Elija un área de trabajo de Machine Learning. Esta es el área de trabajo turboFanDemo que creó en el Tutorial: Entrenamiento e implementación de un modelo de Azure Machine Learning.

  8. Seleccione la imagen que creó al ejecutar el cuaderno de Azure Notebooks.

  9. Examine la solución y observe los archivos que se han creado:

    • deployment.template.json: este archivo contiene la definición de cada uno de los módulos de la solución. Hay tres secciones importantes en este archivo:

      • Credenciales del registro: define el conjunto de instancias de Container Registry personalizadas que se usan en la solución. Ahora mismo, debería contener el registro del área de trabajo de Machine Learning, que es donde se almacenó la imagen de Azure Machine Learning. Puede tener el número que quiera de instancias de Container Registry pero, para simplificar, usaremos este registro único para todos los módulos.

        "registryCredentials": {
          "<your registry>": {
            "username": "$CONTAINER_REGISTRY_USERNAME_<your registry>",
            "password": "$CONTAINER_REGISTRY_PASSWORD_<your registry>",
            "address": "<your registry>.azurecr.io"
          }
        }
        
      • Módulos: esta sección contiene el conjunto de módulos definidos por el usuario que se incluyen con esta solución. La definición del módulo turbofanRulClassifier apunta a la imagen de su instancia de Container Registry. A medida que se agregan más módulos a la solución, se mostrarán en esta sección.

        "modules": {
           "turbofanRulClassifier": {
             "version": "1.0",
             "type": "docker",
             "status": "running",
             "restartPolicy": "always",
             "settings": {
               "image": "turbofandemo2cd74296.azurecr.io/edgemlsample:1",
               "createOptions": {}
             }
           }
        }
        
      • Rutas: trabajaremos bastante con rutas en este tutorial. Las rutas definen cómo se comunican los módulos entre sí. La ruta existente definida por la plantilla no coincide con el enrutamiento que necesitamos. Elimine la ruta turbofanRulClassifierToIoTHub.

        "$edgeHub": {
           "properties.desired": {
             "schemaVersion": "1.0",
             "routes": {
               "turbofanRulClassifierToIoTHub": "FROM /messages/modules/turbofanRulClassifier/outputs/* INTO $upstream"
             },
             "storeAndForwardConfiguration": {
               "timeToLiveSecs": 7200
             }
           }
        }
        
    • deployment.debug.template.json: este archivo es la versión de depuración de deployment.template.json. Normalmente, mantendremos este archivo sincronizado con el contenido del archivo deployment.template.json, pero en este tutorial no es necesario.

    • .env: este archivo es donde debe proporcionar el nombre de usuario y la contraseña para acceder al registro.

      CONTAINER_REGISTRY_USERNAME_<your registry name>=<ACR username>
      CONTAINER_REGISTRY_PASSWORD_<your registry name>=<ACR password>
      

      Nota

      En este tutorial se usan credenciales de inicio de sesión de administrador de Azure Container Registry, que son prácticas para escenarios de desarrollo y pruebas. Cuando esté listo para escenarios de producción, se recomienda una opción de autenticación con privilegios mínimos, como las entidades de servicio. Para obtener más información, vea Administración del acceso al registro de contenedor.

  10. Haga clic con el botón derecho en el archivo deployment.template.json en el explorador de Visual Studio Code y seleccione Build IoT Edge Solution (Compilar la solución IoT Edge).

  11. Tenga en cuenta que este comando crea una carpeta de configuración con un archivo deployment.amd64.json. Este archivo es la plantilla de implementación concreta de la solución.

Adición del módulo de enrutador

A continuación, agregamos el módulo de enrutador a nuestra solución. El módulo de enrutador controla varias responsabilidades de nuestra solución:

  • Recibir mensajes de dispositivos de bajada: conforme lleguen mensajes al dispositivo IoT Edge desde dispositivos de bajada, el módulo de enrutador recibe el mensaje y comienza la orquestación del enrutamiento del mensaje.
  • Enviar mensajes al módulo Clasificador RUL: cuando se recibe un mensaje nuevo de un dispositivo de bajada, el módulo de enrutador transforma el mensaje al formato que espera el Clasificador RUL. El enrutador envía el mensaje al Clasificador RUL para obtener una predicción de RUL. Una vez que el clasificador ha realizado una predicción, devuelve el mensaje al módulo de enrutador.
  • Enviar mensajes de RUL a IoT Hub: cuando el enrutador recibe mensajes desde el clasificador, transforma el mensaje para que contenga solo la información esencial, el id. de dispositivo y la vida útil restante, y envía el mensaje abreviado a IoT Hub. Otro perfeccionamiento, que no hemos hecho, enviaría mensajes a la instancia de IoT Hub solo cuando la predicción del RUL caiga por debajo de un umbral (por ejemplo, cuando el RUL sea inferior a 100 ciclos). Filtrar de este modo podría reducir el volumen de mensajes y los costos de IoT Hub.
  • Enviar mensajes al módulo escritor Avro: para conservar todos los datos enviados por el dispositivo de bajada, el módulo de enrutador envía todo el mensaje recibido desde el clasificador al módulo de escritor de Avro, que se conservará y cargará los datos mediante la carga de archivos de IoT Hub.

El módulo Router es una parte importante de la solución que garantiza que los mensajes se procesen en el orden correcto.

Creación del módulo y copia de archivos

  1. Haga clic con el botón derecho en la carpeta de módulos de Visual Studio Code y elija Agregar módulo de IoT Edge.

  2. Elija el módulo de C# como plantilla del módulo.

  3. Asigne un nombre al módulo turbofanRulClassifier.

  4. Cuando el repositorio de imágenes de Docker se lo solicite, use el registro del área de trabajo de Machine Learning (puede encontrar el registro en el nodo registryCredentials del archivo deployment.template.json). Este valor es la dirección completa del registro, como <su registro>.azurecr.io/turbofanrouter.

    Nota

    En este artículo, usamos la instancia de Azure Container Registry que creó el área de trabajo de Azure Machine Learning. Esto es únicamente para su comodidad. Se podría haber creado una nueva instancia de Container Registry y publicar nuestros módulos allí.

  5. En el terminal, use el shell del símbolo del sistema para copiar los archivos del módulo de ejemplo en la solución.

    copy c:\source\IoTEdgeAndMlSample\EdgeModules\modules\turbofanRouter\*.cs c:\source\IoTEdgeAndMlSample\EdgeSolution\modules\turbofanRouter\
    
  6. Acepte el aviso para sobrescribir el archivo program.cs.

Compilación del módulo de enrutador

  1. En Visual Studio Code, seleccione Terminal>Configure Default Build Task (Configurar tarea de compilación predeterminada).

  2. Seleccione Crear archivo tasks.json desde plantilla.

  3. Seleccione .NET Core.

  4. Reemplace el contenido de tasks.json por el código siguiente:

    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "build",
          "command": "dotnet",
          "type": "shell",
          "group": {
            "kind": "build",
            "isDefault": true
          },
          "args": [
            "build",
            "${workspaceFolder}/modules/turbofanRouter"
          ],
          "presentation": {
            "reveal": "always"
          },
          "problemMatcher": "$msCompile"
        }
      ]
    }
    
  5. Guarde y cierre el archivo tasks.json.

  6. Ejecute la compilación con Ctrl + Shift + B o Terminal>Run Build Task (Ejecutar la tarea de compilación).

Configurar las rutas del módulo

Como se mencionó anteriormente, el entorno de ejecución de Azure IoT Edge usa rutas configuradas en el archivo deployment.template.json para administrar las comunicaciones entre módulos acoplados débilmente. En esta sección, profundizamos en cómo configurar las rutas para el módulo turbofanRouter. Cubriremos primero las rutas de entrada y luego pasaremos a las salidas.

Entradas

  1. En el método Init() de Program.cs, registramos dos devoluciones de llamadas para el módulo:

    await ioTHubModuleClient.SetInputMessageHandlerAsync(EndpointNames.FromLeafDevice, LeafDeviceInputMessageHandler, ioTHubModuleClient);
    await ioTHubModuleClient.SetInputMessageHandlerAsync(EndpointNames.FromClassifier, ClassifierCallbackMessageHandler, ioTHubModuleClient);
    
  2. La primera devolución de llamada escucha los mensajes enviados al receptor deviceInput. En el diagrama anterior, vemos que queremos enrutar los mensajes desde cualquier dispositivo de bajada a esta entrada. En el archivo deployment.template.json, agregue una ruta que indique al centro de Edge que enrute cualquier mensaje recibido por el dispositivo IoT Edge que no se haya enviado por un módulo IoT Edge en la entrada denominada "deviceInput" en el módulo turbofanRouter:

    "leafMessagesToRouter": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/deviceInput\")"
    
  3. A continuación, agregue una ruta para los mensajes desde el módulo rulClassifier en el módulo turbofanRouter:

    "classifierToRouter": "FROM /messages/modules/turbofanRulClassifier/outputs/amloutput INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/rulInput\")"
    

Salidas

Agregue cuatro rutas adicionales para el parámetro de ruta $edgeHub, para controlar las salidas del módulo de enrutador.

  1. El archivo Program.cs define el método SendMessageToClassifier(), que usa al cliente de módulo para enviar un mensaje al clasificador de RUL con la ruta:

    "routerToClassifier": "FROM /messages/modules/turbofanRouter/outputs/classOutput INTO BrokeredEndpoint(\"/modules/turbofanRulClassifier/inputs/amlInput\")"
    
  2. SendRulMessageToIotHub() usa el cliente de módulo para enviar solo los datos de RUL del dispositivo a IoT Hub a través de la ruta:

    "routerToIoTHub": "FROM /messages/modules/turboFanRouter/outputs/hubOutput INTO $upstream"
    
  3. SendMessageToAvroWriter() usa el cliente de módulo para enviar el mensaje con los datos de RUL agregados al módulo avroFileWriter.

    "routerToAvro": "FROM /messages/modules/turbofanRouter/outputs/avroOutput INTO BrokeredEndpoint(\"/modules/avroFileWriter/inputs/avroModuleInput\")"
    
  4. HandleBadMessage() envía los mensajes con errores a IoT Hub, donde se pueden enrutar para su uso posterior.

    "deadLetter": "FROM /messages/modules/turboFanRouter/outputs/deadMessages INTO $upstream"
    

Con todas las rutas tomadas en conjunto, el nodo "$edgeHub" debería tener un aspecto similar al siguiente JSON:

"$edgeHub": {
  "properties.desired": {
    "schemaVersion": "1.0",
    "routes": {
      "leafMessagesToRouter": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/deviceInput\")",
      "classifierToRouter": "FROM /messages/modules/turbofanRulClassifier/outputs/amlOutput INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/rulInput\")",
      "routerToClassifier": "FROM /messages/modules/turbofanRouter/outputs/classOutput INTO BrokeredEndpoint(\"/modules/turbofanRulClassifier/inputs/amlInput\")",
      "routerToIoTHub": "FROM /messages/modules/turboFanRouter/outputs/hubOutput INTO $upstream",
      "routerToAvro": "FROM /messages/modules/turbofanRouter/outputs/avroOutput INTO BrokeredEndpoint(\"/modules/avroFileWriter/inputs/avroModuleInput\")",
      "deadLetter": "FROM /messages/modules/turboFanRouter/outputs/deadMessages INTO $upstream"
    },
    "storeAndForwardConfiguration": {
      "timeToLiveSecs": 7200
    }
  }
}

Nota

La adición del módulo turbofanRouter crea la siguiente ruta adicional: turbofanRouterToIoTHub": "FROM /messages/modules/turbofanRouter/outputs/* INTO $upstream. Quite esta ruta y deje solo las rutas enumeradas anteriormente en el archivo deployment.template.json.

Adición del módulo escritor Avro

El módulo escritor Avro tiene dos responsabilidades en nuestra solución: almacenar mensajes y cargar archivos.

  • Almacenar mensajes: cuando el módulo escritor Avro recibe un mensaje, lo escribe en el sistema de archivos locales en formato Avro. Usamos un montaje de enlace, que se monta en un directorio (en este caso /data/avrofiles) en una ruta de acceso del contenedor del módulo. Este montaje permite al módulo escribir en una ruta de acceso local (/avrofiles) y que estos archivos sean accesibles directamente desde el dispositivo IoT Edge.

  • Cargar archivos: el módulo escritor Avro utiliza la característica de carga de archivos de Azure IoT Hub para cargar archivos en una cuenta de almacenamiento de Azure. Una vez que un archivo se cargue correctamente, el módulo elimina el archivo del disco

Creación del módulo y copia de archivos

  1. En Visual Studio Code, seleccione Ver>Paleta de comandos y, a continuación, busque y seleccione Python: Select Interpreter (Seleccionar intérprete).

  2. Seleccione la versión instalada de Python 3.7 o posterior.

  3. Haga clic con el botón derecho en la carpeta de módulos de Visual Studio Code y elija Agregar módulo de IoT Edge.

  4. Elija Módulo de Python.

  5. Asigne al módulo el nombre avroFileWriter.

  6. Cuando se le solicite su repositorio de imágenes de Docker, use el mismo registro que usó al agregar el módulo de enrutador.

  7. Copie archivos desde el módulo de ejemplo a la solución.

    copy C:\source\IoTEdgeAndMlSample\EdgeModules\modules\avroFileWriter\*.py C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avroFileWriter\
    
  8. Acepte la sobrescritura de main.py.

  9. Tenga en cuenta que se han agregado a la solución filemanager.py y schema.py, y main.py se ha actualizado.

Nota

Al abrir un archivo de Python se le pedirá que instale pylint. No es necesario instalar el linter para completar este tutorial.

Montaje de enlace para archivos de datos

Como ya se ha mencionado, el módulo escritor se basa en la presencia de un montaje de enlace para escribir los archivos de Avro en el sistema de archivos del dispositivo.

Adición de un directorio al dispositivo

  1. En Azure Portal, inicie la máquina virtual del dispositivo IoT Edge si aún no se está ejecutando. Conéctese a ella mediante SSH. La conexión requiere el nombre DNS, que puede copiar desde la página de información general de la máquina virtual en Azure Portal.

    ssh -l <user>@<vm name>.<region>.cloudapp.azure.com
    
  2. Después de iniciar sesión, cree el directorio que contendrá los mensajes del dispositivo de bajada guardados.

    sudo mkdir -p /data/avrofiles
    
  3. Actualice los permisos del directorio para que el contenedor pueda escribir en él.

    sudo chmod ugo+rw /data/avrofiles
    
  4. Valide el directorio, ahora tendrá permisos de escritura (w) para el usuario, grupo y propietario.

    ls -la /data
    

    Permisos de directorio para avrofiles

Adición de un directorio al módulo

Para agregar el directorio al contenedor del módulo, modificaremos las instancias de Dockerfiles asociadas con el módulo avroFileWriter. Hay tres archivos Dockerfiles asociados con el módulo: Dockerfile.amd64, Dockerfile.amd64.debug y Dockerfile.arm32v7. Estos archivos deben mantenerse sincronizados en caso de que se quiera depurar o implementar en un dispositivo de arm32. En aras de este artículo, céntrese solo en Dockerfile.amd64.

  1. En la máquina virtual de desarrollo, abra el archivo C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avoFileWriter\Dockerfile.amd64.

  2. Modifique el archivo para que tenga el siguiente aspecto:

    FROM ubuntu:xenial
    
    WORKDIR /app
    
    RUN apt-get update && apt-get install -y --no-install-recommends libcurl4-openssl-dev
    python3-pip libboost-python1.58-dev libpython3-dev && rm -rf /var/lib/apt/lists/*
    
    RUN pip3 install --upgrade pip
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    
    COPY . .
    
    RUN useradd -ms /bin/bash moduleuser
    RUN mkdir /avrofiles && chown moduleuser /avrofiles
    USER moduleuser
    
    CMD [ "python3", "-u", "./main.py" ]
    

    Los comandos mkdir y chown indican al proceso de compilación de Docker que cree un directorio de nivel superior llamado /avrofiles en la imagen y, después, que convierta a moduleuser en el propietario de ese directorio. Es importante que estos comandos se inserten después de que el usuario del módulo se agregue a la imagen con el comando useradd y antes de que el contexto pase a moduleuser (USER moduleuser).

  3. Si es necesario, haga los cambios correspondientes en Dockerfile.amd64.debug y Dockerfile.arm32v7.

Incorporación de la configuración de enlace a avroFileWriter

El paso final de la creación del enlace es actualizar los archivos deployment.template.json (y deployment.debug.template.json) con la información de enlace.

  1. Guarde deployment.template.json.

  2. Modifique la definición del módulo de avroFileWriter agregando el parámetro Binds que dirija el directorio del contenedor /avrofiles al directorio local en el dispositivo Edge. La definición del módulo debe coincidir con este ejemplo:

    "avroFileWriter": {
      "version": "1.0",
      "type": "docker",
      "status": "running",
      "restartPolicy": "always",
      "settings": {
        "image": "${MODULES.avroFileWriter}",
        "createOptions": {
          "HostConfig": {
            "Binds": [
              "/data/avrofiles:/avrofiles"
            ]
          }
        }
      }
    }
    

Montaje de enlace para acceder a config.yaml

Es necesario agregar un enlace más para el módulo de escritor. Este enlace proporciona al módulo acceso para leer la cadena de conexión desde el archivo /etc/iotedge/config.yaml en el dispositivo IoT Edge. Se necesita la cadena de conexión para crear una instancia de IoTHubClient de modo que podamos llamar al método upload_blob_async para cargar archivos en IoT Hub. Los pasos para agregar este enlace son similares a los de la sección anterior.

Actualización del permiso de directorio

  1. Conéctese al dispositivo IoT Edge con SSH.

    ssh -l <user>@IoTEdge-<extension>.<region>.cloudapp.azure.com
    
  2. Agregue el permiso de lectura al archivo config.yaml.

    sudo chmod +r /etc/iotedge/config.yaml
    
  3. Confirme que los permisos están correctamente configurados.

    ls -la /etc/iotedge/
    
  4. Asegúrese de que los permisos para config.yaml son -r--r--r-- .

Adición de un directorio al módulo

  1. En el equipo de desarrollo, abra el archivo Dockerfile.amd64.

  2. Agregue un conjunto adicional de comandos mkdir y chown al archivo para que tenga el aspecto siguiente:

    FROM ubuntu:xenial
    
    WORKDIR /app
    
    RUN apt-get update && apt-get install -y --no-install-recommends libcurl4-openssl-dev
    python3-pip libboost-python1.58-dev libpython3-dev && rm -rf /var/lib/apt/lists/\*
    
    RUN pip3 install --upgrade pip
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    
    COPY . .
    
    RUN useradd -ms /bin/bash moduleuser
    RUN mkdir /avrofiles && chown moduleuser /avrofiles
    RUN mkdir -p /app/iotconfig && chown moduleuser /app/iotconfig
    
    USER moduleuser
    
    CMD "python3", "-u", "./main.py"]
    
  3. Haga los cambios correspondientes en Dockerfile.amd64.debug y Dockerfile.arm32v7.

Actualización de la configuración del módulo

  1. Abra el archivo deployment.template.json.

  2. Modifique la definición del módulo de avroFileWriter agregando una segunda línea al parámetro Binds que dirija el directorio del contenedor (/app/iotconfig) al directorio local en el dispositivo (/etc/iotedge).

    "avroFileWriter": {
      "version": "1.0",
      "type": "docker",
      "status": "running",
      "restartPolicy": "always",
      "settings": {
        "image": "${MODULES.avroFileWriter}",
        "createOptions": {
          "HostConfig": {
            "Binds": [
              "/data/avrofiles:/avrofiles",
              "/etc/iotedge:/app/iotconfig"
            ]
          }
        }
      }
    }
    
  3. Realice los cambios correspondientes en deployment.debug.template.json.

Instalar dependencias

El módulo escritor toma una dependencia en las dos bibliotecas de Python, fastavro y PyYAML. Es necesario instalar las dependencias en nuestro equipo de desarrollo e indicarle al proceso de compilación de Docker que las instale en la imagen de nuestro módulo.

PyYAML

  1. En la máquina de desarrollo, abra el archivo C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avoFileWriter\requirements.txt y agregue "pyyaml" en una nueva línea del archivo.

    azure-iothub-device-client~=1.4.3
    pyyaml
    
  2. Abra el archivo Dockerfile.amd64 y agregue un comando pip install para actualizar setuptools.

    FROM ubuntu:xenial
    
    WORKDIR /app
    
    RUN apt-get update && \
        apt-get install -y --no-install-recommends libcurl4-openssl-dev python3-pip libboost-python1.58-dev libpython3-dev && \
        rm -rf /var/lib/apt/lists/\*
    
    RUN pip3 install --upgrade pip
    RUN pip install -U pip setuptools
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    
    COPY . .
    
    RUN useradd -ms /bin/bash moduleuser
    RUN mkdir /avrofiles && chown moduleuser /avrofiles
    RUN mkdir -p /app/iotconfig && chown moduleuser /app/iotconfig
    USER moduleuser
    
    CMD [ "python3", "-u", "./main.py" ]
    
  3. En un símbolo del sistema, instale pyyaml en la máquina de desarrollo.

    pip install pyyaml
    

Fastavro

  1. En requirements.txt, agregue fastavro después de pyyaml.

    azure-iothub-device-client~=1.4.3
    pyyaml
    fastavro
    
  2. Instale fastavro en la máquina de desarrollo.

    pip install fastavro
    

Reconfiguración de IoT Hub

Mediante la introducción de los módulos y el dispositivo IoT Edge en el sistema, hemos cambiado nuestras expectativas sobre qué datos se enviarán al concentrador y su finalidad. Es necesario volver a configurar el enrutamiento en el concentrador para tratar con nuestra nueva realidad.

Nota

El concentrador se vuelve a configurar antes de implementar los módulos porque algunas de las opciones de configuración del concentrador, específicamente la carga de archivos, debe configurarse correctamente para que el módulo avroFileWriter se ejecute correctamente

Configuración de ruta para los mensajes de RUL en IoT Hub

Con el enrutador y el clasificador preparados, se espera recibir mensajes regulares que contengan solo el id. del dispositivo y la predicción de RUL del dispositivo. Queremos enrutar los datos de RUL a su propia ubicación de almacenamiento donde podemos supervisar el estado de los dispositivos, compilar informes y activar alertas según sea necesario. Al mismo tiempo, queremos que los datos del dispositivo que se envían directamente a través de un dispositivo de bajada que aún no se ha vinculado a nuestro dispositivo IoT Edge se sigan enrutando a la ubicación de almacenamiento actual.

Creación de una ruta de mensajes RUL

  1. En Azure Portal, navegue a IoT Hub.

  2. En el menú del panel izquierdo, en Configuración central, seleccione Enrutamiento de mensajes.

  3. En la pestaña Rutas, seleccione Agregar.

  4. Asigne un nombre a la ruta RulMessageRoute.

  5. Seleccione Agregar punto de conexión a la derecha del selector de Punto de conexión y elija Almacenamiento.

  6. En la página Agregar un punto de conexión de almacenamiento, asigne el nombre ruldata al punto de conexión.

  7. Seleccione Seleccionar un contenedor.

  8. En la página Cuentas de almacenamiento, busque la cuenta de almacenamiento que está usando en este tutorial, cuyo nombre esiotedgeandml<sufijo único>.

  9. Elija el contenedor ruldata y haga clic en Seleccionar.

  10. De nuevo en la página Agregar un punto de conexión de almacenamiento, seleccione Crear para crear el punto de conexión de almacenamiento.

  11. De vuelta en la página Agregar una ruta para la Consulta de enrutamiento, reemplace true por la siguiente consulta:

    IS_DEFINED($body.PredictedRul) AND NOT IS_DEFINED($body.OperationalSetting1)
    
  12. Expanda la sección Prueba y, después, la sección Cuerpo del mensaje. Reemplace el cuerpo del mensaje con este ejemplo de nuestros mensajes esperados:

    {
      "ConnectionDeviceId": "aaLeafDevice_1",
      "CorrelationId": "b27e97bb-06c5-4553-a064-e9ad59c0fdd3",
      "PredictedRul": 132.62721409309165,
      "CycleTime": 64.0
    }
    
  13. Seleccione Probar ruta. Si la prueba es correcta, vera "El mensaje coincidió con la consulta".

  14. Haga clic en Save(Guardar).

Actualización de la ruta turbofanDeviceDataToStorage

No queremos enrutar los nuevos datos de predicción a la ubicación de almacenamiento anterior, por lo que es necesario actualizar la ruta.

  1. En la página Enrutamiento de mensajes de IoT Hub, seleccione la pestaña Rutas.

  2. Seleccione turbofanDeviceDataToStorage, o el nombre que haya asignado a la ruta de datos inicial del dispositivo.

  3. Actualización de la consulta de enrutamiento

    IS_DEFINED($body.OperationalSetting1)
    
  4. Expanda la sección Prueba y, después, la sección Cuerpo del mensaje. Reemplace el mensaje con este ejemplo de nuestros mensajes esperados:

    {
      "Sensor13": 2387.96,
      "OperationalSetting1": -0.0008,
      "Sensor6": 21.61,
      "Sensor11": 47.2,
      "Sensor9": 9061.45,
      "Sensor4": 1397.86,
      "Sensor14": 8140.39,
      "Sensor18": 2388.0,
      "Sensor12": 522.87,
      "Sensor2": 642.42,
      "Sensor17": 391.0,
      "OperationalSetting3": 100.0,
      "Sensor1": 518.67,
      "OperationalSetting2": 0.0002,
      "Sensor20": 39.03,
      "DeviceId": 19.0,
      "Sensor5": 14.62,
      "PredictedRul": 212.00132402791962,
      "Sensor8": 2388.01,
      "Sensor16": 0.03,
      "CycleTime": 42.0,
      "Sensor21": 23.3188,
      "Sensor15": 8.3773,
      "Sensor3": 1580.09,
      "Sensor10": 1.3,
      "Sensor7": 554.57,
      "Sensor19": 100.0
    }
    
  5. Seleccione Probar ruta. Si la prueba es correcta, vera "El mensaje coincidió con la consulta".

  6. Seleccione Guardar.

Configuración de la carga de archivos

Configure la característica de carga de archivos de IoT Hub para habilitar el módulo de escritor de archivos para la carga de archivos al almacenamiento.

  1. En el menú del panel izquierdo del IoT Hub, en Configuración de centro, elija Carga de archivo.

  2. Seleccione Contenedor de Azure Storage.

  3. Seleccione la cuenta de almacenamiento en la lista.

  4. Seleccione el contenedor que comienza con azureml-blobstore y tiene anexado un GUID, y haga clic en Seleccionar.

  5. Seleccione Guardar. El portal le avisa cuando se completa la operación de guardar.

Nota

No vamos a activar la notificación de carga para este tutorial, pero consulte Recepción de una notificación de carga de archivos para obtener más información acerca de cómo usar la notificación de carga de archivos.

Creación, publicación e implementación de módulos

Ahora que hemos modificado la configuración, ya está todo listo para compilar imágenes y publicarlas en Azure Container Registry. El proceso de compilación usa el archivo deployment.template.json para determinar qué módulos deben compilarse. La configuración de cada módulo, incluida la versión, se encuentra en el archivo module.json de la carpeta del módulo. En primer lugar, el proceso de compilación se ejecuta en una compilación de Docker en los archivos Dockerfile que coinciden con la configuración actual que se encuentra en el archivo module.json para crear una imagen. A continuación, publica la imagen en el registro desde el archivo module.json con una etiqueta de versión que coincide con la del archivo module.json. Por último, genera un manifiesto de implementación específico de la configuración (por ejemplo, deployment.amd64.json), que se implementará en el dispositivo IoT Edge. El dispositivo IoT Edge lee la información del manifiesto de implementación y, basándose en las instrucciones, descargará los módulos, y configurará las rutas y las propiedades que quiera. Este método de implementación tiene dos efectos secundarios que debería tener en cuenta:

  • Retardo de implementación: puesto que el entorno de ejecución de Azure IoT Edge debe reconocer el cambio a sus propiedades deseadas antes de comenzar a volver a configurar, puede pasar algún tiempo desde que se implementan los módulos hasta que el entorno de ejecución los detecta y empieza a actualizar el dispositivo IoT Edge.

  • Versiones del módulo: si publica una nueva versión de un contenedor del módulo en la instancia de Container Registry utilizando las mismas etiquetas de versión que el módulo anterior, el entorno de ejecución no descargará la nueva versión del módulo. Realiza una comparación de la etiqueta de la versión de la imagen local y la imagen deseada desde el manifiesto de implementación. Si esas versiones coinciden, el entorno de ejecución no realiza ninguna acción. Por lo tanto, es importante aumentar la versión del módulo cada vez que quiera implementar nuevos cambios. Aumente la versión cambiando la propiedad version en la propiedad tag del archivo module.json para el módulo que se va a cambiar. A continuación, compile y publique la solución.

    {
      "$schema-version": "0.0.1",
      "description": "",
      "image": {
        "repository": "<your registry>.azurecr.io/avrofilewriter",
        "tag": {
          "version": "0.0.1",
          "platforms": {
            "amd64": "./Dockerfile.amd64",
            "amd64.debug": "./Dockerfile.amd64.debug",
            "arm32v7": "./Dockerfile.arm32v7"
          }
        },
        "buildOptions": []
      },
      "language": "python"
    }
    

Compilación y publicación

  1. En la máquina virtual de desarrollo, inicie Docker si aún no se está ejecutando.

  2. En Visual Studio Code, inicie un nuevo terminal con el símbolo del sistema e inicie sesión en Azure Container Registry (ACR).

Puede encontrar los valores de nombre de usuario, contraseña y servidor de inicio de sesión necesarios en Azure Portal. El nombre del registro de contenedor tiene el formato "turbofandemo<identificador único>". En el menú del panel izquierdo, en Ajustes, seleccione Claves de acceso para verlas.

docker login -u <ACR username> -p <ACR password> <ACR login server>
  1. En Visual Studio Code, haga clic con el botón derecho en el archivo deployment.template.json y seleccione Build and Push IoT Edge solution (Compilar e insertar solución IoT Edge).

Vista de módulos en el registro

Una vez que la compilación se complete correctamente, se podrá usar Azure Portal para revisar los módulos publicados.

  1. Abra la instancia de Azure Container Registry para este tutorial. El nombre del registro de contenedor tiene el formato "turbofandemo<identificador único>".

  2. En el menú del panel izquierdo, en Servicios, seleccione Repositorios.

  3. Tenga en cuenta que los módulos que creó, avrofilewriter y turbofanrouter, aparecen como repositorios.

  4. Seleccione turbofanrouter y tenga en cuenta que ha publicado una imagen etiquetada como 0.0.1-amd64.

    Visualización de la primera versión etiquetada de turbofanrouter

Implementación de módulos en un dispositivo IoT Edge

Hemos compilado y configurado los módulos en nuestra solución, ahora los implementaremos en el dispositivo IoT Edge.

  1. En Visual Studio Code, haga clic en el archivo deployment.amd64.json de la carpeta config.

  2. Seleccione Crear una implementación para un dispositivo individual.

  3. Elija el dispositivo IoT Edge, aaTurboFanEdgeDevice.

  4. Actualice el panel de dispositivos de Azure IoT Hub en el explorador de Visual Studio Code. Debería ver implementados los tres nuevos módulos, que aún no se están ejecutando.

  5. Vuelva a actualizar después de unos minutos y verá los módulos en ejecución.

    Visualización de los módulos en ejecución en Visual Studio Code

Nota

Los módulos pueden tardar varios minutos en iniciarse y establecerse en un estado de ejecución estable. Durante ese tiempo, es posible que vea que los módulos se inician y detienen mientras intentan establecer una conexión con el módulo del centro de IoT Edge.

Diagnóstico de errores

En esta sección, se comparten algunas técnicas para comprender qué ha ido mal con un módulo o módulos. A menudo, un error suele detectarse en primer lugar desde el estado de Visual Studio Code.

Identificación de módulos con errores

  • Visual Studio Code: consulte el panel de dispositivos de Azure IoT Hub. Si la mayoría de los módulos está en un estado de ejecución, pero uno está detenido, deberá investigar porqué lo está. Si todos los módulos están detenidos durante un largo período de tiempo, esto también puede indicar un error.

  • Azure Portal: si navega a IoT Hub en el portal y, después, busca la página de detalles del dispositivo (en IoT Edge, profundice en el dispositivo) es posible que descubra que un módulo ha detectado un error o que nunca ha notificado nada a IoT Hub.

Diagnóstico desde el dispositivo

Al iniciar sesión en el dispositivo IoT Edge (la máquina virtual Linux en nuestro caso), puede obtener acceso a una gran cantidad de información acerca del estado de los módulos. El principal mecanismo que usamos son los comandos de Docker que permiten examinar los contenedores y las imágenes en el dispositivo.

  1. Inicie sesión en el dispositivo IoT Edge:

    ssh -l <user>@IoTEdge-<extension>.<region>.cloudapp.azure.com
    
  2. Enumere todos los contenedores en ejecución. Se espera ver un contenedor por módulo con un nombre que se corresponde con dicho módulo. Además, este comando muestra la imagen del contenedor, incluida la versión para que coincida con sus expectativas. También puede enumerar las imágenes sustituyendo "image" por "container" en el comando.

    sudo docker container ls
    
  3. Obtenga los registros de un contenedor. Este comando da como resultado lo que se ha escrito en StdErr y StdOut en el contenedor. Este comando funciona para los contenedores que se iniciaron y, después, desaparecieron por algún motivo. También es útil para comprender qué está pasando con los contenedores edgeAgent o edgeHub.

    sudo docker container logs <container id>
    
  4. Inspeccione un contenedor. Este comando proporciona una gran cantidad de información sobre la imagen. Los datos se pueden filtrar según lo que busca. Por ejemplo, si quiere ver si son correctos los enlaces en avroFileWriter puede usar el comando:

    sudo docker container inspect -f "{{ json .Mounts }}" avroFileWriter | python -m json.tool
    
  5. Conéctese a un contenedor en ejecución. Este comando puede ser útil si quiere examinar el contenedor mientras se está ejecutando:

    sudo docker exec -it avroFileWriter bash
    

Limpieza de recursos

Este tutorial forma parte de una serie en la que cada artículo complementa el trabajo realizado en los anteriores. No borre ningún recurso hasta que complete el tutorial final.

Pasos siguientes

En este artículo, hemos creado una solución de IoT Edge en Visual Studio Code con tres módulos: un clasificador, un enrutador y un sistema de escritura y carga de archivos. Configuramos las rutas para permitir que los módulos se comuniquen entre sí en el dispositivo Edge. Modificamos la configuración del dispositivo Edge y actualizamos los archivos Dockerfiles para instalar las dependencias y agregar montajes de enlace a los contenedores de los módulos.

A continuación, hemos actualizado la configuración de IoT Hub para enrutar los mensajes según el tipo y controlar las cargas de archivos. Con todo preparado, implementamos los módulos en el dispositivo IoT Edge y garantizamos que los módulos se estaban ejecutando correctamente.

Continúe con el siguiente artículo para empezar a enviar datos y ver la solución en acción.

Send data via transparent gateway (Envío de datos mediante una puerta de enlace transparente)