Buy Me a Coffee

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.0nvm install 18.17.0Next.js 開發環境
.NET SDK>= 8.0.0官網下載安裝包後端 API 開發
Docker Desktop最新版官網下載安裝包容器化環境
Azure CLI>= 2.50.0curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bashAzure 管理工具

環境安裝指令

# 安裝 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 前端專案設定

  1. 建立專案
# 創建 Next.js 專案
npx create-next-app@latest frontend --typescript --tailwind --eslint
cd frontend

# 安裝必要依賴
npm install @azure/storage-blob axios swr react-query
  1. 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"]
  1. 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 後端專案設定

  1. 建立專案
# 創建解決方案和專案
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
  1. 後端 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"]
  1. 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"

效能優化建議

前端優化

  1. 實作緩存策略
// 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
  1. 配置圖片最佳化
// 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'],
  },
}

後端優化

  1. 實作 Response 壓縮
// Program.cs
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

app.UseResponseCompression();
  1. 實作快取機制
// 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 已啟用

延伸閱讀 📚

  1. Azure App Service 文檔
  2. Next.js 部署指南
  3. .NET Core 最佳實踐
  4. Docker 最佳實踐

小測驗 🤔

  1. 為什麼要使用多階段 Docker 建置?
  2. Azure Storage 的不同類型有什麼差異?
  3. 如何選擇適合的 App Service 方案?
  4. 自動擴展規則應該如何設定?

期待聽到您的想法與經驗分享!如果您有任何問題,歡迎在下方留言討論。 💬