Condividi tramite


Distribuire Orleans in Servizio app di Azure

In questa esercitazione si apprenderà come distribuire un'app carrello acquisti Orleans in Servizio app di Azure. L'esercitazione illustra un'applicazione di esempio che supporta le funzionalità seguenti:

  • Carrello acquisti: una semplice applicazione carrello acquisti che usa Orleans per il supporto multipiattaforma e le sue funzionalità di applicazioni distribuite scalabili.

    • Gestione inventario: modificare e/o creare l'inventario dei prodotti.
    • Inventario acquisti: esplora i prodotti acquistabili e li aggiungi al carrello.
    • Carrello: visualizza un riepilogo di tutti gli articoli nel carrello e gestisci questi articoli; rimozione o modifica della quantità di ogni articolo.

Con una conoscenza dell'app e delle relative funzionalità, si apprenderà quindi come distribuire l'app in Servizio app di Azure usando GitHub Actions, .NET e ClI di Azure e Azure Bicep. Si apprenderà anche come configurare la rete virtuale per l'app in Azure.

In questa esercitazione verranno illustrate le procedure per:

  • Distribuire un'applicazione Orleans in Servizio app di Azure
  • Automatizzare la distribuzione con GitHub Actions e Azure Bicep
  • Configurare la rete virtuale per l'app in Azure

Prerequisiti

Eseguire l'app in locale

Per eseguire l'app in locale, creare una copia tramite fork del cluster Azure Samples: Orleans in Servizio app di Azure repository e clonarla nel computer locale. Dopo la clonazione, aprire la soluzione in un IDE di propria scelta. Se si usa Visual Studio, fare clic con il pulsante destro del mouse sul progetto Orleans.ShoppingCart.Silo e scegliere Imposta come progetto di avvio, quindi eseguire l'app. In caso contrario, è possibile eseguire l'app usando il comando dell'interfaccia della riga di comando di .NET seguente:

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

Per altre informazioni, vedere dotnet run. Con l'app in esecuzione, è possibile spostarsi ed è possibile testarne le funzionalità. Tutte le funzionalità dell'app durante l'esecuzione in locale si basano sulla persistenza in memoria, sul clustering locale e usa il pacchetto NuGet Bogus per generare prodotti falsi. Arrestare l'app selezionando l'opzione Arresta debug in Visual Studio oppure premendo CTRL+C nell'interfaccia della riga di comando di .NET.

All'interno dell'app carrello acquisti

Orleans è un framework affidabile e scalabile per la creazione di applicazioni distribuite. Per questa esercitazione si distribuirà una semplice app carrello acquisti creata usando Orleans per Servizio app di Azure. L'app espone la possibilità di gestire l'inventario, aggiungere e rimuovere articoli in un carrello e acquistare i prodotti disponibili. Il client viene compilato usando Blazor con un modello di hosting del server. L'app è progettata come segue:

Orleans: Architettura dell'app di esempio carrello acquisti.

Il diagramma precedente mostra che il client è l'app Blazor lato server. È composto da diversi servizi che utilizzano un grano Orleans corrispondente. Ogni servizio è associato a una granularità di Orleans come indicato di seguito:

  • InventoryService: utilizza la posizione in cui l'inventario IInventoryGrain viene partizionato per categoria di prodotti.
  • ProductService: utilizza la IProductGrain posizione in cui un singolo prodotto viene sottoposto a tethering in una singola istanza di granularità da Id.
  • ShoppingCartService: utilizza l'oggetto IShoppingCartGrain in cui un singolo utente ha una sola istanza del carrello acquisti indipendentemente dall'utilizzo dei client.

La soluzione contiene tre progetti:

  • Orleans.ShoppingCart.Abstractions: libreria di classi che definisce i modelli e le interfacce per l'app.
  • Orleans.ShoppingCart.Grains: libreria di classi che definisce i granelli che implementano la logica di business dell'app.
  • Orleans.ShoppingCart.Silos: un'app Blazor sul lato server che ospita il silo Orleans.

Esperienza utente client

L'app client del carrello acquisti ha diverse pagine, ognuna delle quali rappresenta un'esperienza utente diversa. L'interfaccia utente dell'app viene compilata usando il pacchetto NuGet MudBlazor .

Home page

Alcune frasi semplici per l'utente per comprendere lo scopo dell'app e aggiungere il contesto a ogni voce di menu di spostamento.

Orleans: App di esempio carrello acquisti, home page.

Pagina inventario negozio

Pagina che visualizza tutti i prodotti disponibili per l'acquisto. Gli elementi possono essere aggiunti al carrello da questa pagina.

Orleans: App di esempio carrello acquisti, pagina inventario negozio.

Pagina del carrello vuota

Quando non hai aggiunto nulla al carrello, la pagina esegue il rendering di un messaggio che indica che non hai elementi nel carrello.

Orleans: App di esempio carrello acquisti, pagina del carrello vuota.

Articoli aggiunti al carrello durante la pagina inventario negozio

Quando gli articoli vengono aggiunti al carrello nella pagina dell'inventario negozio, l'app visualizza un messaggio che indica che l'articolo è stato aggiunto al carrello.

