자습서: Visual Studio Code를 사용하여 IoT Edge 모듈 개발

적용 대상:IoT Edge 1.4 checkmark IoT Edge 1.4

Important

IoT Edge 1.4는 지원되는 릴리스입니다. 이전 릴리스에 있는 경우 IoT Edge 업데이트를 참조하세요.

이 자습서에서는 IoT Edge 디바이스에 고유한 코드를 개발하고 배포하는 방법을 안내합니다. Azure IoT Edge 모듈을 사용하여 비즈니스 논리를 구현하는 코드를 IoT Edge 디바이스에 직접 배포할 수 있습니다. Linux 디바이스에 코드 배포 빠른 시작에서 IoT Edge 디바이스를 만들고 Azure Marketplace에서 모듈을 배포했습니다.

이 문서에는 두 개의 IoT Edge 개발 도구에 대한 단계가 포함되어 있습니다.

  • Azure IoT Edge CLI(Dev Tool 명령줄). 이 도구는 개발에 선호됩니다.
  • Visual Studio Code 용 Azure IoT Edge 도구 확장 확장은 기본 테넌트 모드입니다.

이 문서의 시작 부분에 있는 도구 선택기 단추를 사용하여 도구 버전을 선택합니다.

이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.

  • 개발 머신을 설정합니다.
  • IoT Edge 도구를 사용하여 새 프로젝트를 만듭니다.
  • 프로젝트를 Docker 컨테이너빌드하고 Azure 컨테이너 레지스트리에 저장합니다.
  • IoT Edge 디바이스에 코드를 배포합니다.

이 자습서에서 만드는 IoT Edge 모듈은 디바이스에서 생성하는 온도 데이터를 필터링합니다. 온도가 지정된 임계값을 초과하는 경우에만 메시지 업스트림을 전송합니다. Edge에서 이 유형의 분석은 클라우드로 전송되고 저장되는 데이터 양을 줄이는 데 유용합니다.

필수 조건

개발 머신:

  • 사용자 고유의 컴퓨터 또는 가상 머신을 사용합니다.
  • 개발 머신은 컨테이너 엔진을 실행하기 위해 중첩된 가상화를 지원해야 합니다.
  • 컨테이너 엔진을 실행할 수 있는 대부분의 운영 체제를 사용하여 Linux 디바이스용 IoT Edge 모듈을 개발할 수 있습니다. 이 자습서에서는 Windows 컴퓨터를 사용하지만 macOS 또는 Linux의 알려진 차이점을 지적합니다.
  • Visual Studio Code를 설치합니다.
  • Azure CLI를 설치합니다.

Azure IoT Edge 디바이스:

클라우드 리소스:

  • Azure의 무료 또는 표준 계층 IoT 허브 입니다.

Azure를 구독하고 있지 않다면 시작하기 전에 Azure 체험 계정을 만듭니다.

Visual Studio Code 또는 Visual Studio 2022의 대화형 디버깅에 대한 지침은 다음과 같습니다.

이 자습서에서는 Visual Studio Code에 대한 개발 단계를 설명합니다.

주요 개념

이 자습서는 IoT Edge 모듈 개발 과정을 안내합니다. IoT Edge 모듈은 실행 코드가 있는 컨테이너입니다. 하나 이상의 모듈을 IoT Edge 디바이스에 배포할 수 있습니다. 모듈은 센서에서 데이터 수집, 데이터 정리 및 분석 또는 IoT 허브로 메시지 보내기 등의 특정 작업을 수행합니다. 자세한 내용은 Azure IoT Edge 모듈 이해

IoT Edge 모듈을 개발할 때는 개발 머신과 모듈이 배포되는 대상 IoT Edge 디바이스 간의 차이점을 이해하는 것이 중요합니다. 모듈 코드를 보관하기 위해 빌드하는 컨테이너는 대상 디바이스OS(운영 체제)와 일치해야 합니다. 예를 들어 가장 일반적인 시나리오는 IoT Edge를 실행하는 Linux 디바이스를 대상으로 하는 Windows 컴퓨터에서 모듈을 개발하는 사람입니다. 이 경우 컨테이너 운영 체제는 Linux입니다. 이 자습서를 진행할 때는 개발 머신 OS컨테이너 OS 간의 차이점에 유의해야 합니다.

Windows에서 Linux용 IoT Edge를 사용하는 경우 시나리오의 대상 디바이스는 Windows 호스트가 아닌 Linux 가상 머신입니다.

이 자습서에서는 Linux 컨테이너를 사용하여 IoT Edge를 실행하는 디바이스를 대상으로 합니다. 개발 컴퓨터에서 Linux 컨테이너를 실행하는 한 원하는 운영 체제를 사용할 수 있습니다. Visual Studio Code를 사용하여 Linux 컨테이너를 사용하여 개발하는 것이 좋으므로 이 자습서에서 사용합니다. 두 도구 간에 지원의 차이점이 있지만 Visual Studio도 사용할 수 있습니다.

다음 표에는 Visual Studio Code 및 Visual Studio의 Linux 컨테이너에 대해 지원되는 개발 시나리오가 나와 있습니다.

Visual Studio Code Visual Studio 2019/2022
Linux 디바이스 아키텍처 Linux AMD64
Linux ARM32v7
Linux ARM64
Linux AMD64
Linux ARM32
Linux ARM64
Azure 서비스 Azure Functions
Azure Stream Analytics
Azure Machine Learning
언어 C
C#
Java
Node.js
Python
C
C#
추가 정보 Visual Studio Code용 Azure IoT Edge Visual Studio 2019용 Azure IoT Edge 도구
Visual Studio 2022용 Azure IoT Edge 도구

컨테이너 엔진 설치

