자습서: Azure Functions 및 Azure Web PubSub 서비스를 사용하여 서버리스 실시간 채팅 앱 만들기
Azure Web PubSub 서비스를 사용하면 WebSocket 및 게시-구독 패턴을 사용하여 실시간 메시징 웹 애플리케이션을 쉽게 빌드할 수 있습니다. Azure Functions는 인프라를 관리하지 않고 코드를 실행할 수 있는 서버리스 플랫폼입니다. 이 자습서에서는 Azure Web PubSub 서비스 및 Azure Functions를 사용하여 실시간 메시징과 게시-구독 패턴으로 서버리스 애플리케이션을 빌드하는 방법에 대해 알아봅니다.
이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.
- 서버리스 실시간 채팅 앱 빌드
- Web PubSub 함수 트리거 바인딩 및 출력 바인딩 작업
- Azure Function 앱에 함수 배포
- Azure 인증 구성
- 애플리케이션에 이벤트 및 메시지를 라우팅하도록 Web PubSub 이벤트 처리기 구성
Important
원시 연결 문자열 데모용으로만 이 문서에 표시됩니다.
연결 문자열에는 애플리케이션이 Azure Web PubSub 서비스에 액세스하는 데 필요한 권한 부여 정보가 포함됩니다. 연결 문자열 내의 액세스 키는 서비스의 루트 암호와 비슷합니다. 프로덕션 환경에서는 항상 액세스 키를 보호합니다. Azure Key Vault를 사용하여 키를 안전하게 관리 및 회전하고 연결을 WebPubSubServiceClient
보호합니다.
액세스 키를 다른 사용자에게 배포하거나 하드 코딩하거나 다른 사용자가 액세스할 수 있는 일반 텍스트로 저장하지 않도록 합니다. 키가 손상되었다고 생각되면 키를 교체하세요.
필수 조건
Visual Studio Code와 같은 코드 편집기
Node.js, 버전 18.x 이상
참고 항목
지원되는 Node.js 버전에 대한 자세한 내용은 Azure Functions 런타임 버전 설명서를 참조하세요.
Azure Functions Core Tools(v4 이상 추천) - Azure Function 앱을 로컬로 실행하고 Azure에 배포합니다.
Azure 리소스를 관리하기 위한 Azure CLI.
Azure를 구독하고 있지 않다면 시작하기 전에 Azure 체험 계정을 만듭니다.
Azure에 로그인
Azure 계정을 사용하여 https://portal.azure.com/에서 Azure Portal에 로그인합니다.
Azure Web PubSub 서비스 인스턴스 만들기
애플리케이션이 Azure의 Web PubSub 서비스 인스턴스에 연결됩니다.
Azure Portal의 왼쪽 위에 있는 새로 만들기 단추를 선택합니다. 새 화면의 검색 상자에서 Web PubSub를 입력하고 Enter를 누릅니다. (
Web
범주에서 Azure Web PubSub를 검색할 수도 있습니다.)검색 결과에서 Web PubSub를 선택한 다음, 만들기를 선택합니다.
다음 설정을 입력합니다.
설정 제안 값 설명 리소스 이름 전역적으로 고유한 이름 새 Web PubSub 서비스 인스턴스를 식별하는 전역적으로 고유한 이름입니다. 유효한 문자는 a-z
,A-Z
,0-9
및-
입니다.구독 구독 이 새 Web PubSub 서비스 인스턴스가 생성되는 Azure 구독입니다. 리소스 그룹 myResourceGroup Web PubSub 서비스 인스턴스를 만들 새 리소스 그룹의 이름입니다. 위치 미국 서부 가까운 지역을 선택합니다. 가격 책정 계층 Free 먼저 Azure Web PubSub 서비스 평가판을 사용할 수 있습니다. Azure Web PubSub 서비스 가격 책정 계층에 대해 자세히 알아보세요. 단위 수 - 단위 수는 Web PubSub 서비스 인스턴스가 허용할 수 있는 연결 수를 지정합니다. 각 단위는 최대 1,000개의 동시 연결을 지원합니다. 표준 계층에서만 구성할 수 있습니다. 만들기를 선택하여 Web PubSub 서비스 인스턴스 배포를 시작하세요.
함수 만들기
Azure Functions Core Tools가 설치되어 있는지 확인합니다. 그런 다음, 프로젝트에 대한 빈 디렉터리를 만듭니다. 이 작업 디렉터리 아래에서 명령을 실행합니다.
func init --worker-runtime javascript --model V4
Microsoft.Azure.WebJobs.Extensions.WebPubSub
설치Web PubSub 지원을 가져오려면
host.json
의 extensionBundle을 확인하고 버전 4.* 이상으로 업데이트합니다.{ "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" } }
클라이언트에 대한 정적 웹 페이지를 읽고 호스팅하는
index
함수를 만듭니다.func new -n index -t HttpTrigger
src/functions/index.js
를 업데이트하고 다음 코드를 복사합니다.const { app } = require('@azure/functions'); const { readFile } = require('fs/promises'); app.http('index', { methods: ['GET', 'POST'], authLevel: 'anonymous', handler: async (context) => { const content = await readFile('index.html', 'utf8', (err, data) => { if (err) { context.err(err) return } }); return { status: 200, headers: { 'Content-Type': 'text/html' }, body: content, }; } });
클라이언트가 액세스 토큰과 함께 서비스 연결 URL을 얻을 수 있도록
negotiate
함수를 만듭니다.func new -n negotiate -t HttpTrigger
참고 항목
이 샘플에서는 In this sample, we use Microsoft Entra ID 사용자 ID 헤더
x-ms-client-principal-name
을 사용하여userId
를 검색합니다. 그리고 이는 로컬 함수에서 작동하지 않습니다. 비워두거나, 로컬로 재생할 때userId
를 가져오거나 생성하는 다른 방법으로 변경할 수 있습니다. 예를 들어 클라이언트에서 사용자 이름을 입력하고,negotiate
함수를 호출하여 서비스 연결 URL을 가져올 때?user={$username}
과 같은 쿼리에 해당 사용자 이름을 전달할 수 있습니다. 그리고negotiate
함수에서userId
를{query.user}
값으로 설정합니다.src/functions/negotiate
를 업데이트하고 다음 코드를 복사합니다.const { app, input } = require('@azure/functions'); const connection = input.generic({ type: 'webPubSubConnection', name: 'connection', userId: '{headers.x-ms-client-principal-name}', hub: 'simplechat' }); app.http('negotiate', { methods: ['GET', 'POST'], authLevel: 'anonymous', extraInputs: [connection], handler: async (request, context) => { return { body: JSON.stringify(context.extraInputs.get('connection')) }; }, });
서비스를 통해 클라이언트 메시지를 브로드캐스트하는
message
함수를 만듭니다.func new -n message -t HttpTrigger
src/functions/message.js
를 업데이트하고 다음 코드를 복사합니다.const { app, output, trigger } = require('@azure/functions'); const wpsMsg = output.generic({ type: 'webPubSub', name: 'actions', hub: 'simplechat', }); const wpsTrigger = trigger.generic({ type: 'webPubSubTrigger', name: 'request', hub: 'simplechat', eventName: 'message', eventType: 'user' }); app.generic('message', { trigger: wpsTrigger, extraOutputs: [wpsMsg], handler: async (request, context) => { context.extraOutputs.set(wpsMsg, [{ "actionName": "sendToAll", "data": `[${context.triggerMetadata.connectionContext.userId}] ${request.data}`, "dataType": request.dataType }]); return { data: "[SYSTEM] ack.", dataType: "text", }; } });
프로젝트 루트 폴더에서 클라이언트 단일 페이지(
index.html
)를 추가하고 콘텐츠를 복사합니다.<html> <body> <h1>Azure Web PubSub Serverless Chat App</h1> <div id="login"></div> <p></p> <input id="message" placeholder="Type to chat..." /> <div id="messages"></div> <script> (async function () { let authenticated = window.location.href.includes( "?authenticated=true" ); if (!authenticated) { // auth let login = document.querySelector("#login"); let link = document.createElement("a"); link.href = `${window.location.origin}/.auth/login/aad?post_login_redirect_url=/api/index?authenticated=true`; link.text = "login"; login.appendChild(link); } else { // negotiate let messages = document.querySelector("#messages"); let res = await fetch(`${window.location.origin}/api/negotiate`, { credentials: "include", }); let url = await res.json(); // connect let ws = new WebSocket(url.url); ws.onopen = () => console.log("connected"); ws.onmessage = (event) => { let m = document.createElement("p"); m.innerText = event.data; messages.appendChild(m); }; let message = document.querySelector("#message"); message.addEventListener("keypress", (e) => { if (e.charCode !== 13) return; ws.send(message.value); message.value = ""; }); } })(); </script> </body> </html>
Azure 함수 앱 만들기 및 배포
함수 코드를 Azure에 배포하기 전에 다음 세 가지 리소스를 만들어야 합니다.
- 리소스 그룹 - 관련 리소스에 대한 논리 컨테이너입니다.
- 스토리지 계정 - 함수에 대한 상태 및 기타 정보를 유지 관리합니다.
- 함수 앱 - 함수 코드를 실행할 수 있는 환경을 제공합니다. 함수 앱은 로컬 함수 프로젝트에 매핑되며, 함수를 논리적 단위로 그룹화하여 리소스를 더 쉽게 관리, 배포 및 공유할 수 있습니다.
다음 명령을 사용하여 이러한 항목을 만듭니다.
아직 로그인하지 않은 경우 Azure에 로그인합니다.
az login
리소스 그룹을 만들거나, Azure Web PubSub 서비스 중 하나를 다시 사용하여 건너뛸 수 있습니다.
az group create -n WebPubSubFunction -l <REGION>
범용 스토리지 계정을 리소스 그룹 및 지역에 만듭니다.
az storage account create -n <STORAGE_NAME> -l <REGION> -g WebPubSubFunction
Azure에서 함수 앱을 만듭니다.
az functionapp create --resource-group WebPubSubFunction --consumption-plan-location <REGION> --runtime node --runtime-version 18 --functions-version 4 --name <FUNCIONAPP_NAME> --storage-account <STORAGE_NAME>
참고 항목
Azure Functions 런타임 버전 설명서를 확인하여
--runtime-version
매개 변수를 지원되는 값으로 설정하세요.함수 프로젝트를 Azure에 배포합니다.
Azure에서 함수 앱을 성공적으로 만들었으면 이제 func azure functionapp publish 명령을 사용하여 로컬 함수 프로젝트를 배포할 준비가 되었습니다.
func azure functionapp publish <FUNCIONAPP_NAME>
함수 앱의
WebPubSubConnectionString
을 구성합니다.원시 연결 문자열 데모용으로만 이 문서에 표시됩니다. 프로덕션 환경에서는 항상 액세스 키를 보호합니다. Azure Key Vault를 사용하여 키를 안전하게 관리 및 회전하고 연결을
WebPubSubServiceClient
보호합니다.먼저 Azure Portal에서 Web PubSub 리소스를 찾고 키 아래에 있는 연결 문자열을 복사합니다. 그런 다음, Azure Portal>설정>구성에서 함수 앱 설정으로 이동합니다. 그리고 애플리케이션 설정에 이름이
WebPubSubConnectionString
이며 값은 Web PubSub 리소스 연결 문자열인 새 항목을 추가합니다.
Event Handler
Web PubSub 서비스 구성
이 샘플에서는 WebPubSubTrigger
를 사용하여 서비스 업스트림 요청을 수신 대기합니다. 따라서 Web PubSub는 대상 클라이언트 요청을 보내기 위해 함수의 엔드포인트 정보를 인식하고 있어야 합니다. 그리고 Azure Function 앱에는 확장 관련 웹후크 방법에 대한 보안을 위한 시스템 키가 필요합니다. 이전 단계에서 message
함수를 사용하여 함수 앱을 배포하면 시스템 키를 얻을 수 있습니다.
Azure Portal -> 함수 앱 리소스 찾기 ->앱 키 ->시스템 키 ->webpubsub_extension
로 이동합니다. 값을 <APP_KEY>
로 복사합니다.
Azure Web PubSub 서비스에 Event Handler
를 설정합니다. Azure Portal -> Web PubSub 리소스 찾기 ->설정으로 이동합니다. 사용 중인 하나의 함수에 새 허브 설정 매핑을 추가합니다. <FUNCTIONAPP_NAME>
및 <APP_KEY>
를 사용자 고유의 값으로 바꿉니다.
- 허브 이름:
simplechat
- URL 템플릿: https://<FUNCTIONAPP_NAME>.azurewebsites.net/runtime/webhooks/webpubsub?code=<APP_KEY>
- 사용자 이벤트 패턴: *
- 시스템 이벤트: -(이 샘플에서는 구성할 필요가 없음)
클라이언트 인증을 사용하도록 구성
Azure Portal -> 함수 앱 리소스 찾기 ->인증으로 이동합니다. Add identity provider
을 클릭합니다. App Service 인증 설정을 인증되지 않은 액세스 허용으로 설정합니다. 그러면 익명 사용자가 인증을 위해 리디렉션하기 전에 클라이언트 인덱스 페이지를 방문할 수 있습니다. 그런 다음 저장을 선택합니다.
여기서는 negotiate
함수에서 x-ms-client-principal-name
을 userId
로 사용할 ID 공급자로 Microsoft
를 선택합니다. 또한 링크에 따라 다른 ID 공급자를 구성할 수 있으며, 이에 따라 negotiate
함수에서 userId
값을 업데이트해야 합니다.
애플리케이션 사용해 보기
이제 함수 앱(https://<FUNCTIONAPP_NAME>.azurewebsites.net/api/index
)에서 페이지를 테스트할 수 있습니다. 스냅샷을 참조하세요.
login
을 클릭하여 자신을 인증합니다.- 입력 상자에서 채팅 메시지를 입력합니다.
메시지 함수에서 호출자의 메시지를 모든 클라이언트에 브로드캐스트하고 [SYSTEM] ack
메시지와 함께 호출자를 반환합니다. 따라서 샘플 채팅 스냅샷에서 처음 4개 메시지는 현재 클라이언트에서 제공되었으며, 마지막 2개 메시지는 다른 클라이언트에서 제공되었습니다.
리소스 정리
이 앱을 계속 사용하지 않으려면 다음 단계에 따라 이 문서에서 만든 리소스를 모두 삭제하세요. 요금은 발생되지 않습니다.
Azure Portal에서 맨 왼쪽에 있는 리소스 그룹을 선택한 다음, 만든 리소스 그룹을 선택합니다. 대신 검색 상자를 사용하여 이름으로 리소스 그룹을 찾을 수 있습니다.
열린 창에서 리소스 그룹을 선택한 다음, 리소스 그룹 삭제를 선택합니다.
새 창에서 삭제할 리소스 그룹의 이름을 입력한 다음, 삭제를 선택합니다.
다음 단계
이 빠른 시작에서는 서버리스 채팅 애플리케이션을 실행하는 방법을 알아보았습니다. 이제 자체 애플리케이션을 빌드할 수 있습니다.