SQL Server: App Service PYODBC Connection 연결 알아 보기 #2

Agenda

이전 포스트에 이어서 Azure 환경에 앱 배포 및 Azure SQL DB 와 연동 설정에 대해서 포스팅한다.

로컬 환경과 달리 Azure 환경에서 네트워크 설정 문제로 인한 통신 에러가 발생하였다. 퍼블릭 통신이기 때문에 따로 네트워크 설정은 필요하지 않을 것이라 예상했던 것과는 달리, Azure 리소스 간의 통신에 추가적인 네트워크 설정이 필요했다.

글 작성 배경

SQL IAM (Identity and Access Management) 설정에 App Service의 시스템 할당 관리 ID로 유저를 생성하고, 역할을 할당하는 것만으로는 앱이 SQL Database 와 연결되지 않았다. 커넥션 설정을 추가함으로 연결 및 쿼리를 실행할 수 있게 된다.

Microsoft Learn 의 문서를 참고하여 테스트를 진행했고, 몇 가지시행착오에 대해서 정리하려고 한다.

  1. Azure CLI 를 이용한 App Service 배포 명령어에 대해서 알아 본다.
  2. SQL Server 네트워크 설정에 대해서 알아 본다.
  3. Azure 환경에서 PYODBC 커넥션으로 SQL DB 과의 연동에 대해서 알아 본다.

Commands

주의) Micorosoft 문서의 명령어와 다른 부분이 존재한다.

Powershell을 이용해서 테스트가 가능하도록 명령어를 수정하였다.

# Variable for Local Test
$env:AZURE_SQL_CONNECTIONSTRING = "Driver={ODBC Driver 18 for SQL Server};Server=tcp:demo-kgineer-sql.database.windows.net,1433;Database=demo-kgineer-sqldb;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;"

# Run the app.py file 
uvicorn app:app --reload

# Variables
$rg_name = "azure-learn-rg"
$app_name = "azure-learn-demo-app"
$connection_string = "Driver={ODBC Driver 18 for SQL Server};Server=tcp:demo-kgineer-sql.database.windows.net,1433;Database=demo-kgineer-sqldb;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;"

# Azure CLI Commands
az webapp up `
  --resource-group $rg_name `
  --name $app_name

az webapp config set `
  --resource-group $rg_name `
  --name $app_name `
  --startup-file start.sh

az webapp identity assign `
  --resource-group $rg_name `
  --name $app_name

# SQL Query
CREATE USER [azure-learn-demo-app] FROM EXTERNAL PROVIDER
ALTER ROLE db_datareader ADD MEMBER [azure-learn-demo-app]
ALTER ROLE db_datawriter ADD MEMBER [azure-learn-demo-app]

# Azure Commands
az webapp config appsettings set `
  --resource-group $rg_name `
  --name $app_name `
  --settings AZURE_SQL_CONNECTIONSTRING=$connection_string

# App Service API URL
https://azure-learn-demo-app.azurewebsites.net/docs

Deploy to Azure App Service

로컬에 작성해 놓은 .venv 디렉토리의 내용을 그대로 Azure App Service 에 배포 한다.

  • App Service Plan 및 App Service 리소스는 배포 명령어 실행 시에 자동으로 생성된다.
  • 사전에 App Service (Linux: Python 3.12) 를 생성하고 배포 명령어를 실행한 경우, App Service 가 정상적으로 동작하지 않았다.
    1. <App Service Name>.azurewebsites.net URL 에 Gateway Timeout 504 Error 가 발생하게 된다.
    2. SSH 콘솔에 접속할 수 없게 된다.

원인에 대해서 조금 조사해 보았는데, 포트 충돌로 인한 에러가 발생하는 것으로 보였다.

Create a start.sh file

App Service 실행 및 다시 시작, 코드 재배포가 이루어졌을 경우에 자동으로 앱이 시작되도록 스크립트 파일을 작성한다.

gunicorn -w 4 -k uvicorn.workers.UvicornWorker app:app

Use the az webapp up to deploy the code to App Service.

# Variables
$rg_name = "azure-learn-rg"
$app_name = "azure-learn-demo-app"
$connection_string = "Driver={ODBC Driver 18 for SQL Server};Server=tcp:demo-kgineer-sql.database.windows.net,1433;Database=demo-kgineer-sqldb;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;"

# Active Subscription Check
az account show

# Azure CLI Commands
az webapp up `
  --resource-group $rg_name `
  --name $app_name
az webapp up 실행 결과

Use the az webapp config set command to configure App Service to use the start.sh file.

az webapp config set `
  --resource-group $rg_name `
  --name $app_name `
  --startup-file start.sh
az webapp config set실행 결과

Azure Portal [Configuration] 에서 정상적으로 설정된 것을 확인할 수 있다.

Use the az webapp identity assign command to enable a system-assigned managed identity for the App Service.

az webapp identity assign `
  --resource-group $rg_name `
  --name $app_name
az webapp identity assign 실행 결과

Azure Portal [Identity] 에서 정상적으로 설정된 것을 확인할 수 있다.

Connect the App Service to Azure SQL Database

SQL DB 에서 쿼리를 실행하여 App Service 의 System Assigned Managed ID 의 User 생성 및 역할 할당을 실시한다.

Add a user to the Azure SQL Database with SQL commands to create a user and role for passwordless access.

-- SQL Query
CREATE USER [azure-learn-demo-app] FROM EXTERNAL PROVIDER
ALTER ROLE db_datareader ADD MEMBER [azure-learn-demo-app]
ALTER ROLE db_datawriter ADD MEMBER [azure-learn-demo-app]

포스팅 전에 테스트할 때 이미 User 생성 및 역할 할당이 완료된 상태이다.

SQL DB Query 결과

Use the az webapp config appsettings set command to add an app setting for the connection string.

App Service 앱 세팅 (환경 변수)에 SQL DB의 Connection String 을 추가한다.

# Azure Commands
az webapp config appsettings set `
  --resource-group $rg_name `
  --name $app_name `
  --settings AZURE_SQL_CONNECTIONSTRING=$connection_string

아래의 두 변수는 지정하지 않아도 자동으로 추가된다.

  • SCM_DO_BUILD_DURING_DEPLOYMENT
  • WEBSITE_HTTPLOGGINH_RETENTION_DAYS

Azure Portal [Evironment variables] 에서 확인이 가능하다.

Test the deployed application

Microsoft 문서에서는 여기까지가 앱 배포 및 커넥션 설정이 끝이라고 기재되어 있지만, 앱의 동작을 확인한 결과, Internal Server Error 500 이 발생했다. 네트워크 측면에서 문제가 있으므로 SQL Server 의 네트워크 설정을 변경해 주어야 한다.

Persons 테이블 조회 실패

SQL Server Network settings

네트워크 설정의 기본값은 [Selected networks] 이다. Azure SQL Server 는 퍼블릭 접근을 허용하지 않기 때문에 SSMS (SQL Server Management Studio) 에서 접속하기 위해서도 SQL Firewall 에 Client ip 를 허용해 주어야 한다.

SQL Server exceptions

Azure 서비스 간의 통신은 예외적으로 허용하는 옵션을 설정할 필요가 있다.

기업 환경에서는 사설망에 Private Endpoint 를 이용하여, Firewall 과 NSG (Network Security Group)로 리소스 간의 통신을 허가하는 것이 일반적이다. 하지만 코스트와 시간이..

Azure services 는 예외 처리로 설정

Test the deployed application #Retry

App Service 와 SQL DB 가 정상적으로 연계되고 있는 것을 확인할 수 있었다.