2024 Azure 全端開發與部署完整指南:從本地開發到雲端部署
引言 🎯
在現代雲端開發環境中,建立一個完整的全端應用系統需要整合多種技術和工具。本指南將帶您從開發環境設定開始,一步步實現前後端開發、容器化,最後部署至 Azure 雲端平台。無論您是經驗豐富的開發者還是正在學習的新手,這份完整指南都能幫助您掌握整個開發部署流程。
系統架構概觀
讓我們先了解整個系統的架構設計:
graph TB
subgraph "本地開發環境"
A[Next.js 前端] --> B[Docker Container]
C[.NET API] --> D[Docker Container]
E[Local Storage] --> F[Docker Volume]
end
subgraph "Azure 雲端環境"
G[Azure Container Registry] --> H[App Service - Frontend]
G --> I[App Service - Backend]
J[Azure Storage] --> H
J --> I
K[Azure SQL] --> I
L[Azure Monitor] --> H
L --> I
end
B --> G
D --> G
開發環境設定與準備
必要工具安裝
首先,我們需要安裝並設定以下開發工具:
工具名稱 | 版本需求 | 安裝命令 | 用途說明 |
---|---|---|---|
Node.js | >= 18.17.0 | nvm install 18.17.0 | Next.js 開發環境 |
.NET SDK | >= 8.0.0 | 官網下載安裝包 | 後端 API 開發 |
Docker Desktop | 最新版 | 官網下載安裝包 | 容器化環境 |
Azure CLI | >= 2.50.0 | curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash | Azure 管理工具 |
環境安裝指令
# 安裝 Node.js (使用 nvm)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
nvm install 18.17.0
nvm use 18.17.0
# 安裝 .NET SDK (Ubuntu)
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y dotnet-sdk-8.0
# 安裝 Docker (Ubuntu)
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
專案建置
Next.js 前端專案設定
- 建立專案
# 創建 Next.js 專案
npx create-next-app@latest frontend --typescript --tailwind --eslint
cd frontend
# 安裝必要依賴
npm install @azure/storage-blob axios swr react-query
- Next.js Dockerfile
# 建置階段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 執行階段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/server ./.next/server
EXPOSE 3000
ENV PORT 3000
ENV NODE_ENV production
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
- Next.js 環境設定
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
images: {
domains: ['your-storage-account.blob.core.windows.net'],
},
env: {
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
AZURE_STORAGE_CONNECTION_STRING: process.env.AZURE_STORAGE_CONNECTION_STRING,
}
}
module.exports = nextConfig
.NET 後端專案設定
- 建立專案
# 創建解決方案和專案
dotnet new sln -n BackendApi
dotnet new webapi -n BackendApi.Web
dotnet sln add BackendApi.Web/BackendApi.Web.csproj
cd BackendApi.Web
# 安裝必要套件
dotnet add package Azure.Storage.Blobs
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.ApplicationInsights.AspNetCore
- 後端 Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["BackendApi.Web/BackendApi.Web.csproj", "BackendApi.Web/"]
RUN dotnet restore "BackendApi.Web/BackendApi.Web.csproj"
COPY . .
WORKDIR "/src/BackendApi.Web"
RUN dotnet build "BackendApi.Web.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "BackendApi.Web.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "BackendApi.Web.dll"]
- Azure Storage 整合
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 添加 Azure Blob Storage 服務
builder.Services.AddSingleton(x =>
new BlobServiceClient(
builder.Configuration.GetConnectionString("AzureStorage")));
// 添加 CORS 政策
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
app.UseCors("AllowAll");
Docker Compose 開發環境
建立 docker-compose.yml
檔案用於本地開發:
version: '3.8'
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NEXT_PUBLIC_API_URL=http://localhost:5000
volumes:
- ./frontend:/app
- /app/node_modules
- /app/.next
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "5000:80"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__AzureStorage=${AZURE_STORAGE_CONNECTION_STRING}
volumes:
- ./backend:/app
Azure 資源部署
基本資源建立
# 設定變數
$RG_NAME="my-fullstack-app"
$LOCATION="japaneast"
$ACR_NAME="myfullstackacr"
$STORAGE_NAME="myfullstackstorage"
$FRONTEND_APP_NAME="frontend-app"
$BACKEND_APP_NAME="backend-app"
# 建立資源群組
az group create --name $RG_NAME --location $LOCATION
# 建立 Container Registry
az acr create \
--resource-group $RG_NAME \
--name $ACR_NAME \
--sku Basic \
--admin-enabled true
# 建立 Storage Account
az storage account create \
--name $STORAGE_NAME \
--resource-group $RG_NAME \
--location $LOCATION \
--sku Standard_LRS \
--kind StorageV2
# 建立 File Share
az storage share create \
--name appdata \
--account-name $STORAGE_NAME \
--quota 100
App Service 設定
# 建立 App Service Plan
az appservice plan create \
--name fullstack-plan \
--resource-group $RG_NAME \
--is-linux \
--sku P1V2
# 建立前端 Web App
az webapp create \
--resource-group $RG_NAME \
--plan fullstack-plan \
--name $FRONTEND_APP_NAME \
--deployment-container-image-name $ACR_NAME.azurecr.io/frontend:latest
# 建立後端 Web App
az webapp create \
--resource-group $RG_NAME \
--plan fullstack-plan \
--name $BACKEND_APP_NAME \
--deployment-container-image-name $ACR_NAME.azurecr.io/backend:latest
儲存體掛載設定
# 取得儲存帳戶金鑰
$STORAGE_KEY=$(az storage account keys list \
--resource-group $RG_NAME \
--account-name $STORAGE_NAME \
--query "[0].value" \
--output tsv)
# 前端掛載儲存體
az webapp config storage-account add \
--resource-group $RG_NAME \
--name $FRONTEND_APP_NAME \
--custom-id frontend-storage \
--storage-type AzureFiles \
--share-name appdata \
--account-name $STORAGE_NAME \
--access-key $STORAGE_KEY \
--mount-path /data
# 後端掛載儲存體
az webapp config storage-account add \
--resource-group $RG_NAME \
--name $BACKEND_APP_NAME \
--custom-id backend-storage \
--storage-type AzureFiles \
--share-name appdata \
--account-name $STORAGE_NAME \
--access-key $STORAGE_KEY \
--mount-path /data
部署流程
容器映像建置與推送
# 登入 ACR
az acr login --name $ACR_NAME
# 建置並推送前端映像
docker build -t $ACR_NAME.azurecr.io/frontend:latest ./frontend
docker push $ACR_NAME.azurecr.io/frontend:latest
# 建置並推送後端映像
docker build -t $ACR_NAME.azurecr.io/backend:latest ./backend
docker push $ACR_NAME.azurecr.io/backend:latest
應用程式設定更新
# 更新前端環境變數
az webapp config appsettings set \
--resource-group $RG_NAME \
--name $FRONTEND_APP_NAME \
--settings \
NEXT_PUBLIC_API_URL="https://$BACKEND_APP_NAME.azurewebsites.net" \
AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=$STORAGE_NAME;AccountKey=$STORAGE_KEY;EndpointSuffix=core.windows.net"
# 更新後端環境變數
az webapp config appsettings set \
--resource-group $RG_NAME \
--name $BACKEND_APP_NAME \
--settings \
ASPNETCORE_ENVIRONMENT="Production" \
ConnectionStrings__AzureStorage="DefaultEndpointsProtocol=https;AccountName=$STORAGE_NAME;AccountKey=$STORAGE_KEY;EndpointSuffix=core.windows.net"
監控與維護
設定 Application Insights
# 建立 Application Insights
az monitor app-insights component create \
--app fullstack-insights \
--location $LOCATION \
--resource-group $RG_NAME \
--application-type web
# 取得 Instrumentation Key
$INSTRUMENTATION_KEY=$(az monitor app-insights component show \
--app fullstack-insights \
--resource-group $RG_NAME \
--query instrumentationKey \
--output tsv)
# 更新應用程式設定
az webapp config appsettings set \
--resource-group $RG_NAME \
--name $BACKEND_APP_NAME \
--settings APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=$INSTRUMENTATION_KEY"
效能優化建議
前端優化
- 實作緩存策略
// pages/_app.tsx
import { SWRConfig } from 'swr'
function MyApp({ Component, pageProps }) {
return (
<SWRConfig
value={{
fetcher: (url) => fetch(url).then(r => r.json()),
revalidateOnFocus: false,
revalidateOnReconnect: false
}}
>
<Component {...pageProps}/>
</SWRConfig>
)
}
export default MyApp
- 配置圖片最佳化
// next.config.js 補充配置
const nextConfig = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
domains: ['your-storage-account.blob.core.windows.net'],
formats: ['image/webp'],
},
}
後端優化
- 實作 Response 壓縮
// Program.cs
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
});
app.UseResponseCompression();
- 實作快取機制
// Program.cs
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
options.InstanceName = "FullStackApp_";
});
故障排除指南 🔧
常見問題診斷流程
flowchart TD
A[發現問題] --> B{網站可訪問?}
B -- 否 --> C[檢查部署狀態]
B -- 是 --> D{效能問題?}
C --> E[檢查日誌]
C --> F[檢查網路配置]
D --> G[檢查資源使用率]
D --> H[檢查後端回應時間]
G --> I[調整資源配置]
H --> J[優化資料庫查詢]
常見問題與解決方案
問題類型 | 可能原因 | 診斷方法 | 解決方案 |
---|---|---|---|
部署失敗 | Docker 映像問題 | 查看 ACR 日誌 | 重新建置映像 |
502 錯誤 | 應用程式崩潰 | 查看應用程式日誌 | 檢查錯誤堆疊 |
效能緩慢 | 資源不足 | 監控資源使用率 | 擴增實例或升級方案 |
儲存體錯誤 | 權限問題 | 檢查連線字串 | 更新存取金鑰 |
日誌查詢命令
# 查看 Web App 日誌
az webapp log tail \
--resource-group $RG_NAME \
--name $APP_NAME \
--provider http
# 查看容器日誌
az webapp log container \
--resource-group $RG_NAME \
--name $APP_NAME
# 下載診斷日誌
az webapp log download \
--resource-group $RG_NAME \
--name $APP_NAME
安全性設定 🔐
SSL 設定
# 建立 SSL 憑證
az webapp config ssl create \
--resource-group $RG_NAME \
--name $APP_NAME \
--hostname "your-domain.com"
# 綁定 SSL 憑證
az webapp config ssl bind \
--resource-group $RG_NAME \
--name $APP_NAME \
--certificate-thumbprint $CERT_THUMBPRINT
網路安全設定
# 設定 IP 限制
az webapp config access-restriction add \
--resource-group $RG_NAME \
--name $APP_NAME \
--rule-name "AllowVPN" \
--action Allow \
--ip-address "203.0.113.0/24" \
--priority 100
# 啟用 WAF
az network application-gateway waf-policy create \
--resource-group $RG_NAME \
--name fullstack-waf \
--mode Prevention
自動化部署流程 🚀
GitHub Actions 工作流程
# .github/workflows/deploy.yml
name: Deploy to Azure
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Build and Push Frontend
run: |
docker build -t ${{ secrets.ACR_NAME }}.azurecr.io/frontend:${{ github.sha }} ./frontend
docker push ${{ secrets.ACR_NAME }}.azurecr.io/frontend:${{ github.sha }}
- name: Build and Push Backend
run: |
docker build -t ${{ secrets.ACR_NAME }}.azurecr.io/backend:${{ github.sha }} ./backend
docker push ${{ secrets.ACR_NAME }}.azurecr.io/backend:${{ github.sha }}
- name: Deploy to Azure Web App
uses: azure/webapps-deploy@v2
with:
app-name: ${{ secrets.FRONTEND_APP_NAME }}
images: ${{ secrets.ACR_NAME }}.azurecr.io/frontend:${{ github.sha }}
效能監控與擴展 📊
設定自動擴展規則
# 設定 CPU 使用率自動擴展
az monitor autoscale create \
--resource-group $RG_NAME \
--name autoscale-cpu \
--resource frontend-app \
--min-count 1 \
--max-count 5 \
--count 1
# 新增 CPU 規則
az monitor autoscale rule create \
--resource-group $RG_NAME \
--autoscale-name autoscale-cpu \
--condition "CPU Percentage > 75 avg 5m" \
--scale out 1
監控儀表板設定
# 建立自訂儀表板
az portal dashboard create \
--resource-group $RG_NAME \
--name fullstack-dashboard \
--location $LOCATION \
--dashboard-path dashboard.json
總結與最佳實踐 ✨
部署檢查清單
- 環境變數配置完整
- SSL 憑證設定正確
- 監控告警已配置
- 備份策略已實施
- 安全性掃描已完成
- 效能測試已執行
- 日誌收集已設定
- 自動擴展規則已配置
效能優化檢查清單
- 靜態資源已配置 CDN
- 資料庫查詢已優化
- 映像檔大小已最小化
- 快取策略已實施
- Gzip 壓縮已啟用
- HTTP/2 已啟用
延伸閱讀 📚
小測驗 🤔
- 為什麼要使用多階段 Docker 建置?
- Azure Storage 的不同類型有什麼差異?
- 如何選擇適合的 App Service 方案?
- 自動擴展規則應該如何設定?
期待聽到您的想法與經驗分享!如果您有任何問題,歡迎在下方留言討論。 💬