Orleans: app di esempio carrello acquisti, articoli aggiunti al carrello durante la pagina di inventario negozio.

Pagina di gestione dei prodotti

Un utente può gestire l'inventario da questa pagina. I prodotti possono essere aggiunti, modificati e rimossi dall'inventario.

Orleans: App di esempio carrello acquisti, pagina di gestione dei prodotti.

Pagina Gestione prodotti - Creazione di una nuova finestra di dialogo

Quando un utente fa clic sul pulsante Crea nuovo prodotto , l'app visualizza una finestra di dialogo che consente all'utente di creare un nuovo prodotto.

Orleans: App di esempio carrello acquisti, pagina di gestione dei prodotti - Finestra di dialogo per la creazione di un nuovo prodotto.

Elementi nella pagina del carrello

Quando gli articoli sono nel carrello, è possibile visualizzarli e modificarne la quantità e persino rimuoverli dal carrello. L'utente visualizza un riepilogo degli elementi nel carrello e il costo totale pretax.

Orleans: App di esempio carrello acquisti, articoli nella pagina del carrello.

Importante

Quando questa app viene eseguita in locale, in un ambiente di sviluppo, l'app userà il clustering localhost, l'archiviazione in memoria e un silo locale. Esegue anche il seeding dell'inventario con dati falsi generati automaticamente usando il pacchetto NuGet Bogus . Questo è tutto intenzionale per dimostrare la funzionalità.

Distribuire nel Servizio app di Azure

Una tipica applicazione Orleans è costituita da un cluster di processi server (silo) in cui risiedono grani e un set di processi client, in genere server Web, che ricevono richieste esterne, li trasformano in chiamate di metodo granulari e restituiscono risultati. Di conseguenza, la prima cosa da fare per eseguire un'applicazione Orleans consiste nell'avviare un cluster di silo. A scopo di test, un cluster può essere costituito da un singolo silo.

Nota

Per una distribuzione di produzione affidabile, è necessario più di un silo in un cluster per la tolleranza di errore e la scalabilità.

Prima di distribuire l'app, è necessario creare un gruppo di risorse di Azure oppure scegliere di usarne uno esistente. Per creare un nuovo gruppo di risorse di Azure, usare uno degli articoli seguenti:

Prendere nota del nome del gruppo di risorse scelto, sarà necessario in un secondo momento per distribuire l'app.

Creare un'entità servizio

Per automatizzare la distribuzione dell'app, è necessario creare un'entità servizio. Si tratta di un account Microsoft autorizzato a gestire le risorse di Azure per conto dell'utente.

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

Le credenziali JSON create avranno un aspetto simile al seguente, ma con i valori effettivi per il client, la sottoscrizione e il tenant:

{
  "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"
}

Copiare l'output del comando negli Appunti e continuare con il passaggio successivo.

Creare un segreto GitHub

GitHub offre un meccanismo per la creazione di segreti crittografati. I segreti creati sono disponibili per l'uso nei flussi di lavoro GitHub Actions. Si vedrà come usare GitHub Actions per automatizzare la distribuzione dell'app, insieme ad Azure Bicep. Bicep è un linguaggio specifico del dominio che usa una sintassi dichiarativa per distribuire le risorse di Azure. Per altre informazioni, vedere Informazioni su Bicep. Usando l'output dal passaggio Crea un'entità servizio , è necessario creare un segreto GitHub denominato AZURE_CREDENTIALS con le credenziali formattate JSON.

All'interno del repository GitHub selezionare Impostazioni>segreti>Crea un nuovo segreto. Immettere il nome AZURE_CREDENTIALS e incollare le credenziali JSON dal passaggio precedente nel campo Valore .

Repository GitHub: Segreti delle impostazioni >

Per altre informazioni, vedere GitHub: Segreti crittografati.

Preparare la distribuzione di Azure

L'app deve essere in pacchetto per la distribuzione. Orleans.ShoppingCart.Silos Nel progetto viene definito un Target elemento eseguito dopo il Publish passaggio. Verrà zip la directory di pubblicazione in un file disilo.zip :

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

Esistono molti modi per distribuire un'app .NET in Servizio app di Azure. In questa esercitazione si usano GitHub Actions, Azure Bicep e .NET e clI di Azure. Considerare il file ./github/workflow/deploy.yml nella radice del repository GitHub:

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

Il flusso di lavoro GitHub precedente:

Il flusso di lavoro viene attivato da un push nel ramo principale . Per altre informazioni, vedere GitHub Actions e .NET.

Suggerimento

Se si verificano problemi durante l'esecuzione del flusso di lavoro, potrebbe essere necessario verificare che l'entità servizio disponga di tutti gli spazi dei nomi del provider necessari registrati. Sono necessari gli spazi dei nomi del provider seguenti:

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

Per altre informazioni, vedere Risolvere gli errori per la registrazione del provider di risorse.

Azure impone restrizioni di denominazione e convenzioni per le risorse. È necessario aggiornare i valori del file deploy.yml per quanto segue:

  • UNIQUE_APP_NAME
  • AZURE_RESOURCE_GROUP_NAME
  • AZURE_RESOURCE_GROUP_LOCATION

