배포: 시나리오: Azure App Service + Github + SQL Server
Source: Dev.to
우리가 구성할 시나리오의 구성 요소
- Azure App Service: 애플리케이션이 실행되는 곳
- GitHub: 코드가 저장되는 곳
- GitHub Actions (선택 사항이지만 권장): 빌드 및 배포 자동화
- Azure SQL Database (SQL Server): 데이터가 저장되는 곳
GitHub (código)
↓
Pipeline (build / deploy)
↓
Azure App Service (API / App)
↓
Azure SQL Database (dados)
1. Azure App Service란?
이미 서버 유형에 대해 살펴본 바와 같이, Azure App Service는 관리형 서비스입니다. 이는 다음을 의미합니다:
- 서버를 직접 만들지 않음
- Windows/Linux를 직접 설치하지 않음
- IIS, Kestrel 또는 Nginx를 수동으로 구성하지 않음
1.1 App Service
Azure 플랫폼이 이러한 모든 문제를 대신 처리합니다. App Service를 만들 때 다음을 정의합니다:
- 런타임 (예: .NET 8)
- 호스팅 플랜 (CPU / 메모리 / 비용)
- 리전 (서버가 위치하는 곳)
그 결과 공개 URL과 코드를 실행할 준비가 된 환경이 제공됩니다:
https://minha-api.azurewebsites.net
중요: 이 시점에서는 아직 실행 중인 코드는 없습니다.
1.2 코드가 Azure에 어떻게 올라가나요? (GitHub Actions)
Azure App Service가 설정된 후, 코드를 리포지토리에서 Azure로 올려야 합니다. 여기서는 GitHub Actions를 사용하고, 이 도구가 해결하는 문제를 살펴보겠습니다.
1.2.1 수동 프로세스
GitHub Actions 이전에 배포는 보통 다음과 같이 진행되었습니다:
- 로컬에서 컴파일
- 수동으로 배포
- FTP를 통해 파일 덮어쓰기
이 프로세스는 일관성 부족, 인간 실수, 히스토리 부재, 예측 불가능한 배포와 같은 문제를 야기합니다.
1.2.2 GitHub Actions
GitHub Actions는 구성 가능한 로봇으로, 리포지토리에서 무언가가 발생할 때마다 GitHub 내부에서 실행됩니다. 이 “무언가”는 다음과 같습니다:
pushpull request- 태그 생성
- 예약된 시간
이 로봇은 코드를 컴파일하고, 테스트를 실행하고, 빌드를 생성하고, 배포하고, 알림을 보내는 등 다양한 작업을 수행할 수 있습니다. 모든 작업은 워크플로우가 설정되어 있기 때문에 가능합니다.
1.3 워크플로우란 무엇이며 이것과 어떤 관련이 있나요?
워크플로우는 .yml 파일로, “X가 발생하면 Y 단계를 순서대로 실행한다”는 내용을 기술합니다. 예시:
# .github/workflows/deploy.yml
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build
run: dotnet build --configuration Release
- name: Test
run: dotnet test --no-build --configuration Release
- name: Publish
run: dotnet publish -c Release -o ./publish
- name: Deploy to Azure
uses: azure/webapps-deploy@v2
with:
app-name: minha-api
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: ./publish
이점: 워크플로우 파일 자체가 코드이므로, 배포가 버전 관리, 감사 가능, 재현 가능해집니다.
2. Azure에서 SQL Server 만들기
Azure에서 데이터베이스를 만들면 자동 백업, 고가용성 및 설치가 필요 없습니다. 프로세스가 끝나면 다음을 받게 됩니다:
- 서버 이름
- 데이터베이스 이름
- 사용자 이름 및 비밀번호
이 정보는 절대로 코드에 포함되어서는 안 됩니다.
2.1 논리 서버 (SQL Server)
VM이 아니라 인증 및 연결을 위한 관리형 엔드포인트입니다. 서버는:
- 여러 데이터베이스를 호스팅할 수 있음
- 보안을 중앙 집중화
- 방화벽을 제어
Azure 포털에서:
Azure SQL → Create → 입력:
- Server name →
meu-servidor.database.windows.net - Admin login
- 비밀번호
2.2 데이터베이스
서버 내에서 nomeDoBanco 데이터베이스를 만들고 다음을 정의합니다:
- 계층 (Basic / General Purpose / Business Critical)
- DTU 또는 vCore
2.3 SQL Server 방화벽
기본적으로 아무도 데이터베이스에 접근할 수 없습니다. Networking → Firewall rules에서 구성하세요:
- ✔️ Allow Azure services
- ✔️ Adicionar IP da sua máquina (로컬 마이그레이션용)
이렇게 하지 않으면:
- 애플리케이션이 연결되지 않음
- 마이그레이션 실패
- 타임아웃 오류
실제 프로덕션에서는: Private Endpoint를 사용하는 것이 이상적입니다. 시작 단계에서는 간단한 방화벽 설정만으로도 충분합니다.
Source: …
3. Connection String – 애플리케이션과 데이터베이스를 연결하는 방법
이는 전체 배포 과정에서 가장 중요한 부분 중 하나입니다. Connection string이 없으면 애플리케이션이 데이터베이스와 통신하지 못합니다.
- 애플리케이션 시작: ✔️
- 데이터베이스 존재: ✔️
- 하지만 아무것도 통신되지 않음: ❌
3.1 Azure SQL Database에서 이미 만든 항목
- 서버 이름
- 데이터베이스 이름
- 관리자 로그인
- 비밀번호
- 인증 유형 (SQL Authentication)
이 정보들이 Connection string의 기본이 됩니다.
3.2 실제로 Connection String이란?
애플리케이션에 다음 정보를 알려 주는 텍스트입니다.
- 데이터베이스가 어디에 있는지
- 어떤 데이터베이스에 접속할지
- 어떻게 인증할지
- 연결 중에 어떻게 동작할지
일반적인 예시:
Server=...
Database=...
User Id=...
Password=...
3.3 Connection String 값은 어디서 오는가?
Azure SQL Database에서:
SQL Database → Settings → Connection strings
보통 다음과 같은 형태를 볼 수 있습니다.
Server=tcp:meuservidor.database.windows.net,1433;
Initial Catalog=MinhaBase;
PersistSecurityInfo=False;
User ID=adminuser;
Password=********;
MultipleActiveResultSets=False;
Encrypt=True;
TrustServerCertificate=False;
Connection Timeout=30;
팁: 전체 문자열을 복사하여 Secret(예: Azure Key Vault 또는 GitHub Secrets)에 저장해 두면 코드에 노출되지 않습니다.
3.4 이제 앱 → 데이터베이스 연결하기
이 설정은 Azure App Service에서 직접 수행되며, 코드를 수정할 필요가 없습니다.
3.4.1 Azure Portal 경로
App Service
→ Settings
→ Configuration
→ Connection strings
이 영역은 애플리케이션의 비밀 저장소 역할을 합니다.
- ✅ 더 안전함
- ✅ 코드와 분리됨
- ✅ 환경별(Dev / Staging / Production) 사용에 적합
3.4.2 Connection String 이름 (매우 중요)
Entity Framework Core를 사용하는 경우 가장 일반적이고 권장되는 이름은:
DefaultConnection
이 이름은 Program.cs 또는 appsettings.json에 정의된 이름과 정확히 일치해야 합니다.
코드 예시:
builder.Services.AddDbContext(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")));
Azure에서 이름이 다르면:
- ❌ 애플리케이션은 시작됨
- ❌ 하지만 데이터베이스를 찾지 못함
- ❌ 전형적인 오류: The ConnectionString property has not been initialized
4. 마이그레이션
이제 데이터베이스 배포에서 가장 중요한 부분이 나옵니다. 세 가지 실용적인 흐름으로 나누어 보겠습니다:
- 수동 마이그레이션 로컬 → Azure SQL
- GitHub Actions를 통한 마이그레이션 → Azure SQL (파이프라인)
- SQL 스크립트 마이그레이션 (기업에서 사용하는 실무)
4.1 수동 마이그레이션 (로컬 → Azure SQL)
전제 조건
- EF Core 프로젝트
- 이미 생성된 마이그레이션
이는 아직 데이터베이스를 변경하지 않고, C# 파일만 생성합니다.
4.2 Azure에서 데이터베이스 접근 허용
기본적으로 Azure SQL은 모든 접근을 차단하므로 로컬 머신을 허용해야 합니다; 이를 하지 않으면 시스템에서 Login failed / Timeout expired 오류가 발생합니다.
Azure 포털에서
- Azure SQL Server
- 네트워킹
- 방화벽 규칙
- 클라이언트 IPv4 주소 추가
- 저장
4.3 애플리케이션이 Azure를 가리키도록 보장
appsettings.Development.json 파일이 Azure의 SQL Server를 가리키고 있는지 확인하세요:
{
"ConnectionStrings": {
"DefaultConnection": "Server=tcp:meuservidor.database.windows.net;..."
}
}
4.4 마이그레이션 실행
dotnet ef database update
내부에서 일어나는 일
- EF가 Azure SQL에 연결을 엽니다
__EFMigrationsHistory테이블이 존재하는지 확인합니다- 존재하지 않으면 → 생성
- 존재하면 → 이미 실행된 마이그레이션을 읽습니다
- 비교합니다:
- 코드에 있는 마이그레이션
- 데이터베이스에 있는 마이그레이션
- 보류 중인 것만 실행합니다
- 적용된 버전을 기록합니다