자습서: IoT Edge 모듈로 Azure Functions 배포

적용 대상:IoT Edge 1.5 확인 표시 IoT Edge 1.5 IoT Edge 1.4 확인 표시 IoT Edge 1.4

Important

IoT Edge 1.5 LTS 및 IoT Edge 1.4 LTS는 지원되는 릴리스입니다. IoT Edge 1.4 LTS는 2024년 11월 12일에 수명이 종료됩니다. 이전 릴리스에 있는 경우 IoT Edge 업데이트를 참조하세요.

비즈니스 논리를 직접 Azure IoT Edge 디바이스에 구현하는 코드를 배포하려면 Azure Functions를 사용할 수 있습니다. 이 자습서에서는 시뮬레이션된 IoT Edge 디바이스에서 센서 데이터를 필터링하는 Azure 함수를 만들고 배포하는 과정을 안내합니다. 빠른 시작에서 만든 시뮬레이션된 IoT Edge 디바이스를 사용합니다. 이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.

  • Visual Studio Code를 사용하여 Azure 함수를 만듭니다.
  • Visual Studio Code 및 Docker를 사용하여 Docker 이미지를 만들고 컨테이너 레지스트리를 게시합니다.
  • IoT Edge 디바이스에 컨테이너 레지스트리의 모듈을 배포합니다.
  • 필터링된 데이터를 봅니다.

함수 모듈을 스테이징하고 배포하는 방법을 보여 주는 함수 아키텍처 다이어그램.

이 자습서에서 만드는 Azure 함수는 디바이스에서 생성한 온도 데이터를 필터링합니다. 이 함수는 온도가 지정된 임계값을 초과하는 경우에만 Azure IoT Hub에 메시지 업스트림을 전송합니다.

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

필수 조건

이 자습서를 시작하기 전에 Visual Studio Code를 사용하여 Azure IoT Edge 모듈 개발 자습서에 따라 Linux 컨테이너 개발을 위한 개발 환경을 설정해야 합니다. 이 자습서를 완료하여 다음과 같은 필수 구성 요소를 갖추어야 합니다.

Azure Functions를 사용하여 IoT Edge 모듈을 개발하려면 다음과 같은 추가 필수 구성 요소를 개발 컴퓨터에 설치합니다.

함수 프로젝트 만들기

필수 조건에서 설치한 Visual Studio Code용 Azure IoT Tools는 관리 기능뿐만 아니라 일부 코드 템플릿도 제공합니다. 이 섹션에서는 Visual Studio Code를 사용하여 Azure 함수를 포함하는 IoT Edge 솔루션을 만듭니다.

새 프로젝트 만들기

다음 단계에 따라 사용자 지정할 수 있는 C# 함수 솔루션 템플릿을 만듭니다.

  1. 개발 머신에서 Visual Studio Code를 엽니다.

  2. 보기>명령 팔레트를 선택하여 Visual Studio Code 명령 팔레트를 엽니다.

  3. 명령 팔레트에서 Azure IoT Edge: 새 IoT Edge 솔루션 명령을 추가하고 실행합니다. 명령 팔레트의 프롬프트에 따라 솔루션을 만듭니다.

    • 폴더 선택: Visual Studio Code에 대한 개발 컴퓨터에서 위치를 선택하여 솔루션 파일을 만듭니다.
    • 솔루션 이름 제공: FunctionSolution과 같은 솔루션에 대한 설명이 포함된 이름을 추가하거나 기본값을 적용합니다.
    • 모듈 템플릿 선택: Azure Functions - C#을 선택합니다.
    • 모듈 이름 제공 | 모듈 이름을 CSharpFunction으로 지정합니다.
    • 모듈의 Docker 이미지 리포지토리를 제공합니다. 이미지 리포지토리는 컨테이너 레지스트리의 이름 및 컨테이너 이미지의 이름을 포함합니다. 컨테이너 이미지는 마지막 단계에서 미리 채워져 있습니다. localhost:5000을 Azure 컨테이너 레지스트리의 로그인 서버 값으로 바꿉니다. Azure Portal의 컨테이너 레지스트리 개요 페이지에서 로그인 서버를 검색할 수 있습니다. 마지막 문자열은 <레지스트리 이름>.azurecr.io/csharpfunction과 같습니다.

    Visual Studio Code에서 Docker 이미지 리포지토리 이름을 추가할 위치를 보여 주는 스크린샷.

