將Azure App 服務部署至Azure App 服務

在本教學課程中,您將瞭解如何將一個Azure App 服務部署至Azure App 服務。 本教學課程會逐步引導您完成支援下列功能的範例應用程式:

  • 購物車:一個簡單的購物車應用程式,其會針對其跨平臺架構支援,以及其可調整的分散式應用程式功能使用一種。

    • 庫存管理:編輯和/或建立產品清查。
    • 商店庫存:探索可購買的產品,並將其新增至購物車。
    • 購物車:檢視購物車中所有專案的摘要,並管理這些專案;移除或變更每個專案的數量。

透過瞭解應用程式和其功能,您將瞭解如何使用 GitHub Actions、.NET 和 Azure CLI 和 Azure Bicep 將應用程式部署至Azure App 服務。 此外,您將瞭解如何在 Azure 中設定應用程式的虛擬網路。

在本教學課程中,您會了解如何:

  • 將Azure App 服務部署至Azure App 服務
  • 使用 GitHub Actions 和 Azure Bicep 將部署自動化
  • 在 Azure 中設定應用程式的虛擬網路

必要條件

在本機執行應用程式

若要在本機執行應用程式,請將Azure 範例:Azure App 服務 存放庫上的「Azure 範例:在Azure App 服務叢集」分支,並將其複製到本機電腦。 複製之後,請在您選擇的 IDE 中開啟解決方案。 如果您使用 Visual Studio,請以滑鼠右鍵按一下 [一般] .ShoppingCart.Silo 專案,然後選取 [ 設定為啟始專案],然後執行應用程式。 否則,您可以使用下列 .NET CLI 命令來執行應用程式:

dotnet run --project Silo\Orleans.ShoppingCart.Silo.csproj

如需詳細資訊,請參閱 dotnet run。 執行應用程式後,您可以流覽並自由地測試其功能。 在本機執行時,所有應用程式的功能都依賴記憶體內部持續性、本機叢集,並使用 Bogus NuGet 套件來產生假產品。 在 Visual Studio 中選取 [停止偵錯] 選項,或在 .NET CLI 中按Ctrl+C來停止應用程式。

購物車應用程式內部

此為可靠且可調整的架構,可用於建置分散式應用程式。 在本教學課程中,您將部署一個簡單的購物車應用程式,其建置方式為Azure App 服務。 應用程式會公開管理庫存、新增和移除購物車中的專案,以及商店可用產品的能力。 用戶端是使用 Blazor 搭配伺服器裝載模型所建置。 應用程式架構如下:

布建:購物車範例應用程式架構。

上圖顯示用戶端是伺服器端 Blazor 應用程式。 它是由數個取用對應之擷取粒紋的服務所組成。 每個服務會與一個質地粒紋配對,如下所示:

  • InventoryService:取 IInventoryGrain 用依產品類別分割庫存的位置。
  • ProductService:使用將 IProductGrain 單一產品系結至單一細微性實例的 Id
  • ShoppingCartService:取用 IShoppingCartGrain 單一使用者只擁有單一購物車實例,而不論取用用戶端為何。

方案包含三個專案:

  • Orleans.ShoppingCart.Abstractions:定義應用程式的模型和介面的類別庫。
  • Orleans.ShoppingCart.Grains:類別庫,定義實作應用程式商務邏輯的細微性。
  • Orleans.ShoppingCart.Silos:裝載一個在月臺定址接收器的伺服器端 Blazor 應用程式。

用戶端使用者體驗

購物車用戶端應用程式有數個頁面,每個頁面都代表不同的使用者體驗。 應用程式的 UI 是使用 「檔案」套件 來建置。

首頁

一些簡單的片語可供使用者瞭解應用程式的用途,並將內容新增至每個導覽功能表項目。

布建:購物車範例應用程式、首頁。

商店庫存頁面

頁面,顯示所有可供購買的產品。 您可以從此頁面將專案新增至購物車。

布建:購物車範例應用程式、商店庫存頁面。

空購物車頁面

當您尚未將任何專案新增至購物車時,頁面會轉譯訊息,指出您的購物車中沒有專案。

聖卡:購物車範例應用程式、空購物車頁面。

在商店庫存頁面上新增至購物車的專案

在商店庫存頁面上將專案新增至購物車時,應用程式會顯示一則訊息,指出專案已新增至購物車。

一般:購物車範例應用程式,在商店庫存頁面上新增至購物車的專案。

產品管理頁面

使用者可以從此頁面管理清查。 產品可以從庫存中新增、編輯和移除。

布建:購物車範例應用程式、產品管理頁面。

產品管理頁面建立新對話方塊

當使用者按一下 [ 建立新產品 ] 按鈕時,應用程式會顯示一個對話方塊,讓使用者能夠建立新產品。

布建:購物車範例應用程式、產品管理頁面 - 建立新產品對話方塊。

購物車頁面中的專案

當您的購物車中專案時,您可以檢視專案並變更其數量,甚至從購物車中移除它們。 使用者會顯示購物車中的專案摘要,以及預售總成本。

一般:購物車範例應用程式、購物車頁面中的專案。

重要

當此應用程式在本機執行時,在開發環境中,應用程式會使用 localhost 叢集、記憶體內部儲存體和本機定址接收器。 它也會使用 使用 Bogus NuGet 套件自動產生的假資料植入清查。 這全都是刻意示範功能。

部署到 Azure App Service

典型的一般 (應用程式是由伺服器進程叢集所組成,) 定址位置,以及一組接收外部要求的用戶端進程,通常是 Web 服務器,將它們轉換成細微性方法呼叫並傳回結果。 因此,第一件事是執行一個擷取應用程式,就是啟動定址接收器的叢集。 為了進行測試,叢集可以包含單一定址接收器。

注意

針對可靠的生產部署,您希望叢集中有多個定址接收器,以進行容錯和調整。

部署應用程式之前,您必須建立 Azure 資源群組 (,或者您可以選擇使用現有的資源群組) 。 若要建立新的 Azure 資源群組,請使用下列其中一篇文章:

請記下您選擇的資源組名,稍後您將需要它才能部署應用程式。

建立服務主體

若要自動部署應用程式,您必須建立服務主體。 這是一個 Microsoft 帳戶,有權代表您管理 Azure 資源。

az ad sp create-for-rbac --sdk-auth --role Contributor \
  --name "<display-name>"  --scopes /subscriptions/<your-subscription-id>

建立的 JSON 認證看起來會類似下列,但具有用戶端、訂用帳戶和租使用者的實際值:

{
  "clientId": "<your client id>",
  "clientSecret": "<your client secret>",
  "subscriptionId": "<your subscription id>",
  "tenantId": "<your tenant id>",
  "activeDirectoryEndpointUrl": "https://login.microsoftonline.com/",
  "resourceManagerEndpointUrl": "https://brazilus.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"
}

將命令的輸出複製到剪貼簿中,並繼續下一個步驟。

建立 GitHub 祕密

GitHub 提供建立加密密碼的機制。 您建立的秘密可用於GitHub Actions工作流程。 您將瞭解如何使用GitHub Actions來自動化應用程式的部署,以及 Azure Bicep 。 Bicep 是網域特定的語言 (DSL) ,會使用宣告式語法來部署 Azure 資源。 如需詳細資訊,請參閱 什麼是 Bicep。 使用建立 服務主體 步驟的輸出,您必須使用 JSON 格式認證來建立名為 AZURE_CREDENTIALS 的 GitHub 秘密。

在 GitHub 存放庫中,選取 [設定>秘密>] [建立新的秘密]。 輸入名稱 AZURE_CREDENTIALS ,並將上一個步驟中的 JSON 認證貼到 [值 ] 欄位中。

GitHub 存放庫:設定 > 秘密

如需詳細資訊,請參閱 GitHub:加密的秘密

準備 Azure 部署

應用程式必須封裝以進行部署。 在 Orleans.ShoppingCart.Silos 專案中,我們會定義在 Target 步驟之後 Publish 執行的 元素。 這會將發行目錄壓縮成 silo.zip 檔案:

