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

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

비밀번호

댓글 작성자
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13623정성태5/11/2024248닷넷: 2261. C# - 구글 OAuth의 JWT (JSON Web Tokens) 해석파일 다운로드1
13622정성태5/10/2024250닷넷: 2260. C# - Google 로그인 연동 (ASP.NET 예제)파일 다운로드1
13621정성태5/10/2024241오류 유형: 902. IISExpress - Failed to register URL "..." for site "..." application "/". Error description: Cannot create a file when that file already exists. (0x800700b7)
13620정성태5/9/2024470VS.NET IDE: 190. Visual Studio가 node.exe를 경유해 Edge.exe를 띄우는 경우
13619정성태5/7/2024558닷넷: 2259. C# - decimal 저장소의 비트 구조파일 다운로드1
13618정성태5/6/2024709닷넷: 2258. C# - double (배정도 실수) 저장소의 비트 구조파일 다운로드1
13617정성태5/5/2024746닷넷: 2257. C# - float (단정도 실수) 저장소의 비트 구조파일 다운로드1
13616정성태5/3/2024891닷넷: 2256. ASP.NET Core 웹 사이트의 HTTP/HTTPS + Dual mode Socket (IPv4/IPv6) 지원 방법파일 다운로드1
13615정성태5/3/2024915닷넷: 2255. C# 배열을 Numpy ndarray 배열과 상호 변환
13614정성태5/2/2024845닷넷: 2254. C# - COM 인터페이스의 상속 시 중복으로 메서드를 선언
13613정성태5/1/2024884닷넷: 2253. C# - Video Capture 장치(Camera) 열거 및 지원 포맷 조회파일 다운로드1
13612정성태4/30/2024902오류 유형: 902. Visual Studio - error MSB3021: Unable to copy file
13611정성태4/29/2024910닷넷: 2252. C# - GUID 타입 전용의 UnmanagedType.LPStruct - 두 번째 이야기파일 다운로드1
13610정성태4/28/2024972닷넷: 2251. C# - 제네릭 인자를 가진 타입을 생성하는 방법 - 두 번째 이야기
13609정성태4/27/20241017닷넷: 2250. PInvoke 호출 시 참조 타입(class)을 마샬링하는 [IN], [OUT] 특성파일 다운로드1
13608정성태4/26/20241097닷넷: 2249. C# - 부모의 필드/프로퍼티에 대해 서로 다른 자식 클래스 간에 Reflection 접근이 동작할까요?파일 다운로드1
13607정성태4/25/20241102닷넷: 2248. C# - 인터페이스 타입의 다중 포인터를 인자로 갖는 C/C++ 함수 연동
13606정성태4/24/20241064닷넷: 2247. C# - tensorflow 연동 (MNIST 예제)파일 다운로드1
13605정성태4/23/20241058닷넷: 2246. C# - Python.NET을 이용한 파이썬 소스코드 연동파일 다운로드1
13604정성태4/22/20241048오류 유형: 901. Visual Studio - Unable to set the next statement. Set next statement cannot be used in '[Exception]' call stack frames.
13603정성태4/21/20241117닷넷: 2245. C# - IronPython을 이용한 파이썬 소스코드 연동파일 다운로드1
13602정성태4/20/20241062닷넷: 2244. C# - PCM 오디오 데이터를 연속(Streaming) 재생 (Windows Multimedia)파일 다운로드1
13601정성태4/19/20241086닷넷: 2243. C# - PCM 사운드 재생(NAudio)파일 다운로드1
13600정성태4/18/20241131닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/20241045닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...