Visual Studio로 Azure Function 개발하기

Azure Function은 Azure App Service에 포함된 기능 중 하나인 Azure Web Job을 별도의 상품으로 분리하여 출시하였습니다. 하지만 아쉽게도 Visual Studio의 풍부한 IDE 지원을 아직까지도 직접 받을 수 있는 상태는 아닙니다. 또한 Microsoft Docs 등에 공개된 방법도 간접적으로 Azure Function의 설정을 이용한다거나, Node용 CLI를 활용하는 정도에서 언급되는 것이 전부입니다.

소개하려는 내용은 Visual Studio의 콘솔 프로젝트와 Azure Storage Emulator를 이용하여 C# Azure Function을 C# Script가 아닌 통상적인 C# Compiler 기반 프로젝트로 개발과 테스트를 진행하고, 이것을 C# Azure Function으로 마이그레이션하는 방법에 관한 것입니다. 만약 LINQPAD Premium Version을 구입하여 사용 중이라면, 같은 작업을 LINQPAD에서도 실행할 수 있으니 더 적극적으로 Azure Function을 개발하실 수 있을 것입니다.

시작하기

Azure Web Job 기반이기 때문에, 기존에 .NET용으로 출시한 Web Job SDK와 각종 Extension을 Azure Function 사이에는 어느 정도 호환성이 있습니다. 다시 말해서 C# 스크립트로 무언가 새로운 코드를 작성한다기 보다, 기존의 SDK를 C# 스크립트에서 사용할 수 있도록 포장한 것이 Azure Function의 본질에 가깝습니다. 아쉽게도 완전히 같은 코드 베이스는 아니지만, 호환성이 있기 때문에 취할 수 있는 이점이 있고, 그 부분을 활용하는 것입니다.

시작을 위하여 다음의 소프트웨어 스택이 설치되어있는지 점검합니다.

  • Azure Storage Emulator (Azure Cloud Service SDK에 포함되어있습니다.)
  • Visual Studio 2015 Community Edition 이상의 IDE
  • .NET Framework 4.6 이상

만약 Windows 개발 환경이 아닌 경우 Azure Storage Emulator는 제공되지 않기 때문에 어쩔 수 없이 실제 Azure Storage 계정을 만들어 연결해야 합니다. IDE의 경우 Visual Studio Code, Visual Studio for Mac, Rider를 대신 활용할 수 있습니다. 그리고 Mono를 설치하여 개발을 진행할 수 있습니다. 아쉽게도 .NET Core는 2017년 4월 현재 지원되지 않습니다.

선호하는 IDE로 콘솔 프로젝트를 만든 다음, 다음의 NuGet 패키지들을 설치합니다.

  • Microsoft.Azure.WebJobs (2.0.0 이상)
  • Microsoft.Azure.WebJobs.Extensions (2.0.0 이상)

그 다음 Main 메서드를 다음과 같이 코딩합니다.

var jobHostConfig = new JobHostConfiguration("UseDevelopmentStorage=true");
jobHostConfig.UseCore();
jobHostConfig.UseFiles();
jobHostConfig.UseTimers();
jobHostConfig.UseDevelopmentSettings();

using (var cts = new CancellationTokenSource())
using (var jobHost = new JobHost(jobHostConfig))
{
    jobHost.StartAsync(cts.Token);
    Console.WriteLine("Press Ctrl + C to stop the service.");
    Console.CancelKeyPress += (s, e) => cts.Cancel();
    cts.Token.WaitHandle.WaitOne(Timeout.Infinite);
}

Local Azure Storage Emulator를 사용할 수 있는 Windows 환경에서만 UseDevelopmentStorage=true 연결 문자열을 지정하고, 그 외 환경에서는 실제 Azure Storage Account의 연결 문자열을 해당 속성 블레이드에서 찾아 대입해야 합니다.

그리고 Azure Function에 호스팅하려는 함수를 다음과 같이 코딩합니다.

public static void Run(
    [TimerTrigger("* * * * * *", UseMonitor = true)]
    TimerInfo myTimer,
    TraceWriter log)
{
    log.Info($"C# Timer trigger function executed at: {DateTime.Now}");
}

TimerTrigger가 TimerInfo 메서드 인자에 지정되는 것에 유의하여 위와 같이 코딩합니다. TimerTrigger에 지정되는 첫 인자는 타이머의 실행 간격을 나타냅니다. Crontab에 사용되는 반복 간격 표시 문법을 참조하여 값을 지정하도록 구성하는 것이 Azure Function으로 마이그레이션 할 때 편리하므로 해당 문법을 익히는 것을 권장합니다.

그리고 실행이 잘 되는지 확인하기 위하여, Azure Storage Emulator를 시작하고, F5 키를 눌러 샘플 프로그램을 실행합니다. 다음과 비슷하게 출력되면 정상적으로 실행되는 것입니다.

Press Ctrl + C to stop the service.
Development settings applied
Found the following functions:
TimerSample.Run
Singleton lock acquired (1ce1ebaf1e584866b90488a9e1b5d19f/TimerSample.Run.Listener)
The next 5 occurrences of the schedule will be:
2017-04-24 오전 12:16:59
2017-04-24 오전 12:17:00
2017-04-24 오전 12:17:01
2017-04-24 오전 12:17:02
2017-04-24 오전 12:17:03
Job host started
Executing 'TimerSample.Run' (Reason='Timer fired at 2017-04-24T00:16:59.0273081+09:00', Id=aa02dc0a-5a89-4ebd-bf08-8182cce53a0c)
C# Timer trigger function executed at: 2017-04-24 오전 12:16:59
Executed 'TimerSample.Run' (Succeeded, Id=aa02dc0a-5a89-4ebd-bf08-8182cce53a0c)
Executing 'TimerSample.Run' (Reason='Timer fired at 2017-04-24T00:17:00.0061625+09:00', Id=f8161e5d-c989-4d2d-9a49-cb5d9d269134)
C# Timer trigger function executed at: 2017-04-24 오전 12:17:00
Executed 'TimerSample.Run' (Succeeded, Id=f8161e5d-c989-4d2d-9a49-cb5d9d269134)
...

마이그레이션

이렇게 만들어진 Azure Function이 정말 잘 수행되는지 점검할 때 활용할 수 있는 유용한 서비스가 하나 있습니다. Try Azure App Service를 이용하면 실제 Microsoft Azure 구독과 무관하게, Microsoft 계정 이외에도 Google (GMAIL), Facebook, Github 계정으로 로그인하여 1시간짜리 테스트 Azure Function 계정을 발급받을 수 있습니다.

https://azure.microsoft.com/ko-kr/try/app-service/ 에 방문하여 새로운 계정을 하나 생성합니다.

그 다음, 위의 Run 메서드의 코드를 복사합니다. 단, 몇 가지 복사 전에 수정하거나 확인해야 할 부분이 있습니다.

  • 개발 중에 참조한 NuGet 패키지의 참조를 지정해야 합니다. project.json 파일은 기본적으로 만들어지지 않으므로 다음과 같은 뼈대를 만들고, 현재 개발한 프로젝트 내의 package.config 파일의 내용을 여기로 복사해서 넣어야 합니다. 종속 관계에 따라 자동으로 설치되는 패키지들은 제외하고, 실제로 추가했던 패키지만 지정해서 넣으면 됩니다.
{
  "frameworks": {
    "net46":{
      "dependencies": {
        "Microsoft.ProjectOxford.Face": "1.1.0"
      }
    }
   }
}
  • NuGet 패키지가 아닌 BCL 내 어셈블리 또는 개별 .NET DLL 파일을 참조했을 경우에는 C# 스크립트만의 고유 문법인 #r 지시자를 사용하여 참조를 지정합니다.
    • GAC에 설치했거나 별도로 수동 참조한 .NET DLL 파일은 bin 폴더로 직접 업로드해야 합니다.
    • x86용으로 명시하여 빌드한 DLL이거나, 설치 준비 및 사용 과정에서 시스템 레지스트리 변경 등의 작업이 필요한 경우에는 사용할 수 없습니다.
  • 함수를 옮겨 담기 전에는 메서드 이름과 시그니처가 처음 Azure Function을 만들었을 때와 동일한지 점검합니다. 만약 정상적으로 실행되지 않는다면 function.json 파일의 내용을 참고합니다.
{
  "disabled": false,
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */5 * * * *"
    }
  ]
}
  • 마지막으로 앞에서 TimerTrigger나 BlobTrigger, 혹은 ServiceBusTrigger와 같이 트리거에 지정한 인자의 값을 확인하여 function.json 파일을 수정하도록 합니다. 위의 예제의 경우 매 초 마다 실행되도록 하였으므로, function.json의 schedule 프로퍼티를 “* * * * * *”으로 바꾸어야 합니다.