IoT Edge 모듈은 컨테이너로 패키지되므로 개발 머신에서 Docker 호환 컨테이너 관리 시스템을 빌드하고 관리해야 합니다. 기능 지원 및 인기도 때문에 개발용 Docker Desktop을 사용하는 것이 좋습니다. Windows의 Docker Desktop을 사용하면 다양한 유형의 IoT Edge 디바이스에 대한 모듈을 개발할 수 있도록 Linux 컨테이너와 Windows 컨테이너 간에 전환할 수 있습니다.

Docker 설명서를 사용하여 개발 머신에 설치합니다.

  • Windows용 Docker Desktop 설치

    • Windows용 Docker Desktop을 설치할 때 Linux 또는 Windows 컨테이너를 사용할지 묻는 메시지가 표시됩니다. 언제든지 이 결정을 변경할 수 있습니다. 이 자습서에서는 모듈이 Linux 디바이스를 대상으로 하므로 Linux 컨테이너를 사용합니다. 자세한 내용은 Windows와 Linux 컨테이너 간 전환을 참조 하세요.
  • Mac용 Docker Desktop 설치

  • 여러 Linux 플랫폼의 설치 정보에 대해서는 Docker CE 정보를 참조하세요.

    • WSL(Linux용 Windows 하위 시스템)의 경우 Windows용 Docker Desktop을 설치합니다.

도구 설정

Python 기반 Azure IoT Edge 개발자 도구를 설치하여 IoT Edge 솔루션을 만듭니다. 두 옵션이 있습니다.

Important

Visual Studio Code용 Azure IoT Edge 도구 확장은 기본 테넌트 모드입니다. 기본 개발 도구는 CLI(명령줄) Azure IoT Edge 개발자 도구입니다.

Visual Studio Code용 IoT 확장을 사용하여 IoT Edge 모듈을 개발합니다. 이러한 확장은 프로젝트 템플릿을 제공하고, 배포 매니페스트 만들기를 자동화하며, IoT Edge 디바이스를 모니터링하고 관리할 수 있습니다. 이 섹션에서는 Visual Studio Code 및 IoT 확장을 설치한 다음, Visual Studio Code 내에서 IoT Hub 리소스를 관리하도록 Azure 계정을 설정합니다.

  1. Azure IoT Edge 확장을 설치합니다.

  2. Azure IoT Hub 확장을 설치합니다.

  3. 확장을 설치한 후 명령 팔레트 보기를>선택하여 명령 팔레트엽니다.

  4. 명령 팔레트에서 Azure IoT Hub를 검색하여 선택합니다 . IoT Hub를 선택합니다. 프롬프트에 따라 Azure 구독 및 IoT Hub를 선택합니다.

  5. 왼쪽의 작업 표시줄에서 아이콘을 선택하거나 보기>탐색기를 선택하여 Visual Studio Code의 탐색기 섹션을 엽니다.

  6. 탐색기 섹션의 맨 아래에서 축소된 Azure IoT Hub/디바이스 메뉴를 확장합니다 . 명령 팔레트를 통해 선택한 IoT Hub와 연결된 디바이스 및 IoT Edge 디바이스가 표시됩니다.

언어별 도구 설치

개발 중인 언어와 관련된 도구를 설치합니다.

컨테이너 레지스트리 만들기

이 자습서에서는 Azure IoT Edge 및 Azure IoT Hub 확장을 사용하여 모듈을 빌드하고 파일에서 컨테이너 이미지를 만듭니다. 그런 다음 이미지를 저장하고 관리하는 레지스트리이 이미지를 푸시합니다. 마지막으로 레지스트리에서 이미지를 배포하여 IoT Edge 디바이스에서 실행합니다.

Important

Azure IoT Edge Visual Studio Code 확장은 기본 테넌트 모드입니다.

임의 Docker 호환 레지스트리를 사용하여 컨테이너 이미지를 유지할 수 있습니다. 두 개의 인기 있는 Docker 레지스트리 서비스는 Azure Container RegistryDocker Hub입니다. 이 자습서에서는 Azure Container Registry를 사용합니다.

컨테이너 레지스트리가 아직 없는 경우 다음 단계에 따라 Azure에서 새 레지스트리를 만듭니다.

  1. Azure Portal에서 리소스 만들기>컨테이너>Container Registry를 선택합니다.

  2. 컨테이너 레지스트리를 만드는 데 필요한 값은 다음과 같습니다.

    필드
    구독 드롭다운 목록에서 구독을 선택합니다.
    Resource group IoT Edge 빠른 시작 및 자습서 중에 만든 모든 테스트 리소스에 대해 동일한 리소스 그룹을 사용합니다. 예를 들어 IoTEdgeResources입니다.
    레지스트리 이름 고유한 이름을 입력합니다.
    위치 가까운 위치를 선택합니다.
    SKU 기본을 선택합니다.
  3. 검토 + 만들기를 선택한 다음 만들기를 선택합니다.

  4. Azure Portal 홈페이지의 리소스 섹션에서 새 컨테이너 레지스트리를 선택하여 엽니다.

  5. 컨테이너 레지스트리의 왼쪽 창에서 설정 아래에 있는 메뉴에서 액세스 키를 선택합니다.

    Screenshot of the Access Keys menu location.

  6. 토글 단추를 사용하여 관리 사용자를 사용하도록 설정하고 컨테이너 레지스트리의 사용자 이름암호를 봅니다.

  7. 로그인 서버, 사용자 이름암호에 대한 값을 복사하고 편리한 위치에 저장합니다. 이 자습서 전반에서 이러한 값을 사용하여 컨테이너 레지스트리에 대한 액세스를 제공합니다.

새 모듈 프로젝트 만들기