Impostare questi valori sul nome dell'app univoca e sul nome e sulla posizione del gruppo di risorse di Azure.

Per altre informazioni, vedere Regole di denominazione e restrizioni per le risorse di Azure.

Esplorare i modelli Bicep

Quando viene eseguito il az deployment group create comando, valuta il file main.bicep . Questo file contiene le risorse di Azure da distribuire. Un modo per pensare a questo passaggio è che effettua il provisioning di tutte le risorse per la distribuzione.

Importante

Se si usa Visual Studio Code, l'esperienza di creazione bicep viene migliorata quando si usa l'estensione Bicep.

Esistono molti file bicep, ognuno contenente risorse o moduli (raccolte di risorse). Il file main.bicep è il punto di ingresso ed è costituito principalmente dalle module definizioni:

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
  }
}

Il file bicep precedente definisce quanto segue:

  • Due parametri per il nome del gruppo di risorse e il nome dell'app.
  • Definizione storageModule , che definisce l'account di archiviazione.
  • Definizione logsModule che definisce le risorse di Azure Log Analytics e Application Insights.
  • Risorsa vnet , che definisce la rete virtuale.
  • DefinizionesiloModule, che definisce la Servizio app di Azure.

Una cosa molto importante resource è quella della Rete virtuale. La vnet risorsa consente alla Servizio app di Azure di comunicare con il cluster Orleans.

Ogni volta che viene module rilevato un oggetto nel file bicep, viene valutato tramite un altro file bicep che contiene le definizioni delle risorse. Il primo modulo rilevato è , storageModuledefinito nel file 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}'

I file Bicep accettano parametri, dichiarati usando la param parola chiave. Analogamente, possono anche dichiarare output usando la output parola chiave. L'archiviazione resource si basa sul tipo e sulla Microsoft.Storage/storageAccounts@2021-08-01 versione. Verrà eseguito il provisioning nella posizione del gruppo di risorse, come e StorageV2Standard_LRS SKU. Il bicep di archiviazione definisce la stringa di connessione come output. Questa operazione connectionString viene usata in seguito dal silo bicep per connettersi all'account di archiviazione.

Il file logs-and-insights.bicep definisce quindi le risorse di Azure Log Analytics e 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

Questo file bicep definisce le risorse di Azure Log Analytics e Application Insights. La appInsights risorsa è un tipo e la logs risorsa è un webPerGB2018 tipo. Sia la appInsights risorsa che la logs risorsa vengono sottoposte a provisioning nella posizione del gruppo di risorse. La appInsights risorsa è collegata alla logs risorsa tramite la WorkspaceResourceId proprietà . Esistono due output definiti in questo bicep, usati più avanti dal servizio app module.

Infine, il file app-service.bicep definisce la risorsa Servizio app di Azure:

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'
  }
}

Questo file bicep configura l'Servizio app di Azure come applicazione .NET 7. Sia la appServicePlan risorsa che la appService risorsa vengono sottoposte a provisioning nella posizione del gruppo di risorse. La appService risorsa è configurata per usare lo S1 SKU, con una capacità di 1. Inoltre, la risorsa è configurata per usare la vnetSubnetId subnet e per usare HTTPS. Configura anche la appInsightsInstrumentationKey chiave di strumentazione, la appInsightsConnectionString stringa di connessione e la storageConnectionString stringa di connessione. Questi vengono usati dall'app carrello acquisti.

L'estensione di Visual Studio Code precedente per Bicep include un visualizzatore. Tutti questi file bicep vengono visualizzati come segue:

Orleans: l'app di esempio del carrello acquisti esegue il rendering del visualizzatore di provisioning bicep.

Ambienti di staging

L'infrastruttura di distribuzione può essere distribuita in ambienti di staging, che sono di breve durata, incentrati sui test e sugli ambienti non modificabili. Questi ambienti sono molto utili per testare le distribuzioni prima di promuoverle all'ambiente di produzione.

Nota

Se il servizio app è in esecuzione in Windows, ogni servizio app deve trovarsi nel proprio piano di servizio app separato. In alternativa, per evitare tale configurazione, è possibile usare Servizio app in Linux e questo problema verrà risolto.

Riepilogo

Durante l'aggiornamento del codice sorgente e push le modifiche apportate al main ramo del repository, verrà eseguito il flusso di lavoro deploy.yml . Fornisce le risorse definite nei file bicep e distribuisce l'applicazione. L'applicazione può essere espansa in modo da includere nuove funzionalità, ad esempio l'autenticazione o il supporto di più istanze dell'applicazione. L'obiettivo principale di questo flusso di lavoro è dimostrare la possibilità di effettuare il provisioning e distribuire le risorse in un singolo passaggio.

Oltre al visualizzatore dall'estensione bicep, la pagina del gruppo di risorse portale di Azure sarà simile all'esempio seguente dopo il provisioning e la distribuzione dell'applicazione:

Portale di Azure: Risorse dell'app di esempio del carrello acquisti Di Orleans.

Vedi anche