레지스트리 자격 증명 추가

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

Visual Studio Code의 IoT Edge 확장은 Azure에서 컨테이너 레지스트리 자격 증명을 끌어온 후 환경 파일에 채우려고 합니다. 사용자 자격 증명이 이미 파일에 있는지 확인합니다. 그렇지 않은 경우 다음과 같이 지금 추가합니다.

  1. Visual Studio Code 탐색기에서 .env 파일을 엽니다.
  2. 필드를 Azure 컨테이너 레지스트리에서 복사한 사용자 이름암호 값으로 업데이트합니다. Azure의 컨테이너 레지스트리로 이동하여 설정>액세스 키 페이지를 확인하여 다시 찾을 수 있습니다.
  3. 이 파일을 저장합니다.

참고 항목

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

대상 아키텍처를 AMD64로 설정

IoT Edge의 Azure Functions 모듈 실행은 Linux AMD64 기반 컨테이너에서만 지원됩니다. Visual Studio Code 기본 대상 아키텍처는 Linux AMD64이지만 여기서는 Linux AMD64로 명시적으로 설정합니다.

  1. 명령 팔레트를 열고 Azure IoT Edge: Edge 솔루션용 기본 대상 플랫폼 설정을 검색합니다.

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

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

IoT Hub에 전달하기 전에 CSharpFunction 모듈이 에지에서 메시지를 처리하도록 몇 가지 추가 코드를 추가해보겠습니다.

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

  2. CSharpFunction.cs 파일 내용을 다음 코드로 바꿉니다. 이 코드는 주위 온도 및 기계 온도에 대한 원격 분석을 수신한 후, 기계 온도가 정의된 임계값을 초과하는 경우 IoT Hub에 메시지를 전달합니다.

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.Azure.Devices.Client;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.EdgeHub;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    
    namespace Functions.Samples
    {
        public static class CSharpFunction
        {
            [FunctionName("CSharpFunction")]
            public static async Task FilterMessageAndSendMessage(
                [EdgeHubTrigger("input1")] Message messageReceived,
                [EdgeHub(OutputName = "output1")] IAsyncCollector<Message> output,
                ILogger logger)
            {
                const int temperatureThreshold = 20;
                byte[] messageBytes = messageReceived.GetBytes();
                var messageString = System.Text.Encoding.UTF8.GetString(messageBytes);
    
                if (!string.IsNullOrEmpty(messageString))
                {
                    logger.LogInformation("Info: Received one non-empty message");
                    // Get the body of the message and deserialize it.
                    var messageBody = JsonConvert.DeserializeObject<MessageBody>(messageString);
    
                    if (messageBody != null && messageBody.machine.temperature > temperatureThreshold)
                    {
                        // Send the message to the output as the temperature value is greater than the threshold.
                        using (var filteredMessage = new Message(messageBytes))
                        {
                             // Copy the properties of the original message into the new Message object.
                             foreach (KeyValuePair<string, string> prop in messageReceived.Properties)
                             {filteredMessage.Properties.Add(prop.Key, prop.Value);}
                             // Add a new property to the message to indicate it is an alert.
                             filteredMessage.Properties.Add("MessageType", "Alert");
                             // Send the message.
                             await output.AddAsync(filteredMessage);
                             logger.LogInformation("Info: Received and transferred a message with temperature above the threshold");
                        }
                    }
                }
            }
        }
        //Define the expected schema for the body of incoming messages.
        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;}
        }
    }
    
  3. 파일을 저장합니다.

IoT Edge 솔루션 빌드 및 푸시

