Azure App Service 是微軟提供的全託管式 Web 應用程式平台,讓開發者能專注於程式開發,不需要擔心基礎架構的管理。搭配 GitHub Actions,可以實現完全自動化的持續部署流程。這篇文章會介紹如何使用 Azure App Service 部署和管理 Web 應用程式,以及透過 GitHub Actions 實現 CI/CD 自動部署。

開發環境
- Windows 11 + WSL2
- ASP .NET Core 10.0
- Azure CLI 2.82.2
- Github CLI 2.76.2
- Azure App Service
什麼是 Azure App Service?
Azure App Service 是一個完全託管的平台即服務 (PaaS),支援多種程式語言和框架:
- .NET / .NET Core:原生支援,效能最佳化
- Java:支援 Tomcat、JBoss 等容器
- Node.js:完整的 npm 套件支援
- Python:Django、Flask 等框架
- PHP:Laravel、WordPress 等應用
主要特點:
- 自動縮放:根據流量自動調整資源
- 高可用性:內建負載平衡和容錯移轉
- 持續部署:整合 GitHub Actions、Azure DevOps
- 內建監控:Application Insights 即時監控
- 安全性:SSL/TLS、認證授權、防火牆
建立 App Service 的三個步驟
接下來會用到 Azure CLI / Github CLI 開始前分別使用以下指令登入
# github cli
gh auth login
# azure cli
az login步驟 1️⃣ 建立 App Service Plan
App Service Plan 定義了運算資源的規格,類似虛擬主機的方案。
# 建立資源群組
az group create \
--name Lab \
--location eastasia
# 建立 App Service Plan
az appservice plan create \
--name web-app \
--resource-group Lab \
--sku B1 \
--is-linux
SKU 等級:
| SKU | 用途 | 特色 |
|---|---|---|
| F1 (Free) | 開發測試 | 免費,共享資源 |
| B1 (Basic) | 小型應用 | 基本功能,固定費用 |
| S1 (Standard) | 生產環境 | 自動縮放、備份 |
| P1V3 (Premium) | 高效能應用 | 更多記憶體、效能 |
步驟 2️⃣ 建立 Web App
# 建立 ASP.NET Core 應用
az webapp create \
--resource-group Lab \
--plan web-app \
--name azure-web-app-api \
--runtime "DOTNETCORE:10.0"
常用 Runtime:
"DOTNETCORE:10.0"- .NET 10"NODE:20-lts"- Node.js 20 LTS"PYTHON:3.12"- Python 3.12"JAVA:17-java17"- Java 17
步驟 3️⃣ 部署應用程式
有三種部署方式:
方式 A:本機手動部署
# 發佈應用程式到指定目錄
dotnet publish AspNetCoreApp/AspNetCoreApp.csproj \
--configuration Release \
--output ./publish-local \
--force
# 進入發佈目錄並建立 ZIP(重要:ZIP 結構要正確)
cd ./publish-local
zip -r ../publish-local.zip .
cd ..
# 部署到 Azure
az webapp deploy \
--resource-group Lab \
--name azure-web-app-api \
--src-path ./publish-local.zip \
--type zip
為什麼 ZIP 結構重要?
ZIP 內應該直接包含 *.dll、appsettings.json 等檔案,而不是嵌套在 publish-local/ 目錄內。
方式 B:GitHub Actions 自動部署(推薦)
這是最推薦的方式,能實現持續部署 (CI/CD)。詳見下一章節 GitHub Actions 持續部署。
方式 C:Azure CLI 快速部署
# 從本機資料夾直接部署
az webapp up \
--name azure-web-app-api \
--resource-group Lab \
--runtime "DOTNETCORE:10.0"
GitHub Actions 持續部署
GitHub Actions 讓你能自動化從代碼到部署的整個過程。每次 push 到 main 分支,都會自動編譯、測試、打包並部署到 Azure App Service。
架構流程
┌─────────────────┐
│ git push main │
└────────┬────────┘
│
v
┌─────────────────────────────┐
│ GitHub Actions Triggered │
└────────┬────────────────────┘
│
┌────────┴─────────────────────────────┐
│ │
v v
┌──────────────────────┐ ┌───────────────┐
│ Build Stage │ │ Publish │
│ - Checkout code │ │ - ZIP files │
│ - Setup .NET 10.0 │──────────┤ - Ready │
│ - dotnet restore │ │ for │
│ - dotnet build │ │ deploy │
│ - dotnet publish │ └───────┬───────┘
└──────────────────────┘ │
v
┌──────────────────────────┐
│ Deploy to Azure │
│ - Azure CLI login │
│ - Upload ZIP │
│ - App Service restart │
└──────────────────────────┘
設定步驟
步驟 1️⃣ 建立 Service Principal
Service Principal 是一個特殊的 Azure 帳戶,用於自動化任務的認證。
# 建立 Service Principal 並取得憑證
az ad sp create-for-rbac \
--name "github-actions-azure-web-app" \
--role contributor \
--scopes /subscriptions/$(az account show --query id -o tsv)/resourceGroups/Lab \
--sdk-auth
輸出範例如下:
{
"clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"clientSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"subscriptionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
"resourceManagerEndpointUrl": "https://management.azure.com/",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
⚠️ 安全提醒:這個 JSON 檔案包含敏感憑證,絕對不要納入版控!
步驟 2️⃣ 設定 GitHub Secret
GitHub Secrets 存放機敏資訊(如憑證),GitHub Actions 可以在執行時安全地存取。
方式 A:使用 GitHub Web UI
- 進入 GitHub 倉庫
- 點擊 Settings → Secrets and variables → Actions
- 點擊 New repository secret
- 名稱:
AZURE_CREDENTIALS - 值:貼上上一步輸出的完整 JSON
- 點擊 Add secret
方式 B:使用 GitHub CLI
# 將憑證保存到臨時檔案
az ad sp create-for-rbac \
--name "github-actions-azure-web-app" \
--role contributor \
--scopes /subscriptions/$(az account show --query id -o tsv)/resourceGroups/Lab \
--sdk-auth > /tmp/azure-creds.json
# 設定為 GitHub Secret
gh secret set AZURE_CREDENTIALS \
--repo yaochangyu/azure-web-app \
< /tmp/azure-creds.json
# 安全地刪除本地憑證檔案
rm /tmp/azure-creds.json
步驟 3️⃣ 建立 Workflow 檔案
在專案根目錄建立 .github/workflows/deploy.yml:
name: Deploy to Azure App Service
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 步驟 1:檢出程式碼
- uses: actions/checkout@v4
# 步驟 2:設置 .NET 環境
- name: Setup .NET 10.0
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
# 步驟 3:恢復依賴
- name: Restore dependencies
run: dotnet restore AspNetCoreApp/AspNetCoreApp.csproj
# 步驟 4:編譯專案
- name: Build
run: dotnet build AspNetCoreApp/AspNetCoreApp.csproj --configuration Release --no-restore
# 步驟 5:發佈專案
- name: Publish
run: dotnet publish AspNetCoreApp/AspNetCoreApp.csproj --configuration Release --output ${{ github.workspace }}/publish --no-build
# 步驟 6:建立 ZIP 部署包
- name: Create deployment package
run: |
cd ${{ github.workspace }}/publish
zip -r ../app-deployment.zip .
cd ..
# 步驟 7:使用 Azure CLI 登入
- name: Azure CLI login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
# 步驟 8:部署到 Azure App Service
- name: Deploy to Azure App Service
run: |
az webapp deploy \
--resource-group Lab \
--name azure-web-app-api \
--src-path app-deployment.zip \
--type zip
# 步驟 9:記錄部署狀態
- name: Check deployment status
run: |
az webapp show \
--resource-group Lab \
--name azure-web-app-api \
--query "state"
步驟 4️⃣ 觸發自動部署
推送程式碼到 main 分支時,GitHub Actions 會自動執行:
# 進行代碼修改
echo "# Updated" >> README.md
# 提交並推送
git add .
git commit -m "chore: update README"
git push origin main
透過沒有任何異動的 commit 發動部署
git commit --allow-empty -m "Trigger deployment"
git push
監控部署
取得目前正在運行的 action
gh run watch
實時查看部署狀態
- 進入 GitHub 倉庫
- 點擊 Actions 標籤
- 查看最新的工作流運行
- 點擊具體工作流查看詳細步驟
運行中 🟡 → 成功 🟢 → 應用已部署到 Azure
查看部署日誌
# 查看部署日誌
az webapp deployment source show --resource-group Lab --name azure-web-app-api
# 回傳結果
{
"branch": null,
"deploymentRollbackEnabled": false,
"gitHubActionConfiguration": null,
"id": "/subscriptions/63eaf14f-00fa-434d-8ae7-069e0f03b25a/resourceGroups/Lab/providers/Microsoft.Web/sites/azure-web-app-api/sourcecontrols/web",
"isGitHubAction": false,
"isManualIntegration": false,
"isMercurial": false,
"kind": null,
"location": "Central US",
"name": "azure-web-app-api",
"repoUrl": null,
"resourceGroup": "Lab",
"type": "Microsoft.Web/sites/sourcecontrols"
}
查看最近的部署
# 查看最近的部署
az rest --method get \
--uri "/subscriptions/63eaf14f-00fa-434d-8ae7-069e0f03b25a/resourceGroups/Lab/providers/Microsoft.Web/sites/azure-web-app-api/deployments?api-version=2022-03-01" \
--query "value[0].properties.[id, status, end_time]"
# 回傳結果
{
"id": "/subscriptions/63eaf14f-00fa-434d-8ae7-069e0f03b25a/resourceGroups/Lab/providers/Microsoft.Web/sites/azure-web-app-api/deployments/22f8bb55-0e65-451b-821f-6efe8c4a1452",
"location": "Central US",
"name": "azure-web-app-api/22f8bb55-0e65-451b-821f-6efe8c4a1452",
"properties": {
"active": true,
"author": "N/A",
"author_email": "N/A",
"build_summary": {
"errors": [],
"warnings": []
},
"complete": true,
"deployer": "OneDeploy",
"end_time": "2026-01-31T06:56:48.7623942Z",
"id": "22f8bb55-0e65-451b-821f-6efe8c4a1452",
"is_readonly": true,
"is_temp": false,
"last_success_end_time": "2026-01-31T06:56:48.7623942Z",
"log_url": "https://azure-web-app-api.scm.azurewebsites.net/api/deployments/22f8bb55-0e65-451b-821f-6efe8c4a1452/log",
"message": "OneDeploy",
"progress": "",
"received_time": "2026-01-31T06:56:42.4360886Z",
"site_name": "azure-web-app-api",
"start_time": "2026-01-31T06:56:43.8932073Z",
"status": 4,
"status_text": "",
"url": "https://azure-web-app-api.scm.azurewebsites.net/api/deployments/22f8bb55-0e65-451b-821f-6efe8c4a1452"
},
"type": "Microsoft.Web/sites/deployments"
}
查看應用程式的即時日誌
# 查看應用程式的即時日誌
az webapp log tail \
--resource-group Lab \
--name azure-web-app-api
# 回傳結果
2026-01-31T13:57:29 Welcome, you are now connected to log-streaming service.
Starting Log Tail -n 10 of existing logs ----
/appsvctmp/volatile/logs/runtime/container.log
2026-01-31T06:57:45.9165096Z info: Microsoft.Hosting.Lifetime[14]
2026-01-31T06:57:45.9165758Z Now listening on: http://[::]:8080
2026-01-31T06:57:45.9269065Z info: Microsoft.Hosting.Lifetime[0]
2026-01-31T06:57:45.9269597Z Application started. Press Ctrl+C to shut down.
2026-01-31T06:57:45.9356962Z info: Microsoft.Hosting.Lifetime[0]
2026-01-31T06:57:45.9357243Z Hosting environment: Production
2026-01-31T06:57:45.9361160Z info: Microsoft.Hosting.Lifetime[0]
2026-01-31T06:57:45.9361353Z Content root path: /home/site/wwwroot
2026-01-31T06:57:47.1606237Z warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
2026-01-31T06:57:47.1606935Z Failed to determine the https port for redirect.
Ending Log Tail of existing logs ---
Starting Live Log Stream ---
檢視應用程式記錄
啟用應用程式記錄
# 啟用檔案系統記錄
az webapp log config \
--resource-group Lab \
--name azure-web-app-api \
--application-logging filesystem \
--level information
# 即時串流記錄
az webapp log tail \
--resource-group Lab \
--name azure-web-app-api
整合 Application Insights
Application Insights 可以監控應用程式效能、追蹤例外狀況。
# 啟用 Application Insights
az monitor app-insights component create \
--app azure-web-app-insights \
--location eastasia \
--resource-group Lab
# 取得 Instrumentation Key
az monitor app-insights component show \
--app azure-web-app-insights \
--resource-group Lab \
--query instrumentationKey
在 appsettings.json 加入:
{
"ApplicationInsights": {
"InstrumentationKey": "your-instrumentation-key"
}
}
調整效能與擴展
垂直擴展 (Scale Up)
升級 App Service Plan 的等級:
# 升級到 Standard S1
az appservice plan update \
--name web-app \
--resource-group Lab \
--sku S1
水平擴展 (Scale Out)
增加執行個體數量:
# 手動擴展到 3 個執行個體
az appservice plan update \
--name web-app \
--resource-group Lab \
--number-of-workers 3
自動擴展規則
# 建立自動擴展設定(需要 Standard 以上)
az monitor autoscale create \
--resource-group Lab \
--resource web-app \
--resource-type Microsoft.Web/serverfarms \
--name auto-scale-plan \
--min-count 1 \
--max-count 5 \
--count 2
# 新增 CPU 使用率規則
az monitor autoscale rule create \
--resource-group Lab \
--autoscale-name auto-scale-plan \
--condition "Percentage CPU > 70 avg 5m" \
--scale out 1
設定自訂網域與 SSL
新增自訂網域
# 新增自訂網域
az webapp config hostname add \
--resource-group Lab \
--webapp-name azure-web-app-api \
--hostname www.example.com
在 DNS 設定中新增 CNAME 記錄:
www.example.com → azure-web-app-api.azurewebsites.net
啟用 SSL 憑證
# 建立免費的 App Service Managed Certificate
az webapp config ssl bind \
--resource-group Lab \
--name azure-web-app-api \
--certificate-thumbprint auto \
--ssl-type SNI
# 強制使用 HTTPS
az webapp update \
--resource-group Lab \
--name azure-web-app-api \
--set httpsOnly=true
設定部署位置 (Deployment Slots)
部署位置讓你可以在不影響生產環境的情況下測試新版本。
# 建立 staging 位置
az webapp deployment slot create \
--resource-group Lab \
--name azure-web-app-api \
--slot staging
# 部署到 staging
az webapp deploy \
--resource-group Lab \
--name azure-web-app-api \
--slot staging \
--src-path app.zip \
--type zip
# 驗證無誤後,交換到生產環境
az webapp deployment slot swap \
--resource-group Lab \
--name azure-web-app-api \
--slot staging \
--target-slot production
優點:
- 零停機時間部署
- 快速回滾機制
- A/B 測試流量分流
監控與診斷
健康檢查
在 Program.cs 新增健康檢查端點:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/health");
app.Run();
在 Azure 設定健康檢查:
az webapp config set \
--resource-group Lab \
--name azure-web-app-api \
--health-check-path "/health"
效能監控
使用 Application Insights 儀表板:
- 開啟 Azure Portal
- 前往 Application Insights
- 檢視效能、失敗請求、相依性
或使用 Azure Monitor Metrics:
# 檢視 CPU 使用率
az monitor metrics list \
--resource /subscriptions/{subscription-id}/resourceGroups/Lab/providers/Microsoft.Web/sites/azure-web-app-api \
--metric "CpuPercentage" \
--start-time 2026-01-31T00:00:00Z \
--end-time 2026-01-31T23:59:59Z
安全性最佳實踐
1. 使用 Managed Identity
避免在程式碼中硬編碼憑證:
# 啟用系統指派的受控識別
az webapp identity assign \
--resource-group Lab \
--name azure-web-app-api
2. 設定 IP 限制
# 只允許特定 IP 存取
az webapp config access-restriction add \
--resource-group Lab \
--name azure-web-app-api \
--rule-name AllowOfficeIP \
--action Allow \
--ip-address 203.0.113.0/24 \
--priority 100
3. 啟用診斷記錄
az webapp log config \
--resource-group Lab \
--name azure-web-app-api \
--web-server-logging filesystem \
--detailed-error-messages true \
--failed-request-tracing true
4. 定期更新 Runtime
保持 .NET、Node.js 等 runtime 在最新的安全版本。
心得
Azure App Service 搭配 GitHub Actions,提供了完整的 PaaS 解決方案和自動化部署流程,佈署的過程輕鬆、簡單。
實作的過程中搭配 Github MCP + Azure MCP,更是大幅縮短時間。
範例位置
本文完整範例程式碼與配置:
https://github.com/yaochangyu/azure-web-app
參考資料
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET