Microsoft MVP성태의 닷넷 이야기
.NET Framework: 1998. Azure Functions를 사용한 간단한 실습 [링크 복사], [링크+제목 복사],
조회: 14532
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

(시리즈 글이 5개 있습니다.)
기타: 46. Microsoft의 응용 프로그램을 클라우드로 제공하는 서비스 - Azure RemoteApp 소개
; https://www.sysnet.pe.kr/2/0/1672

Java: 22. Azure - 자바(Java)로 만드는 Web App Service - Java SE (Embedded Web Server) 호스팅
; https://www.sysnet.pe.kr/2/0/12686

Java: 23. Azure - 자바(Java)로 만드는 Web App Service - Tomcat 호스팅
; https://www.sysnet.pe.kr/2/0/12690

.NET Framework: 1998. Azure Functions를 사용한 간단한 실습
; https://www.sysnet.pe.kr/2/0/13037

개발 환경 구성: 736. 파이썬 웹 앱을 Azure App Service에 배포하기
; https://www.sysnet.pe.kr/2/0/13830




Azure Functions를 사용한 간단한 실습

오늘은 부담없이, ^^ 간단하게 Azure Function을 실습해 볼까요?

사실 Visual Studio 환경에서는 매우 쉽게 테스트해 볼 수 있습니다. 우선, 프로젝트 자체를 "Azure Functions"로 시작해,

azure_func_1.png

중간에 선택하는 응용 프로그램 유형에서 (이번 실습은 웹 요청에 반응할 것이므로) "Http trigger"를 선택하면,

azure_func_2.png

기본적으로 다음과 같은 코드를 포함하는 프로젝트가 열립니다.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            string responseMessage = string.IsNullOrEmpty(name)
                ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
                : $"Hello, {name}. This HTTP triggered function executed successfully.";

            return new OkObjectResult(responseMessage);
        }
    }
}

제가 원하는 기능은 클라이언트의 공용 IP를 출력하는 것이므로 Function1을 다음과 같이 수정하면 됩니다.

[FunctionName("Function1")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    string userHostAddress = req.HttpContext.Connection.RemoteIpAddress.ToString(); 
    string ip = req.Headers["HTTP_X_FORWARDED_FOR"];

    if (string.IsNullOrEmpty(ip) == false)
    {
        userHostAddress = ip;
    }

    return new OkObjectResult(userHostAddress);
}

이렇게 바꾸고 곧바로 F5 키를 눌러 디버깅을 실행하면 Local PC에서 Emulator가 구동되면서 다음과 같은 출력의 콘솔 창이 뜹니다.

Azure Functions Core Tools
Core Tools Version:       4.0.4483 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.1.3.17473

[2022-04-18T04:33:25.113Z] Found C:\temp\FunctionApp1\FunctionApp1\FunctionApp1.csproj. Using for user secrets file configuration.

Functions:

        Function1: [GET,POST] http://localhost:7071/api/Function1

For detailed output, run func with --verbose flag.

따라서 웹 브라우저를 이용해 "http://localhost:7071/api/Function1" URL로 요청을 보내면, 콘솔에는 다음과 같은 식의 디버깅 로그가 찍히고,

[2022-04-18T04:54:04.785Z] Executing 'Function1' (Reason='This function was programmatically called via the host APIs.', Id=f13d0c90-2f8e-4424-ad94-eeca81759aa3)
[2022-04-18T04:54:06.632Z] C# HTTP trigger function processed a request.
[2022-04-18T04:54:06.646Z] Executed 'Function1' (Succeeded, Id=f13d0c90-2f8e-4424-ad94-eeca81759aa3, Duration=1871ms

화면에는 (로컬에서 테스트했으므로) "127.0.0.1"이 찍히는 것을 확인할 수 있습니다.




이렇게 로컬에서도 실행 및 테스트를 할 수 있으므로 개발이 어렵지 않습니다. 이후, Azure로의 배포는 솔루션 탐색기의 프로젝트 노드를 우 클릭해 나오는 "Publish" 메뉴를 선택, Azure에서 준비한 다양한 환경을 대상으로 배포할 수 있습니다.

azure_func_3.png

Azure 측에 미리 Function App 서비스를 하나 만들어 두거나, 위의 배포 창에서 제공하는 기능을 이용해 즉석에서 만들어도 됩니다.

Azure Function App 서비스는 겉으로는 별도의 서비스인 듯하지만, 내부적으로는 결국 Azure Web App Services와 다를 바가 없습니다. 실제로 호스팅되는 기본 URL도 사용자가 지정한 이름 외에 "azurewebsites.net"가 붙기도 합니다. 그러니까 전체적인 서비스 형태는 기존의 App Services를 Function App 유형으로 확장한 것에 불과합니다.

배포 후 사용법을 볼까요?

가령 사용자의 Function App URL이 다음과 같이 정해진 경우라면,

https://publicipfuncapp.azurewebsites.net/

이 글의 예제에서 작성한 코드는 다음과 같은 경로로 호출할 수 있습니다.

https://publicipfuncapp.azurewebsites.net/api/Function1

그런데, 실제로 저렇게 호출하면 "HTTP ERROR 401" 오류가 발생합니다.

This page isn’t working right now
If the problem continues, contact the site owner.
HTTP ERROR 401

왜냐하면, 해당 Function1에 대해 소스 코드에서 보면 AuthorizationLevel이 Function으로 되어 있기 때문입니다.

[FunctionName("Function1")]
public static async Task&lt;IActionResult&gt; Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
    ILogger log)

