Microsoft MVP성태의 닷넷 이야기
.NET Framework: 1998. Azure Functions를 사용한 간단한 실습 [링크 복사], [링크+제목 복사],
조회: 14508
글쓴 사람
정성태 (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

비밀번호

댓글 작성자
 




... 91  92  93  94  95  96  97  98  99  100  101  102  103  104  [105]  ...
NoWriterDateCnt.TitleFile(s)
11299정성태9/9/201719726개발 환경 구성: 330. Hyper-V VM의 Internal Network를 Private 유형으로 만드는 방법
11298정성태9/8/201723089VC++: 119. EnumProcesses / EnumProcessModules API 사용 시 주의점 [1]
11297정성태9/8/201719706디버깅 기술: 96. windbg - 풀 덤프에 포함된 모든 닷넷 모듈을 파일로 저장하는 방법
11296정성태9/8/201722902웹: 36. Edge - "이 웹 사이트는 이전 기술에서 실행되며 Internet Explorer에서만 작동합니다." 끄는 방법
11295정성태9/7/201720323디버깅 기술: 95. Windbg - .foreach 사용법
11294정성태9/4/201720043개발 환경 구성: 329. 마이크로소프트의 CoreCLR 프로파일러 예제 빌드 방법 [1]
11293정성태9/4/201720591개발 환경 구성: 328. Visual Studio(devenv.exe)를 배치 파일(.bat)을 통해 실행하는 방법
11292정성태9/4/201718864오류 유형: 419. Cannot connect to WMI provider - Invalid class [0x80041010]
11291정성태9/3/201720704개발 환경 구성: 327. 아파치 서버 2.4를 위한 mod_aspdotnet 마이그레이션
11290정성태9/3/201723934개발 환경 구성: 326. 아파치 서버에서 ASP.NET을 실행하는 mod_aspdotnet 모듈 [2]
11289정성태9/3/201721591개발 환경 구성: 325. GAC에 어셈블리 등록을 위해 gacutil.exe을 사용하는 경우 주의 사항
11288정성태9/3/201718291개발 환경 구성: 324. 윈도우용 XAMPP의 아파치 서버 구성 방법
11287정성태9/1/201727572.NET Framework: 680. C# - 작업자(Worker) 스레드와 UI 스레드 [11]
11286정성태8/28/201714871기타: 67. App Privacy Policy
11285정성태8/28/201723477.NET Framework: 679. C# - 개인 키 보안의 SFTP를 이용한 파일 업로드파일 다운로드1
11284정성태8/27/201721506.NET Framework: 678. 데스크톱 윈도우 응용 프로그램에서 UWP 라이브러리를 이용한 비디오 장치 열람하는 방법 [1]파일 다운로드1
11283정성태8/27/201717273오류 유형: 418. CSS3117: @font-face failed cross-origin request. Resource access is restricted.
11282정성태8/26/201719715Math: 22. 행렬로 바라보는 피보나치 수열
11281정성태8/26/201721509.NET Framework: 677. Visual Studio 2017 - NuGet 패키지를 직접 참조하는 PackageReference 지원 [2]
11280정성태8/24/201718562디버깅 기술: 94. windbg - 풀 덤프에 포함된 모든 모듈을 파일로 저장하는 방법
11279정성태8/23/201730177.NET Framework: 676. C# Thread가 Running 상태인지 아는 방법
11278정성태8/23/201718308오류 유형: 417. TFS - Warning - Unable to refresh ... because you have a pending edit. [1]
11277정성태8/23/201719555오류 유형: 416. msbuild - error MSB4062: The "TransformXml" task could not be loaded from the assembly
11276정성태8/23/201723908.NET Framework: 675. C# - (파일) 확장자와 연결된 실행 파일 경로 찾기 [2]파일 다운로드1
11275정성태8/23/201732874개발 환경 구성: 323. Visual Studio 설치 없이 빌드 환경 구성 - Visual Studio 2017용 Build Tools [1]
11274정성태8/22/201719457.NET Framework: 674. Thread 타입의 Suspend/Resume/Join 사용 관련 예외 처리
... 91  92  93  94  95  96  97  98  99  100  101  102  103  104  [105]  ...