마무리

이렇게 해서 만들어진 최종 버전의 CSX 파일을 실제 Azure Function 서비스로 배포하는 것은 자유롭게 할 수 있습니다. 연속성 있는 개발을 위해서, 버전 관리 저장소를 통하여 배포하도록 설정해두면 더욱 편리할 것입니다.

이 글을 작성하면서 좀 더 고민해볼 만한 주제가 있다면, 아래와 같은 부분들이 있을 것 같습니다.

  • HTTP Trigger, Web Hook Trigger는 Web Job과 사실 직접적인 상관이 없으며, ASP.NET Web API의 서브셋에 가깝습니다. 다만 TraceWriter 클래스를 사용하는 부분만이 온전히 Web Job에 관련이 있는 부분입니다. 이 부분을 감안하여 DummyTraceWriter 클래스를 만들어 단위 테스트를 하도록 할 수 있을 듯 합니다.
class DummyTraceWriter : TraceWriter
{
    public DummyTraceWriter() : base(default(TraceLevel)) { }
    public override void Trace(TraceEvent traceEvent) => Console.WriteLine(traceEvent);
}
  • LINQPAD용 스크립트 템플릿을 만들어 공유한다면 정식 SDK가 출시되기 전에 더 많이 Azure Function을 개발하고 테스트할 수 있을 것이라고 생각합니다.
  • 일부 네이티브 코드를 포함하는 NuGet 패키지는 아마도 64비트용으로 빌드된 패키지를 사용하는 것이 실행에 문제가 없을 것으로 예상합니다. 32비트 버전의 패키지도 별도 EXE 파일로 실행하는 경우에는 Windows-on-Windows 호환성 기능으로 실행은 보장될 수 있을 것입니다.

더 세부적인 사항, 보충할 부분, 혹은 수정해야 할 부분에 대한 의견을 주시면 큰 도움이 될 것 같습니다.

[ClouDeveloper News – Azure Edition] 2016년 12월 15일

클라우드 컴퓨팅을 중심으로 관련된 여러 기술과 업계 소식을 매주 전하는 ClouDeveloper News를 시작합니다. 파일럿 프로그램으로 구상하여 운영 중에 있으며 추후 여러 피드백과 의견 수렴을 통하여 프로그램의 틀을 갖추어 나갈 예정이오니 많은 관심과 구독을 부탁드립니다.

이번주 커뮤니티 소식

Azure 서비스 공지 사항

  • General availability: Package Management extension for Visual Studio Team Services
    • Visual Studio Team Service에서 NuGet Package와 NPM Package를 관리할 수 있는 익스텐션 서비스가 새로 출시되었습니다. Visual Studio Marketplace에서 청약할 수 있는 상품입니다.
  • General availability: Azure IoT Gateway SDK
    • 기존 하드웨어나 인프라를 교체하지 않고, 게이트웨이 장치를 개발하여 Azure IoT와 자연스럽게 연동될 수 있도록 만들 수 있습니다. 오픈 소스로 공개된 Azure IoT Gateway SDK를 사용하여 기존 장치가 Azure IoT Hub와 직접 통신할 수 있는 여건이 되지 않더라도 원격에서 장치를 제어하거나 상태를 보고하는 대행 게이트웨이 하드웨어를 더 쉽게 개발할 수 있습니다.
  • With general availability, enhancements abound in Azure IoT Hub Device Management
    • Azure IoT Hub에서 그동안 강조되지 않았거나 샘플 코드 수준으로만 제공되어오던 “장치 관리”에 관련된 기능과 API가 GA로 전환되었습니다. 예약 작업, 다이렉트 메서드, 쿼리, 디바이스 트윈 API를 사용하여 좀 더 많은 장치 제어 시나리오를 커버할 수 있게 되었습니다.
  • Latest update of Azure Analysis Services preview brings scale up and down
    • Azure Analysis Service의 인스턴스 크기를 조정할 수 있는 기능이 포털에서 새롭게 제공됩니다. 상황에 따라 강력한 성능 발휘를 위하여 인스턴스 등급이나 규모를 늘리고, 사용하지 않는 때에는 최소한으로 낮추어 경제적으로 Azure Analysis Service를 활용할 수 있게 됩니다.