<Target Name="ZipPublishOutput" AfterTargets="Publish">
    <Delete Files="$(ProjectDir)\..\silo.zip" />
    <ZipDirectory SourceDirectory="$(PublishDir)" DestinationFile="$(ProjectDir)\..\silo.zip" />
</Target>

有許多方式可將 .NET 應用程式部署至 Azure App 服務。 在本教學課程中,您會使用 GitHub Actions、Azure Bicep 和 .NET 和 Azure CLI。 請考慮 GitHub 存放庫根目錄中 的 ./github/workflows/deploy.yml 檔案:

name: Deploy to Azure App Service

on:
  push:
    branches:
    - main

env:
  UNIQUE_APP_NAME: cartify
  AZURE_RESOURCE_GROUP_NAME: orleans-resourcegroup
  AZURE_RESOURCE_GROUP_LOCATION: centralus

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Setup .NET 7.0
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 7.0.x

    - name: .NET publish shopping cart app
      run: dotnet publish ./Silo/Orleans.ShoppingCart.Silo.csproj --configuration Release

    - name: Login to Azure
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}
    
    - name: Flex bicep
      run: |
        az deployment group create \
          --resource-group ${{ env.AZURE_RESOURCE_GROUP_NAME }} \
          --template-file '.github/workflows/flex/main.bicep' \
          --parameters location=${{ env.AZURE_RESOURCE_GROUP_LOCATION }} \
            appName=${{ env.UNIQUE_APP_NAME }} \
          --debug

    - name: Webapp deploy
      run: |
        az webapp deploy --name ${{ env.UNIQUE_APP_NAME }} \
          --resource-group ${{ env.AZURE_RESOURCE_GROUP_NAME  }} \
          --clean true --restart true \
          --type zip --src-path silo.zip --debug

    - name: Staging deploy
      run: |
        az webapp deploy --name ${{ env.UNIQUE_APP_NAME }} \
          --slot ${{ env.UNIQUE_APP_NAME }}stg \
          --resource-group ${{ env.AZURE_RESOURCE_GROUP_NAME  }} \
          --clean true --restart true \
          --type zip --src-path silo.zip --debug

上述 GitHub 工作流程會:

工作流程是由推送至 main 分支所觸發。 如需詳細資訊,請參閱GitHub Actions 和 .NET

提示

如果您在執行工作流程時遇到問題,您可能需要確認服務主體已註冊所有必要的提供者命名空間。 需要下列提供者命名空間:

  • Microsoft.Web
  • Microsoft.Network
  • Microsoft.OperationalInsights
  • Microsoft.Insights
  • Microsoft.Storage

如需詳細資訊,請參閱 解決資源提供者註冊的錯誤

Azure 會對資源施加命名限制和慣例。 您需要更新下列專案的 deploy.yml 檔案值:

  • UNIQUE_APP_NAME
  • AZURE_RESOURCE_GROUP_NAME
  • AZURE_RESOURCE_GROUP_LOCATION

將這些值設定為唯一的應用程式名稱和您的 Azure 資源組名和位置。

如需詳細資訊,請參閱 Azure 資源的命名規則和限制

探索 Bicep 範本

az deployment group create當命令執行時,它會評估main.bicep檔案。 此檔案包含您想要部署的 Azure 資源。 若要思考此步驟,其中一種方式是它會 建所有資源以進行部署。

重要

如果您使用 Visual Studio Code,Bicep 撰寫體驗在使用 Bicep 擴充功能時會改善。

有許多 bicep 檔案,每個檔案都包含資源或模組 (資源集合) 。 main.bicep檔案是進入點,主要是由定義組成 module

param appName string
param location string = resourceGroup().location

module storageModule 'storage.bicep' = {
  name: 'orleansStorageModule'
  params: {
    name: '${appName}storage'
    location: location
  }
}