이전 섹션에서는 IoT Edge 솔루션을 만들고 CSharpFunction을 수정하여 보고된 머신 온도가 허용 가능한 임계값 미만인 메시지를 필터링했습니다. 이제 솔루션을 컨테이너 이미지로 빌드하고 컨테이너 레지스트리로 푸시해야 합니다.

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

  2. 터미널에 다음 명령을 입력하여 Docker에 로그인합니다. Azure Container Registry의 사용자 이름, 암호 및 로그인 서버로 로그인합니다. Azure Portal에서 레지스트리의 액세스 키 섹션에서 이러한 값을 검색할 수 있습니다.

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

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

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

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

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

컨테이너 이미지 보기

컨테이너 이미지가 컨테이너 레지스트리에 푸시될 때 Visual Studio Code는 성공 메시지를 출력합니다. 직접 성공적인 작업을 확인하려면 레지스트리에서 이미지를 볼 수 있습니다.

  1. Azure Portal에서 Azure 컨테이너 레지스트리를 찾습니다.
  2. 서비스>리포지토리를 선택합니다.
  3. 목록에 csharpfunction 리포지토리가 표시됩니다. 자세한 내용을 보려면 이 리포지토리를 선택합니다.
  4. 태그 섹션에 0.0.1-amd64 태그가 표시됩니다. 이 태그는 빌드하는 이미지의 버전 및 플랫폼을 나타냅니다. 이러한 값은 CSharpFunction 폴더의 module.json 파일에서 설정됩니다.

솔루션 배포 및 실행

Azure Portal을 사용하여 빠른 시작에서 수행한 것처럼 IoT Edge 디바이스에 함수 모듈을 배포할 수 있습니다. 또한 Visual Studio Code 내에서 모듈을 배포하고 모니터링할 수 있습니다. 다음 섹션에서는 필수 조건에 나열된 Visual Studio Code용 Azure IoT Edge 및 IoT Hub를 사용합니다. 아직 설치하지 않은 경우 확장을 설치합니다.

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

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

  3. CSharpFunction이 포함된 솔루션 폴더를 찾습니다. config 폴더를 열고 deployment.amd64.json 파일을 선택한 다음, Edge 배포 매니페스트 선택을 클릭합니다.

  4. 배포되어 실행 중인 모듈의 목록을 보려면 디바이스 아래에서 모듈을 확장합니다. 새로고침 단추를 클릭합니다. SimulatedTemperatureSensor 모듈과 $edgeAgent$edgeHub와 함께 실행되는 새 CSharpFunction이 표시됩니다.

    모듈을 시작하는 데 몇 분 정도 걸릴 수 있습니다. IoT Edge 디바이스는 IoT Hub에서 해당 새 배포 정보를 검색하고, 새 컨테이너를 시작하고, 상태를 IoT Hub에 다시 보고해야 합니다.

    Visual Studio Code에 배포된 모듈을 보는 방법을 보여 주는 스크린샷.

생성된 데이터 보기

명령 팔레트에서 Azure IoT Hub: 기본 제공 이벤트 엔드포인트 모니터링 시작을 실행하여 IoT 허브에 도달한 모든 메시지를 볼 수 있습니다. 메시지 모니터링을 중지하려면 명령 팔레트에서 Azure IoT Hub: 기본 제공 이벤트 엔드포인트 모니터링 중지 명령을 실행합니다.

특정 디바이스에서 IoT Hub에 도달한 모든 메시지를 보려면 보기를 필터링할 수도 있습니다. Visual Studio Code 탐색기의 Azure IoT Hub>디바이스 섹션에서 디바이스를 마우스 오른쪽 단추로 클릭하고 기본 제공 이벤트 엔드포인트 모니터링 시작을 선택합니다.

리소스 정리

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

그렇지 않은 경우 요금 청구를 방지하도록 이 문서에서 만든 로컬 구성 및 Azure 리소스를 삭제할 수 있습니다.

Azure 리소스 삭제

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

리소스를 삭제하려면:

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

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

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

다음 단계

이 자습서에서는 IoT Edge 디바이스에서 생성한 원시 데이터를 필터링하는 코드가 포함된 Azure 함수 모듈을 만들었습니다.

Azure IoT Edge에서 데이터를 통해 비즈니스 통찰력을 얻는 데 도움이 되는 다른 방법을 알아보려면 다음 자습서를 진행합니다.