저 값을 "AuthorizationLevel.Anonymous"로 바꾸고 다시 시도하면 이제는 정상적으로 Function1 코드가 수행되는 것을 확인할 수 있습니다.

반면, AuthorizationLevelFunction이 Function으로 지정돼 있다면 이를 호출하기 위해 (일반적인 REST API 서비스 측에서 요구하는 App Key처럼) 미리 정해진 Key 값을 함께 명시를 해야 합니다. 이 Key 값은 Azure Portal에서 Function App 화면을 통해 "Get Function Url"로 알아낼 수 있습니다.

azure_func_4.png

저 위의 모든 키 값은 Function App 서비스가 생성되는 시점에 함께 만들어지지만, 원한다면 언제든 새롭게 키를 바꿀 수 있습니다. 위의 목록을 보면 3가지 유형의 키가 나오는데,

  1. default (function key)
  2. default (host key)
  3. masterKey (host key)

function key는 해당 Function마다 달라지는 key입니다. 그래서 또 다른 Function을 하나 더 추가하면 그 Function은 그것에 고유하게 생성되는 Function Key를 또 알아내서 호출을 해야 합니다.

반면, host key는 모든 Function을 호출할 수 있는 기능을 합니다. 따라서, Function1과 Funciton2를 만들었고 host key가 "6vkrc/7BLZVHc2AXkeG"라면, 다음과 같은 식으로 2개의 Function 모두를 호출할 수 있습니다.

https://publicipfuncapp.azurewebsites.net/api/Function1?code=6vkrc/7BLZVHc2AXkeG
https://publicipfuncapp.azurewebsites.net/api/Function2?code=6vkrc/7BLZVHc2AXkeG

또한 같은 host key이면서, default와 masterKey로 나뉘는데 masterKey는 일종의 관리자 권한을 더한다고 보시면 됩니다.

Master Key
; https://learn.microsoft.com/en-us/azure/azure-functions/security-concepts?tabs=v4#master-key-admin-level

일례로, AuthorizationLevel을 Admin으로 주면,

[HttpTrigger(AuthorizationLevel.Admin, "get", "post", Route = null)] HttpRequest req, ILogger log)

이 Function은 오직 masterKey로만 호출할 수 있고, 일반적인 다른 host key로는 호출할 수 없습니다.

참고로, host key는 Azure Portal의 "Function App" 서비스 화면에서 제어할 수 있고, function key는 개별 Function 화면에서 제어할 수 있습니다.




비주얼 스튜디오 환경 내에서, 로컬로 실행하는 Function App의 응용 프로그램은 다음의 위치에서 실행되는 func.exe가 대체합니다.

%USERPROFILE%\AppData\Local\AzureFunctionsTools\Releases\4.13.0\cli_x64

그리고 iisexpress.exe처럼, 이것 역시 비주얼 스튜디오가 아닌 그냥 단순하게 다음과 같은 식의 명령어를 이용해 실행하는 것도 가능합니다.

// Function App 프로젝트가 빌드된 경로로 이동하고,

c:\temp> cd c:\temp\FunctionApp1\FunctionApp1\bin\Debug\net6.0\

// 그 경로를 Current Directory로 해서 func.exe를 수행

c:\temp\FunctionApp1\FunctionApp1\bin\Debug\net6.0> "%USERPROFILE%\AppData\Local\AzureFunctionsTools\Releases\4.13.0\cli_x64\func.exe" host start --port 7071 --pause-on-error