Azure IoT Edge 확장은 Visual Studio Code에서 지원되는 모든 IoT Edge 모듈 언어에 대한 프로젝트 템플릿을 제공합니다. 이러한 템플릿에는 작업 모듈을 배포하여 IoT Edge를 테스트하거나 고유한 비즈니스 논리를 사용하여 템플릿을 사용자 지정하기 위한 시작점을 제공하는 데 필요한 모든 파일과 코드가 있습니다.

프로젝트 템플릿 만들기

IoT Edge 개발자 도구환경 변수에 의해 구동되는 명령으로 Azure IoT Edge 개발을 간소화합니다. 기본 모듈 및 모든 필수 구성 파일이 있는 IoT Edge 개발자 컨테이너 및 IoT Edge 솔루션 스캐폴딩을 사용하여 IoT Edge 개발을 시작합니다.

  1. 선택한 경로를 사용하여 솔루션에 대한 디렉터리를 만듭니다. 디렉터리로 변경합니다 iotedgesolution .

    mkdir c:\dev\iotedgesolution
    cd c:\dev\iotedgesolution
    
  2. iotedgedev solution init 명령을 사용하여 솔루션을 만들고 선택한 개발 언어로 Azure IoT Hub를 설정합니다.

    iotedgedev solution init --template csharp
    

iotedgedev solution init 스크립트는 다음을 포함한 여러 단계를 완료하라는 메시지를 표시합니다.

  • Azure에 대한 인증
  • Azure 구독 선택
  • 리소스 그룹 선택 또는 만들기
  • Azure IoT Hub 선택 또는 만들기
  • Azure IoT Edge 디바이스 선택 또는 만들기

Visual Studio Code 및 Azure IoT Edge 확장을 사용합니다. 먼저 솔루션을 만든 다음 해당 솔루션에서 첫 번째 모듈을 생성합니다. 각 솔루션에는 여러 모듈이 포함될 수 있습니다.

  1. >명령 팔레트를 선택합니다.
  2. 명령 팔레트에서 Azure IoT Edge: New IoT Edge Solution 명령을 입력하고 실행합니다.
  3. 새 솔루션을 만들 폴더로 이동한 다음 폴더 선택을 선택합니다.
  4. 솔루션에 대한 이름을 입력합니다.
  5. 원하는 개발 언어의 모듈 템플릿을 솔루션의 첫 번째 모듈로 선택합니다.
  6. 모듈의 이름을 입력합니다. 컨테이너 레지스트리 내에서 고유한 이름을 선택합니다.
  7. 모듈의 이미지 리포지토리 이름을 입력합니다. Visual Studio Code는 localhost:5000/<모듈 이름>으로 모듈 이름을 자동으로 채웁니다. 고유한 레지스트리 정보로 바꿉니다. 테스트에 로컬 Docker 레지스트리를 사용하는 경우 localhost를 사용합니다. Azure Container Registry를 사용하는 경우 레지스트리 설정에서 로그인 서버를 사용합니다. 로그인 서버는 registry name.azurecr.io> 같습니다.< 최종 결과가 registry name.azurecr.io/>< your 모듈 이름>처럼< 보이도록 문자열의 localhost:5000 부분만 바꿉습니다.

Visual Studio Code는 입력한 정보를 사용하여 IoT Edge 솔루션을 만든 다음, 새 창에서 로드합니다.

솔루션을 만든 후 이러한 기본 파일이 솔루션에 있습니다.

  • .vscode 폴더에는 구성 파일 launch.json이 포함되어 있습니다.

  • 각 모듈에 대한 하위 폴더가 있는 모듈 폴더입니다. 각 모듈의 하위 폴더 내에는 파일 module.json 파일이 모듈을 빌드하고 배포하는 방법을 제어합니다.

  • .env 파일에는 환경 변수가 나열됩니다. 컨테이너 레지스트리의 환경 변수는 기본적으로 localhost:5000입니다.

  • deployment.template.json 명명된 두 개의 모듈 배포 파일과 deployment.debug.template.json 디바이스에 배포할 모듈을 나열합니다. 기본적으로 목록에는 IoT Edge 시스템 모듈(edgeAgent 및 edgeHub) 및 다음과 같은 샘플 모듈이 포함됩니다.

    참고 항목

    설치된 정확한 모듈은 선택한 언어에 따라 달라질 수 있습니다.

IoT Edge 런타임 버전 설정