module logsModule 'logs-and-insights.bicep' = {
  name: 'orleansLogModule'
  params: {
    operationalInsightsName: '${appName}-logs'
    appInsightsName: '${appName}-insights'
    location: location
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2021-05-01' = {
  name: '${appName}-vnet'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '172.17.0.0/16',
        '192.168.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'default'
        properties: {
          addressPrefix: '172.17.0.0/24'
          delegations: [
            {
              name: 'delegation'
              properties: {
                serviceName: 'Microsoft.Web/serverFarms'
              }
            }
          ]
        }
      }
      {
        name: 'staging'
        properties: {
          addressPrefix: '192.168.0.0/24'
          delegations: [
            {
              name: 'delegation'
              properties: {
                serviceName: 'Microsoft.Web/serverFarms'
              }
            }
          ]
        }
      }
    ]
  }
}

module siloModule 'app-service.bicep' = {
  name: 'orleansSiloModule'
  params: {
    appName: appName
    location: location
    vnetSubnetId: vnet.properties.subnets[0].id
    stagingSubnetId: vnet.properties.subnets[1].id
    appInsightsConnectionString: logsModule.outputs.appInsightsConnectionString
    appInsightsInstrumentationKey: logsModule.outputs.appInsightsInstrumentationKey
    storageConnectionString: storageModule.outputs.connectionString
  }
}

上述 bicep 檔案會定義下列專案:

  • 資源組名和應用程式名稱的兩個參數。
  • 定義 storageModule ,定義儲存體帳戶。
  • 定義 logsModule ,定義 Azure Log Analytics 和 Application Insights 資源。
  • 定義 vnet 虛擬網路的資源。
  • 定義 siloModule 定義Azure App 服務。

其中一個非常重要 resource 的是虛擬網路。 資源 vnet 可讓Azure App 服務與Azure App 服務叢集通訊。

每當 module 在 bicep 檔案中遇到 時,就會透過另一個包含資源定義的 bicep 檔案進行評估。 第一個遇到的模組是 storageModule ,其定義于 storage.bicep 檔案中:

param name string
param location string

resource storage 'Microsoft.Storage/storageAccounts@2021-08-01' = {
  name: name
  location: location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
}

var key = listKeys(storage.name, storage.apiVersion).keys[0].value
var protocol = 'DefaultEndpointsProtocol=https'
var accountBits = 'AccountName=${storage.name};AccountKey=${key}'
var endpointSuffix = 'EndpointSuffix=${environment().suffixes.storage}'

output connectionString string = '${protocol};${accountBits};${endpointSuffix}'

Bicep 檔案接受使用 關鍵字宣告的參數 param 。 同樣地,他們也可以使用 關鍵字來宣告輸出 output 。 儲存體 resource 依賴 Microsoft.Storage/storageAccounts@2021-08-01 類型和版本。 它會以 和 Standard_LRS SKU 的形式 StorageV2 布建在資源群組的位置。 儲存體 bicep 會將其連接字串 output 定義為 。 這 connectionString 稍後會由定址接收器 Bicep 用來連線到儲存體帳戶。

接下來, logs-and-insights.bicep 檔案會定義 Azure Log Analytics 和 Application Insights 資源:

param operationalInsightsName string
param appInsightsName string
param location string

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: appInsightsName
  location: location
  kind: 'web'
  properties: {
    Application_Type: 'web'
    WorkspaceResourceId: logs.id
  }
}

resource logs 'Microsoft.OperationalInsights/workspaces@2021-06-01' = {
  name: operationalInsightsName
  location: location
  properties: {
    retentionInDays: 30
    features: {
      searchVersion: 1
    }
    sku: {
      name: 'PerGB2018'
    }
  }
}

output appInsightsInstrumentationKey string = appInsights.properties.InstrumentationKey
output appInsightsConnectionString string = appInsights.properties.ConnectionString

此 bicep 檔案會定義 Azure Log Analytics 和 Application Insights 資源。 資源 appInsightsweb 類型,而 logs 資源是 PerGB2018 類型。 appInsights資源和資源 logs 都會布建在資源群組的位置。 資源 appInsights 會透過 WorkspaceResourceId 屬性連結至 logs 資源。 此 bicep 中定義了兩個輸出,稍後由 App Service module 使用。

最後,app-service.bicep檔案會定義Azure App 服務資源:

param appName string
param location string
param vnetSubnetId string
param stagingSubnetId string
param appInsightsInstrumentationKey string
param appInsightsConnectionString string
param storageConnectionString string

resource appServicePlan 'Microsoft.Web/serverfarms@2021-03-01' = {
  name: '${appName}-plan'
  location: location
  kind: 'app'
  sku: {
    name: 'S1'
    capacity: 1
  }
}

resource appService 'Microsoft.Web/sites@2021-03-01' = {
  name: appName
  location: location
  kind: 'app'
  properties: {
    serverFarmId: appServicePlan.id
    virtualNetworkSubnetId: vnetSubnetId
    httpsOnly: true
    siteConfig: {
      vnetPrivatePortsCount: 2
      webSocketsEnabled: true
      netFrameworkVersion: 'v6.0'
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: appInsightsInstrumentationKey
        }
        {
          name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
          value: appInsightsConnectionString
        }
        {
          name: 'ORLEANS_AZURE_STORAGE_CONNECTION_STRING'
          value: storageConnectionString
        }
        {
          name: 'ORLEANS_CLUSTER_ID'
          value: 'Default'
        }
      ]
      alwaysOn: true
    }
  }
}

resource stagingSlot 'Microsoft.Web/sites/slots@2022-03-01' = {
  name: '${appName}stg'
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    virtualNetworkSubnetId: stagingSubnetId
    siteConfig: {
      http20Enabled: true
      vnetPrivatePortsCount: 2
      webSocketsEnabled: true
      netFrameworkVersion: 'v7.0'
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: appInsightsInstrumentationKey
        }
        {
          name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
          value: appInsightsConnectionString
        }
        {
          name: 'ORLEANS_AZURE_STORAGE_CONNECTION_STRING'
          value: storageConnectionString
        }
        {
          name: 'ORLEANS_CLUSTER_ID'
          value: 'Staging'
        }
      ]
      alwaysOn: true
    }
  }
}

resource slotConfig 'Microsoft.Web/sites/config@2021-03-01' = {
  name: 'slotConfigNames'
  parent: appService
  properties: {
    appSettingNames: [
      'ORLEANS_CLUSTER_ID'
    ]
  }
}

resource appServiceConfig 'Microsoft.Web/sites/config@2021-03-01' = {
  parent: appService
  name: 'metadata'
  properties: {
    CURRENT_STACK: 'dotnet'
  }
}

此 bicep 檔案會將Azure App 服務設定為 .NET 7 應用程式。 appServicePlan資源和資源 appService 都會布建在資源群組的位置。 資源 appService 已設定為使用 S1 SKU,容量為 1 。 此外,資源會設定為使用 vnetSubnetId 子網和使用 HTTPS。 它也會設定 appInsightsInstrumentationKey 檢測金鑰、 appInsightsConnectionString 連接字串和 storageConnectionString 連接字串。 購物車應用程式會使用這些應用程式。

上述的 Bicep Visual Studio Code延伸模組包含視覺化檢視。 所有這些 bicep 檔案都會視覺化,如下所示:

布建視覺化檢視轉譯的購物車範例應用程式 Bicep 布建。

預備環境

部署基礎結構可以部署到短期、以測試為中心的預備環境,以及不可變的擲回環境。 在將部署升階至生產環境之前,這些環境非常有助於測試部署。

注意

如果您的App Service是在 Windows 上執行,則每個App Service都必須位於自己的個別App Service方案中。 或者,若要避免這類設定,您可以改用Linux 上的 App Service,並解決此問題。

摘要

當您更新原始程式碼和 push 存放庫分支的變更 main 時, deploy.yml 工作流程將會執行。 它會提供 bicep 檔案中定義的資源,並部署應用程式。 您可以擴充應用程式以包含新功能,例如驗證,或支援應用程式的多個實例。 此工作流程的主要目標是示範在單一步驟中布建和部署資源的能力。

除了 bicep 延伸模組中的視覺化檢視之外,Azure 入口網站資源群組頁面在布建和部署應用程式之後看起來會類似下列範例:

Azure 入口網站:購物籃範例應用程式資源。

另請參閱