대충 어떤 식인지 이 정도면 쉽게 파악이 되셨을 것입니다.

참고로, Azure Functions는 무료 범위가 있다는 점! ^^

// https://azure.microsoft.com/ko-kr/pricing/details/functions/

Azure Functions 사용량 과금제는 초당 리소스 사용량과 실행 횟수에 따라 비용이 청구됩니다. 사용량 플랜 가격에는 종량제 가격 체제로 구독 내의 모든 함수 앱에 대해 구독별로 매월 1백만 건의 요청 및 매월 400,000GB의 리소스 사용이 무료로 부여됩니다.





(2024-04-04: 업데이트)

.NET Conf 2023 (Day 1) - Leveraging the power of the .NET platform in Azure Functions
; https://youtu.be/vU-iZcxbDUk?t=14791

azure_func_net8_1.png




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 4/4/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 151  152  153  154  155  156  157  158  159  160  161  [162]  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
999정성태2/28/201146553개발 환경 구성: 108. RemoteFX - Windows 7 가상 머신에서 DirectX 9c 환경을 제공 [5]
998정성태2/27/201120255Team Foundation Server: 42. TFS Application-Tier만 재설치
996정성태2/12/201137705디버깅 기술: 35. windbg - 분석 예: 시작하자마자 비정상 종료하는 프로세스 - NullReferenceException
995정성태2/11/201156251.NET Framework: 205. 코드(C#)를 통한 풀 덤프 만드는 방법 [4]
994정성태2/10/201136159디버깅 기술: 34. Windbg - ERROR: Unable to load DLL mscordacwks_x86_x86_2.0.50727.4200.dll, Win32 error 0n2 [1]
993정성태2/10/201128517개발 환경 구성: 107. 하나의 WPF 프로젝트를 WinExe / Library로 빌드하는 방법
992정성태10/15/201129359개발 환경 구성: 106. VSS(Volume Shadow Service)를 이용한 Hyper-V VM 백업/복원 [2]
991정성태2/6/201148815개발 환경 구성: 105. 풀 덤프 파일을 남기는 방법 [4]
990정성태2/2/201133999개발 환경 구성: 104. Visual C++ Custom Build Tool 사용예 [1]파일 다운로드1
989정성태2/1/201130503개발 환경 구성: 103. DOS batch - 동기 방식으로 원격 서비스 제어
988정성태1/30/201126666개발 환경 구성: 102. MSBuild - DefineConstants에 다중 전처리 값 설정
987정성태1/29/201139854디버깅 기술: 33. PDB Symbol 로드 오류 - Cannot find or open the PDB file. [2]
986정성태1/26/201131259.NET Framework: 204. 분리된 ThreadPool 사용 - Smart Thread Pool
985정성태1/25/201127939디버깅 기술: 32. 인증서로 서명된 닷넷 어셈블리의 실행 지연 현상
984정성태1/25/201122632개발 환경 구성: 101. SharePoint 2010 - Form Design
983정성태1/23/201127666제니퍼 .NET: 15. 눈으로 확인하는 maxWorkerThreads, minFreeThreads 설정값 [1]
982정성태1/22/201124953개발 환경 구성: 100. SharePoint 2010 - iPad 친화적인 게시판 만들기 (사용자 지정 목록) [1]
981정성태1/19/201120874개발 환경 구성: 99. SharePoint 2010 - 웹 애플리케이션 생성 시 고려해야 할 점. [1]
980정성태1/19/201132271개발 환경 구성: 98. SharePoint 2010 - Office Web Apps 설치
979정성태1/18/201124995개발 환경 구성: 97. SharePoint 2010 팀 사이트 구성
978정성태1/16/201131952.NET Framework: 203. VPN 자동 연결 및 Router 설정 추가
977정성태1/12/201131299개발 환경 구성: 96. SharePoint 2010 설치 [5]
976정성태1/11/201153923오류 유형: 111. IIS - 500.19 오류 (0x8007000d)
975정성태1/10/201128130.NET Framework: 202. CLR JIT 컴파일러가 생성한 기계어 코드 확인하는 방법 [3]파일 다운로드1
974정성태1/8/201126963.NET Framework: 201. 윈폼 TreeView - Bold 폰트 설정 후 텍스트가 잘리는 문제 [1]파일 다운로드1
973정성태1/7/201126291.NET Framework: 200. IIS Metabase와 ServerManager 개체 활용파일 다운로드1
... 151  152  153  154  155  156  157  158  159  160  161  [162]  163  164  165  ...