교육 자료

새로운 제품 및 서비스

  • Introducing Windows Server & SQL Server Premium Assurance
    • 지원이 중단될 예정인 Windows Server와 SQL Server에 대한 보안 업데이트 제공 서비스가 유상으로 제공됨에 따라 기존 라이프사이클에서 최대 6년까지 지원이 연장됩니다. 신규 플랫폼과 서비스로 이행을 하기에 시간적 여유가 없는 경우 선택할 수 있는 옵션입니다. Windows Server 2008, Windows Server 2008 R2, SQL Server 2008, SQL Server 2008 R2가 첫 지원 대상입니다.
  • Announcing SQL Server Management Studio – 16.5.1 Release
    • SQL Server Management Studio의 최신 버전인 16.5.1이 릴리스되었습니다. 제품 출시 후 발견된 문제점들을 수정한 패치 성격의 업데이트 버전입니다.

활용 및 노하우

웹 캐스트

  • SQL Server + Java: What’s new
    • 새 Microsoft JDBC 드라이버를 통해 Java 기반 애플리케이션에서 SQL Server에 접속하여 쓸 수 있는 새로운 기능들을 소개하는 웹 캐스트입니다. 최근 JDBC 드라이버의 소스 코드를 GitHub 리포지터리에 게시하여 오픈소스화 하였으며, Maven 리포지터리를 통하여 JDBC 드라이버에 대한 종속성을 간편하게 추가할 수 있게 되었습니다.
  • Azure Media Indexer 2: Japanese support, punctuation improvements, no more time limit
    • 동영상에서 화자가 말하는 언어를 음성 인식하여 자막을 만들고 동영상 검색의 기본 데이터를 형성하는데 도움을 주는 Azure Media Indexer의 새 버전에서는 Microsoft Research의 연구 성과를 바탕으로 지속적으로 품질과 성능을 개선하고 있으며, 이번 릴리스에서는 일본어 음성 인식 지원, 10분 길이 제한 해제, 발음과 문법 품질 향상을 주안점으로 두고 있습니다.
  • Get Started with Azure Functions
    • Azure Function에 대한 튜토리얼 웹 캐스트입니다.
  • Digital marketing solutions on Azure
    • Orchard, Umbraco와 같은 유명 CMS 솔루션을 Azure 위에서 기술적인 지식 없이 손쉽게 구축하여 디지털 마케팅 전략에 활용할 수 있는 방안을 소개하는 웨비나 세션을 소개합니다.
  • Dev and test better in the cloud
    • Azure 및 클라우드 환경에서 개발과 테스트 전략을 더 효율적으로 수행할 수 있는 방법을 소개하는 무료 웹 캐스트입니다.

서드파티 소식

  • Kafka Connect for Azure IoT Hub
    • Azure IoT Hub에 연결하여 데이터를 Kafka로 보낼 수 있는 Connector의 오픈 소스 버전이 새롭게 공개되었습니다.

ClouDeveloper 페이스북 페이지에 댓글로 의견을 남겨주시면 뉴스 발행 및 각종 정보 전달에 반영하도록 하겠습니다. 고맙습니다.

의견 남기기: https://fb.com/cloudeveloper