안정적인 최신 IoT Edge 시스템 모듈 버전은 1.4입니다. 시스템 모듈을 버전 1.4로 설정합니다.

  1. Visual Studio Code에서 deployment.template.json 배포 매니페스트 파일을 엽니다. 배포 매니페스트는 대상 IoT Edge 디바이스에 구성할 모듈을 설명하는 JSON 문서입니다.

  2. 시스템 런타임 모듈 이미지 edgeAgentedgeHub의 런타임 버전을 변경합니다. 예를 들어 IoT Edge 런타임 버전 1.4를 사용하려면 배포 매니페스트 파일에서 다음 줄을 변경합니다.

    "systemModules": {
        "edgeAgent": {
    
            "image": "mcr.microsoft.com/azureiotedge-agent:1.4",
    
        "edgeHub": {
    
            "image": "mcr.microsoft.com/azureiotedge-hub:1.4",
    

IoT Edge 에이전트에 레지스트리 자격 증명 제공

환경 파일은 컨테이너 레지스트리에 대한 자격 증명을 저장하고 IoT Edge 런타임과 공유합니다. 이러한 자격 증명은 런타임에서 컨테이너 이미지를 IoT Edge 디바이스로 가져오기 위해 필요합니다.

IoT Edge 확장은 Azure에서 컨테이너 레지스트리 자격 증명을 가져와서 환경 파일에 채우려고 합니다.

참고 항목

환경 파일은 모듈에 대한 이미지 리포지토리를 제공하는 경우에만 생성됩니다. localhost 기본값을 로컬로 테스트하고 디버그하도록 수락하는 경우 환경 변수를 선언할 필요가 없습니다.

자격 증명이 있는지 확인합니다. 그렇지 않은 경우 지금 추가합니다.

  1. Azure Container Registry가 레지스트리인 경우 Azure Container Registry 사용자 이름 및 암호를 설정합니다. Azure Portal의 컨테이너 레지스트리 설정>Access 키 메뉴에서 이러한 값을 가져옵니다.

  2. 모듈 솔루션에서 .env 파일을 엽니다.

  3. Azure Container Registry에서 복사한 사용자 이름암호 값을 추가합니다. 예시:

    CONTAINER_REGISTRY_SERVER="myacr.azurecr.io"
    CONTAINER_REGISTRY_USERNAME="myacr"
    CONTAINER_REGISTRY_PASSWORD="<registry_password>"
    
  4. 변경 내용을 .env 파일에 저장합니다.

참고 항목

이 자습서에서는 개발 및 테스트 시나리오에 편리한 Azure Container Registry에 대한 관리자 로그인 자격 증명을 사용합니다. 프로덕션 시나리오에 사용할 준비가 되면 서비스 주체 또는 리포지토리 범위 토큰과 같은 최소 권한 인증 옵션을 사용하는 것이 좋습니다. 자세한 내용은 컨테이너 레지스트리에 대한 액세스 관리를 참조 하세요.

대상 아키텍처

컨테이너를 빌드하고 실행하는 방법에 영향을 주므로 각 솔루션에서 대상으로 지정하는 아키텍처를 선택해야 합니다. 기본값은 Linux AMD64입니다. 이 자습서에서는 Ubuntu 가상 머신을 IoT Edge 디바이스로 사용하고 기본 amd64를 유지합니다.

솔루션의 대상 아키텍처를 변경해야 하는 경우 다음 단계를 사용합니다.

  1. 명령 팔레트를 열고 Azure IoT Edge를 검색 합니다. Edge 솔루션에 대한 기본 대상 플랫폼 설정 또는 창 아래쪽의 사이드바에서 바로 가기 아이콘을 선택합니다.

  2. 명령 팔레트의 옵션 목록에서 대상 아키텍처를 선택합니다.

대상 아키텍처는 이후 단계에서 컨테이너 이미지를 만들 때 설정됩니다.

사용자 지정 코드를 사용하여 모듈 업데이트

각 템플릿에는 SimulatedTemperatureSensor 모듈에서 시뮬레이션된 센서 데이터를 가져와서 IoT 허브로 라우팅하는 샘플 코드가 포함되어 있습니다. 샘플 모듈은 메시지를 받은 다음 전달합니다. 파이프라인 기능은 모듈이 서로 통신하는 방식인 IoT Edge의 중요한 개념을 보여 줍니다.

각 모듈의 코드에는 여러 개의 입력출력 큐가 선언될 수 있습니다. 디바이스에서 실행되는 IoT Edge 허브는 한 모듈의 출력에서 하나 이상의 모듈의 입력으로 메시지를 라우팅합니다. 입력 및 출력을 선언하기 위한 특정 코드는 언어마다 다르지만 개념은 모든 모듈에서 동일합니다. 모듈 간의 라우팅에 대한 자세한 내용은 경로 선언을 참조하세요.

프로젝트 템플릿과 함께 제공되는 샘플 C# 코드는 .NET용 IoT Hub SDK의 ModuleClient 클래스를 사용합니다.

  1. Visual Studio Code 탐색기에서 모듈>filtermodule>ModuleBackgroundService.cs 엽니다.

  2. filtermodule 네임스페이스 앞에 나중에 사용되는 형식에 대해 세 개의 using 문을 추가합니다.

    using System.Collections.Generic;     // For KeyValuePair<>
    using Microsoft.Azure.Devices.Shared; // For TwinCollection
    using Newtonsoft.Json;                // For JsonConvert
    
  3. moduleBackgroundService 클래스에 temperatureThreshold 변수를 추가합니다. 이 변수는 데이터를 IoT Hub로 보내려면 측정된 온도가 초과해야 하는 값을 설정합니다.

    static int temperatureThreshold { get; set; } = 25;
    
  4. MessageBody, MachineAmbient 클래스를 추가합니다. 이러한 클래스는 수신 메시지 본문의 예상 스키마를 정의합니다.

    class MessageBody
    {
        public Machine machine {get;set;}
        public Ambient ambient {get; set;}
        public string timeCreated {get; set;}
    }
    class Machine
    {
        public double temperature {get; set;}
        public double pressure {get; set;}
    }
    class Ambient
    {
        public double temperature {get; set;}
        public int humidity {get; set;}
    }
    
  5. ExecuteAsync 함수를 찾습니다. 이 함수는 모듈이 로컬 Azure IoT Edge 런타임에 연결하여 메시지를 보내고 받을 수 있도록 하는 ModuleClient 개체를 만들고 구성합니다. ModuleClient를 만든 후 코드는 모듈 쌍의 desired 속성에서 temperatureThreshold 값을 읽습니다. 이 코드는 input1이라는 엔드포인트를 통해 IoT Edge 허브에서 메시지를 수신하는 콜백을 등록합니다.

    ProcessMessageAsync 메서드에 대한 호출을 엔드포인트의 이름과 입력이 도착할 때 호출되는 메서드를 업데이트하는 새 메서드로 바꿉니다. 또한 원하는 속성에 대한 업데이트를 위해 SetDesiredPropertyUpdateCallbackAsync 메서드를 추가합니다. 이렇게 변경하려면 ExecuteAsync 메서드의 마지막 줄을 다음 코드로 바꿉다.

    // Register a callback for messages that are received by the module.
    // await _moduleClient.SetInputMessageHandlerAsync("input1", PipeMessage, cancellationToken);
    
    // Read the TemperatureThreshold value from the module twin's desired properties
    var moduleTwin = await _moduleClient.GetTwinAsync();
    await OnDesiredPropertiesUpdate(moduleTwin.Properties.Desired, _moduleClient);
    
    // Attach a callback for updates to the module twin's desired properties.
    await _moduleClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertiesUpdate, null);
    
    // Register a callback for messages that are received by the module. Messages received on the inputFromSensor endpoint are sent to the FilterMessages method.
    await _moduleClient.SetInputMessageHandlerAsync("inputFromSensor", FilterMessages, _moduleClient);
    
  6. ModuleBackgroundService 클래스에 onDesiredPropertiesUpdate 메서드를 추가합니다. 이 메서드는 모듈 쌍에서 원하는 속성에 대한 업데이트를 수신하고 일치하도록 temperatureThreshold 변수를 업데이트합니다. 모든 모듈에는 자체 모듈 쌍이 있어서 클라우드에서 직접 모듈 내에서 실행되는 코드를 구성할 수 있습니다.

    static Task OnDesiredPropertiesUpdate(TwinCollection desiredProperties, object userContext)
    {
        try
        {
            Console.WriteLine("Desired property change:");
            Console.WriteLine(JsonConvert.SerializeObject(desiredProperties));
    
            if (desiredProperties["TemperatureThreshold"]!=null)
                temperatureThreshold = desiredProperties["TemperatureThreshold"];
    
        }
        catch (AggregateException ex)
        {
            foreach (Exception exception in ex.InnerExceptions)
            {
                Console.WriteLine();
                Console.WriteLine("Error when receiving desired property: {0}", exception);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error when receiving desired property: {0}", ex.Message);
        }
        return Task.CompletedTask;
    }
    
  7. FilterMessages 메서드를 추가합니다. 이 메서드는 모듈이 IoT Edge 허브에서 메시지를 받을 때마다 호출됩니다. 모듈 쌍을 통해 설정된 온도 임계값 이하의 온도를 보고하는 메시지를 필터링합니다. 또한 값이 경고로 설정된 메시지에 MessageType 속성을 추가합니다.

    async Task<MessageResponse> FilterMessages(Message message, object userContext)
    {
        var counterValue = Interlocked.Increment(ref _counter);
        try
        {
            ModuleClient moduleClient = (ModuleClient)userContext;
            var messageBytes = message.GetBytes();
            var messageString = Encoding.UTF8.GetString(messageBytes);
            Console.WriteLine($"Received message {counterValue}: [{messageString}]");
    
            // Get the message body.
            var messageBody = JsonConvert.DeserializeObject<MessageBody>(messageString);
    
            if (messageBody != null && messageBody.machine.temperature > temperatureThreshold)
            {
                Console.WriteLine($"Machine temperature {messageBody.machine.temperature} " +
                    $"exceeds threshold {temperatureThreshold}");
                using (var filteredMessage = new Message(messageBytes))
                {
                    foreach (KeyValuePair<string, string> prop in message.Properties)
                    {
                        filteredMessage.Properties.Add(prop.Key, prop.Value);
                    }
    
                    filteredMessage.Properties.Add("MessageType", "Alert");
                    await moduleClient.SendEventAsync("output1", filteredMessage);
                }
            }
    
            // Indicate that the message treatment is completed.
            return MessageResponse.Completed;
        }
        catch (AggregateException ex)
        {
            foreach (Exception exception in ex.InnerExceptions)
            {
                Console.WriteLine();
                Console.WriteLine("Error in sample: {0}", exception);
            }
            // Indicate that the message treatment is not completed.
            var moduleClient = (ModuleClient)userContext;
            return MessageResponse.Abandoned;
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error in sample: {0}", ex.Message);
            // Indicate that the message treatment is not completed.
            ModuleClient moduleClient = (ModuleClient)userContext;
            return MessageResponse.Abandoned;
        }
    }
    
  8. ModuleBackgroundService.cs 파일을 저장합니다.

  9. Visual Studio Code 탐색기에서 IoT Edge 솔루션 작업 영역에서 deployment.template.json 파일을 엽니다.

  10. 모듈이 수신 대기하는 엔드포인트의 이름을 변경했으므로 edgeHub가 새 엔드포인트로 메시지를 보내도록 배포 매니페스트의 경로도 업데이트해야 합니다.

    $edgeHub 모듈 쌍에서 경로 섹션을 찾습니다. 다음으로 inputFromSensor대체 input1 하도록 sensorTofiltermodule 경로를 업데이트합니다.

    "sensorTofiltermodule": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/filtermodule/inputs/inputFromSensor\")"
    
  11. filtermodule 모듈 쌍을 배포 매니페스트에 추가합니다. $edgeHub 모듈 쌍 뒤에 modulesContent 섹션 맨 아래에 다음 JSON 콘텐츠를 삽입합니다.

       "filtermodule": {
           "properties.desired":{
               "TemperatureThreshold":25
           }
       }
    
  12. deployment.template.json 파일을 저장합니다.

솔루션 빌드 및 푸시

몇 가지 주요 배포 개념을 이해하는 데 도움이 되도록 모듈 코드 및 배포 템플릿을 업데이트했습니다. 이제 모듈 컨테이너 이미지를 빌드하고 컨테이너 레지스트리에 푸시할 준비가 되었습니다.

Visual Studio Code에서 deployment.template.json 배포 매니페스트 파일을 엽니다. 배포 매니페스트대상 IoT Edge 디바이스에서 구성할 모듈을 설명합니다. 배포하기 전에 Azure Container Registry 자격 증명 및 모듈 이미지를 적절한 createOptions 값으로 업데이트해야 합니다. createOption 값에 대한 자세한 내용은 IoT Edge 모듈에 대한 컨테이너 만들기 옵션 구성 방법을 참조하세요.

Azure Container Registry를 사용하여 모듈 이미지를 저장하는 경우 deployment.template.json modulesContent edgeAgent>설정>registryCredentials 섹션에 자격 증명을 추가합니다.> myacr를 사용자 고유의 레지스트리 이름으로 바꾸고 암호 및 로그인 서버 주소를 제공합니다. 예시:

"registryCredentials": {
    "myacr": {
        "username": "myacr",
        "password": "<your_acr_password>",
        "address": "myacr.azurecr.io"
    }
}

나열된 각 시스템(edgeHub 및 edgeAgent) 및 사용자 지정 모듈(filtermodule 및 tempSensor)의 createOptions 값에 다음 문자열화된 콘텐츠를 추가하거나 바꿉니다. 필요한 경우 값을 변경합니다.

"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"

예를 들어 filtermodule 구성은 다음과 유사해야 합니다.

"filtermodule": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
   "image": "myacr.azurecr.io/filtermodule:0.0.1-amd64",
   "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
}

모듈 Docker 이미지 빌드

터미널 새 터미널을 선택하여 Visual Studio Code 통합 터미널>엽니다.

명령을 dotnet publish 사용하여 Linux 및 amd64 아키텍처용 컨테이너 이미지를 빌드합니다. 디렉터리를 프로젝트의 filtermodule 디렉터리로 변경하고 dotnet publish 명령을 실행합니다.

dotnet publish --os linux --arch x64 /t:PublishContainer

현재 iotedgedev 도구 템플릿은 .NET 7.0을 대상으로 합니다. 다른 버전의 .NET을 대상으로 지정하려면 filtermodule.csproj 파일을 편집하고 TargetFrameworkPackageReference 값을 변경할 있습니다. 예를 들어 .NET 8.0 을 대상으로 지정하려면 filtermodule.csproj 파일이 다음과 같이 표시됩니다.

<Project Sdk="Microsoft.NET.Sdk.Worker">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.42.0" />
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    </ItemGroup>
</Project>

컨테이너 레지스트리 정보, 버전 및 아키텍처를 사용하여 Docker 이미지에 태그를 지정합니다. myacr를 사용자 고유의 레지스트리 이름으로 바꿉 있습니다.

docker tag filtermodule myacr.azurecr.io/filtermodule:0.0.1-amd64

모듈 Docker 이미지 푸시

컨테이너 이미지를 레지스트리의 스토리지에 푸시할 수 있도록 Docker에 컨테이너 레지스트리 자격 증명을 제공합니다.

  1. ACR(Azure Container Registry) 자격 증명을 사용하여 Docker에 로그인합니다.

    docker login -u <ACR username> -p <ACR password> <ACR login server>
    

    사용을 --password-stdin권장하는 보안 경고가 표시될 수 있습니다. 이는 프로덕션 시나리오에 권장되는 모범 사례이지만 이 자습서의 범위를 벗어납니다. 자세한 내용은 docker 로그인 참조를 참조하세요.

  2. Azure Container Registry에 로그인합니다. 명령을 사용 az 하려면 Azure CLI를 설치해야 합니다. 이 명령은 설정Access 키의 컨테이너 레지스트리에 있는 >사용자 이름 및 암호를 요청합니다.

    az acr login -n <ACR registry name>
    

    이 자습서의 어느 시점에서나 로그아웃된 경우 Docker 및 Azure Container Registry 로그인 단계를 반복하여 계속합니다.

  3. 모듈 이미지를 로컬 레지스트리 또는 컨테이너 레지스트리에 푸시 합니다.

    docker push <ImageName>
    

    예시:

    # Push the Docker image to the local registry
    
    docker push localhost:5000/filtermodule:0.0.1-amd64
    
    # Or push the Docker image to an Azure Container Registry. Replace myacr with your Azure Container Registry name.
    
    az acr login --name myacr
    docker push myacr.azurecr.io/filtermodule:0.0.1-amd64
    

배포 템플릿 업데이트

배포 템플릿 deployment.template.json 컨테이너 레지스트리 이미지 위치로 업데이트합니다. 예를 들어 Azure Container Registry myacr.azurecr.io 사용하고 이미지가 filtermodule:0.0.1-amd64인 경우 filtermodule 구성을 다음으로 업데이트합니다.

"filtermodule": {
    "version": "1.0",
    "type": "docker",
    "status": "running",
    "restartPolicy": "always",
    "settings": {
        "image": "myacr.azurecr.io/filtermodule:0.0.1-amd64",
        "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
    }
}

Visual Studio Code 탐색기에서 deployment.template.json 파일을 마우스 오른쪽 단추로 클릭하고 빌드 및 푸시 IoT Edge 솔루션을 선택합니다.

빌드 및 푸시 명령은 세 가지 작업을 시작합니다. 먼저 배포 템플릿 및 기타 솔루션 파일의 정보로 작성된 전체 배포 매니페스트를 포함하는 구성이라는 솔루션에 새 폴더를 만듭니다. 둘째, 대상 아키텍처에 적합한 dockerfile을 기반으로 컨테이너 이미지를 빌드하기 위해 실행됩니다 docker build . 그런 다음, 이미지 리포지토리를 컨테이너 레지스트리에 푸시하기 위해 실행됩니다 docker push .

이 프로세스는 처음 몇 분 정도 걸릴 수 있지만 다음에 명령을 실행할 때 더 빠릅니다.

선택 사항: 모듈 및 이미지 업데이트

모듈 코드를 변경하는 경우 모듈 이미지를 다시 빌드하고 컨테이너 레지스트리에 푸시해야 합니다. 이 섹션의 단계를 사용하여 빌드 및 컨테이너 이미지를 업데이트합니다. 모듈 코드를 변경하지 않은 경우 이 섹션을 건너뛸 수 있습니다.

새로 만든 구성 폴더에서 deployment.amd64.json 파일을 엽니다. 파일 이름은 대상 아키텍처를 반영하므로 다른 아키텍처를 선택한 경우 다릅니다.

자리 표시자가 있는 두 매개 변수에는 이제 적절한 값이 포함됩니다. registryCredentials 섹션에는 .env 파일에서 가져온 레지스트리 사용자 이름과 암호가 있습니다. filtermodule에는 module.json 파일의 이름, 버전 및 아키텍처 태그가 있는 전체 이미지 리포지토리가 있습니다.

  1. filtermodule 폴더에서 module.json 파일을 엽니다.

  2. 모듈 이미지의 버전 번호를 변경합니다. 예를 들어 패치 버전 번호를 "version": "0.0.2" 모듈 코드에서 약간 수정한 것처럼 증분합니다.

    모듈 버전을 통해 버전을 관리할 수 있으며, 프로덕션 환경에 업데이트를 밸포하기 전에 소규모 디바이스 세트에서 변경 내용을 테스트해볼 수 있습니다. 빌드 및 푸시하기 전에 모듈 버전을 증가하지 않는 경우 컨테이너 레지스트리의 리포지토리를 덮어쓰게 됩니다.

  3. 변경 내용을 module.json 파일에 저장합니다.

0.0.2 버전 태그를 사용하여 업데이트된 이미지를 빌드하고 푸시합니다. 예를 들어 로컬 레지스트리 또는 Azure 컨테이너 레지스트리에 대한 이미지를 빌드하고 푸시하려면 다음 명령을 사용합니다.


# Build the container image for Linux and amd64 architecture.

dotnet publish --os linux --arch x64

# For local registry:
# Tag the image with version 0.0.2, x64 architecture, and the local registry.

docker tag filtermodule localhost:5000/filtermodule:0.0.2-amd64

# For Azure Container Registry:
# Tag the image with version 0.0.2, x64 architecture, and your container registry information. Replace **myacr** with your own registry name.

docker tag filtermodule myacr.azurecr.io/filtermodule:0.0.2-amd64

deployment.template.json 파일을 다시 마우스 오른쪽 단추로 클릭하고 빌드 및 푸시 IoT Edge 솔루션을 다시 선택합니다.

deployment.amd64.json 파일을 다시 엽니다. 빌드를 실행하고 명령을 다시 푸시할 때 빌드 시스템에서 새 파일을 만들지 않습니다. 대신 변경 내용을 반영하도록 동일한 파일이 업데이트됩니다. 이제 filtermodule 이미지는 컨테이너의 0.0.2 버전을 가리킵니다.

빌드 및 푸시 명령이 어떤 작업을 했는지 자세히 확인하려면 Azure Portal이동하여 컨테이너 레지스트리로 이동합니다.

컨테이너 레지스트리에서 리포지토리를 선택한 다음 filtermodule을 선택합니다. 두 버전의 이미지가 레지스트리에 푸시되는지 확인합니다.

Screenshot of where to view both image versions in your container registry.

문제 해결

모듈 이미지를 빌드 및 푸시할 때 오류가 발생하는 경우 개발 머신의 Docker 구성과 관련이 있는 경우가 자주 있습니다. 다음 검사 사용하여 구성을 검토합니다.

  • 컨테이너 레지스트리에서 복사한 자격 증명을 사용하여 명령을 실행 docker login 했나요? 이러한 자격 증명은 Azure에 로그인하는 데 사용하는 자격 증명과 다릅니다.
  • 컨테이너 리포지토리가 올바른가요? 올바른 컨테이너 레지스트리 이름과 올바른 모듈 이름이 있나요? filtermodule 폴더에서 module.json 파일을 열어 검사. 리포지토리 값은 레지스트리 name.azurecr.io/filtermodule><아야 합니다.
  • 모듈에 filtermodule다른 이름을 사용한 경우 해당 이름이 솔루션 전체에서 일관적인가요?
  • 머신이 빌드하는 것과 동일한 유형의 컨테이너를 실행하고 있나요? 이 자습서는 Linux IoT Edge 디바이스용이므로 Visual Studio Code는 사이드바에서 amd64 또는 arm32v7을 말해야 하며 Docker Desktop은 Linux 컨테이너를 실행해야 합니다.

디바이스에 모듈 배포

컨테이너 레지스트리에 저장된 빌드된 컨테이너 이미지가 있는지 확인했기 때문에 디바이스에 배포해야 합니다. IoT Edge 디바이스가 작동되고 실행 중인지 확인합니다.

IoT Edge Azure CLI set-modules 명령을 사용하여 모듈을 Azure IoT Hub에 배포합니다. 예를 들어 deployment.template.json 파일에 정의된 모듈을 IoT Edge 디바이스 my-device용 IoT Hub my-iot-hub에 배포하려면 다음 명령을 사용합니다. 허브 이름, 디바이스 ID로그인 IoT Hub 연결 문자열 값을 사용자 고유의 값으로 바꿉니다.

az iot edge set-modules --hub-name my-iot-hub --device-id my-device --content ./deployment.template.json --login "HostName=my-iot-hub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=<SharedAccessKey>"

Azure Portal에서 공유 액세스 키를 포함하여 IoT Hub 연결 문자열 찾을 수 있습니다. IoT Hub >보안 설정>공유 액세스 정책>iothubowner로 이동합니다.

  1. Visual Studio Code 탐색기의 Azure IoT Hub 섹션에서 디바이스를 확장하여 IoT 디바이스 목록을 표시합니다.

  2. 배포할 IoT Edge 디바이스를 마우스 오른쪽 단추로 클릭한 다음 단일 디바이스에 대한 배포 만들기를 선택합니다.

  3. 파일 탐색기에서 구성 폴더로 이동한 다음, deployment.amd64.json 파일을 선택합니다.

    컨테이너 레지스트리 자격 증명 또는 모듈 이미지 값이 없는 deployment.template.json 파일을 사용하지 마세요. Linux ARM32 디바이스를 대상으로 하는 경우 배포 매니페스트의 이름이 deployment.arm32v7.json.

  4. 디바이스에서 모듈을 확장하여 배포되고 실행 중인 모듈 목록을 확인합니다. 새로 고침 단추를 선택합니다. 디바이스에서 실행되는 새 tempSensorfiltermodule 모듈이 표시됩니다.

    모듈을 시작하는 데 몇 분 정도 걸릴 수 있습니다. IoT Edge 런타임은 새 배포 매니페스트를 수신하고, 컨테이너 런타임에서 모듈 이미지를 풀다운한 다음, 각 새 모듈을 시작해야 합니다.

디바이스에서 메시지 보기

샘플 모듈 코드는 입력 큐를 통해 메시지를 수신하고 출력 큐를 통해 전달합니다. 배포 매니페스트는 tempSensor에서 filtermodule메시지를 전달한 다음 filtermodule에서 IoT Hub로 메시지를 전달하는 경로를 선언했습니다. Azure IoT Edge 및 Azure IoT Hub 확장을 사용하면 개별 디바이스에서 IoT Hub에 도착할 때 메시지를 볼 수 있습니다.

  1. Visual Studio Code 탐색기에서 모니터링할 IoT Edge 디바이스를 마우스 오른쪽 단추로 클릭한 다음 기본 제공 이벤트 엔드포인트 모니터링 시작을 선택합니다.

  2. Visual Studio Code의 출력 창을 시청하여 IoT Hub에 도착하는 메시지를 확인합니다.

    Screenshot showing where to view incoming device to cloud messages.

디바이스에서 변경 내용 보기

디바이스 자체에서 발생하는 작업을 확인하려면 이 섹션의 명령을 사용하여 디바이스에서 실행되는 IoT Edge 런타임 및 모듈을 검사합니다.

이 섹션의 명령은 개발 머신용이 아니라 IoT Edge 디바이스용입니다. IoT Edge 디바이스용으로 가상 머신을 사용하고 있는 경우 지금 연결합니다. Azure에서 가상 머신의 개요 페이지로 이동한 후 연결을 선택하여 보안 셸 연결에 액세스합니다.

  • 디바이스에 배포된 모든 모듈을 보고 해당 상태 검사.

    iotedge list
    

    두 개의 IoT Edge 런타임 모듈, tempSensorfiltermodule의 네 가지 모듈이 표시됩니다. 실행 중으로 나열된 네 가지가 모두 표시됩니다.

  • 특정 모듈에 대한 로그를 검사합니다.

    iotedge logs <module name>
    

    IoT Edge 모듈은 대/소문자를 구분합니다.

    tempSensorfiltermodule 로그는 처리 중인 메시지를 표시해야 합니다. edgeAgent 모듈은 다른 모듈을 시작하는 역할을 하므로 해당 로그에는 배포 매니페스트 구현에 대한 정보가 포함됩니다. 모듈이 목록에 없거나 실행되고 있지 않은 경우 edgeAgent 로그에 오류가 있을 수 있습니다. edgeHub 모듈은 모듈과 IoT Hub 간의 통신을 담당합니다. 모듈이 실행 중이지만 메시지가 IoT Hub에 도착하지 않는 경우 edgeHub 로그에 오류가 있을 수 있습니다.

리소스 정리

권장되는 다음 문서를 계속 진행하려는 경우 만든 리소스와 구성을 그대로 유지하고 다시 사용할 수 있습니다. 테스트 디바이스와 동일한 IoT Edge 디바이스를 계속 사용해도 됩니다.

그렇지 않으면 요금이 부과되지 않도록 이 문서에서 사용한 로컬 구성 및 Azure 리소스를 삭제할 수 있습니다.

Azure 리소스 삭제

Azure 리소스와 리소스 그룹을 삭제하면 되돌릴 수 없습니다. 잘못된 리소스 그룹 또는 리소스를 자동으로 삭제하지 않도록 해야 합니다. 유지하려는 리소스가 있는 기존 리소스 그룹 내에 IoT Hub를 만든 경우 리소스 그룹이 아닌 IoT Hub 리소스 자체만 삭제합니다.

리소스를 삭제하려면:

  1. Azure Portal에 로그인한 다음, 리소스 그룹을 선택합니다.

  2. IoT Edge 테스트 리소스가 포함된 리소스 그룹의 이름을 선택합니다.

  3. 리소스 그룹에 포함된 리소스 목록을 검토합니다. 모두 삭제하려면 리소스 그룹 삭제를 선택할 수 있습니다. 일부만 삭제하려면 각 리소스를 클릭하여 개별적으로 삭제할 수 있습니다.

다음 단계

이 자습서에서는 개발 머신에서 Visual Studio Code를 설정하고 IoT Edge 디바이스에서 생성된 원시 데이터를 필터링하는 코드를 포함하는 첫 번째 IoT Edge 모듈을 배포했습니다.

다음 자습서를 계속 진행하여 Azure IoT Edge가 Azure 클라우드 서비스를 배포하여 에지에서 데이터를 처리하고 분석하는 데 어떻게 도움이 되는지 알아볼 수 있습니다.