Condividi tramite


Esercitazione: Analisi del testo persistente con una condivisione di file di Azure montata

In questa esercitazione si implementa un'app Python di Azure Functions che usa Durable Functions per orchestrare l'analisi parallela dei file di testo. L'app per le funzioni monta una condivisione di File di Azure, analizza più file di testo in parallelo (fan-out), aggrega i risultati (fan-in) e li restituisce al chiamante. Questo approccio illustra un vantaggio fondamentale dei montaggi di archiviazione: l'accesso condiviso ai file tra più istanze di funzione senza sovraccarico di rete per richiesta.

In questa esercitazione, farai:

  • Usare la CLI per sviluppatori di Azure per distribuire un'app Durable Functions in un piano di consumo flessibile con una condivisione di Azure Files montata
  • Attivare un'orchestrazione per elaborare i file di testo di esempio in parallelo
  • Verificare i risultati dell'analisi aggregata

Annotazioni

Gli esempi di codice per questo articolo sono disponibili nel repository GitHub Azure Functions Flex Consumption with Azure Files OS Mount Samples.

Prerequisiti

Gli esempi dell'interfaccia della riga di comando di questa esercitazione usano la sintassi Bash e sono stati testati nei terminali Azure Cloud Shell (Bash) e Linux/macOS.

Inizializzare il progetto di esempio

È possibile trovare il codice di esempio per questa esercitazione nel repository GitHub Azure Functions Flex Consumption with Azure Files OS Mount Samples. La durable-text-analysis cartella contiene il codice dell'app per le funzioni, un modello Bicep che effettua il provisioning delle risorse di Azure necessarie e uno script di post-distribuzione che carica i file di testo di esempio.

  1. Aprire un terminale e passare alla directory in cui si vuole clonare il repository.

  2. Clonare il repository:

    git clone https://github.com/Azure-Samples/Azure-Functions-Flex-Consumption-with-Azure-Files-OS-Mount-Samples.git
    
  3. Passare alla cartella del progetto:

    cd Azure-Functions-Flex-Consumption-with-Azure-Files-OS-Mount-Samples/durable-text-analysis
    
  4. Inizializzare l'ambiente azd . Quando richiesto, immettere un nome di ambiente, durable-textad esempio :

    azd init
    

Esaminare il codice

I tre elementi chiave che fanno funzionare questo esempio sono l'infrastruttura che crea il montaggio, lo script che carica i file di esempio e il codice della funzione che orchestra l'analisi.

Il modulo mounts.bicep configura un mount SMB di Azure Files nell'applicazione funzione. Il mountPath valore determina il percorso locale in cui vengono visualizzati i file in fase di esecuzione. La chiave di accesso dell'account di archiviazione viene passata come parametro e la piattaforma la risolve in fase di esecuzione tramite un riferimento a Key Vault:

@description('Function app name')
param functionAppName string

@description('Storage account name')
param storageAccountName string

@description('Storage account access key or app setting reference for Azure Files SMB mount')
param accessKey string

@description('Array of mount configurations')
param mounts array

// Function app reference
resource functionApp 'Microsoft.Web/sites@2023-12-01' existing = {
  name: functionAppName
}

// Azure Files OS mount configuration
// Deploys azureStorageAccounts site config with all mounts in one shot
resource mountConfig 'Microsoft.Web/sites/config@2023-12-01' = {
  parent: functionApp
  name: 'azurestorageaccounts'
  properties: reduce(mounts, {}, (cur, mount) => union(cur, {
    '${mount.name}': {
      type: 'AzureFiles'
      shareName: mount.shareName
      mountPath: mount.mountPath
      accountName: storageAccountName
      accessKey: accessKey
    }
  }))
}

output mountPaths array = [for mount in mounts: mount.mountPath]

Poiché i montaggi SMB di Azure Files non supportano ancora l'autenticazione tramite identità gestita, è necessaria una chiave dell'account di archiviazione. Come procedura consigliata, archiviare questa chiave in Azure Key Vault e usare un riferimento a Key Vault in un'impostazione dell'app. La configurazione di montaggio fa riferimento all'impostazione dell'app usando @AppSettingRef(), in modo che la chiave non venga mai visualizzata nei modelli Bicep. Il keyvault.bicep modulo crea il vault, archivia la chiave e concede i ruoli di controllo degli accessi in base al ruolo (RBAC):

@description('Key Vault name')
param name string

@description('Location')
param location string

@description('Tags')
param tags object = {}

@description('Storage account name')
param storageAccountName string

@description('Principal ID of the function app identity (receives Key Vault Secrets User role)')
param functionAppPrincipalId string

@description('Principal ID of the deploying user (receives Key Vault Secrets Officer role)')
param deployerPrincipalId string = ''

// Storage account reference
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' existing = {
  name: storageAccountName
}

// Key Vault with RBAC authorization
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: name
  location: location
  tags: tags
  properties: {
    sku: {
      family: 'A'
      name: 'standard'
    }
    tenantId: tenant().tenantId
    enableRbacAuthorization: true
    enabledForTemplateDeployment: true
    enableSoftDelete: true
    softDeleteRetentionInDays: 7
  }
}

// Store storage account key as a secret (Azure Files mounts require shared key)
resource storageKeySecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: 'storageAccountKey'
  properties: {
    value: storage.listKeys().keys[0].value
    contentType: 'Storage account access key for Azure Files SMB mount'
  }
}

// Built-in Key Vault RBAC role IDs
var roles = {
  KeyVaultSecretsOfficer: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')
  KeyVaultSecretsUser: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')
}

// Grant the function app identity read access to secrets
resource functionAppSecretsUser 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(keyVault.id, functionAppPrincipalId, roles.KeyVaultSecretsUser)
  scope: keyVault
  properties: {
    roleDefinitionId: roles.KeyVaultSecretsUser
    principalId: functionAppPrincipalId
    principalType: 'ServicePrincipal'
  }
}

// Grant the deployer manage access to secrets
resource deployerSecretsOfficer 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(deployerPrincipalId)) {
  name: guid(keyVault.id, deployerPrincipalId, roles.KeyVaultSecretsOfficer)
  scope: keyVault
  properties: {
    roleDefinitionId: roles.KeyVaultSecretsOfficer
    principalId: deployerPrincipalId
    principalType: 'User'
  }
}

output name string = keyVault.name
output uri string = keyVault.properties.vaultUri
output storageKeySecretUri string = storageKeySecret.properties.secretUri

Il main.bicep file richiama i moduli mount e Key Vault:


// Key Vault for secure storage of Azure Files access key
module keyVault './app/keyvault.bicep' = {
  name: 'keyVault'
  scope: rg
  params: {
    name: !empty(keyVaultName) ? keyVaultName : '${abbrs.keyVaultVaults}${resourceToken}'
    location: location
    tags: tags
    storageAccountName: storage.outputs.name
    functionAppPrincipalId: processorIdentity.outputs.principalId
    deployerPrincipalId: principalId
  }
}

// Azure Files mount configuration (access key resolved via Key Vault reference)
module azureFilesMount './app/mounts.bicep' = {
  name: 'azureFilesMount'
  scope: rg
  params: {
    functionAppName: functionApp.outputs.name
    storageAccountName: storage.outputs.name
    accessKey: '@AppSettingRef(MOUNT_SECRET_REFERENCE)'
    mounts: [
      {
        name: 'data'
        shareName: 'data'
        mountPath: '/mounts/data/'
      }
    ]
  }
  dependsOn: [
    functionAppRoleAssignments
  ]

Eseguire la distribuzione usando l'interfaccia della riga di comando per sviluppatori di Azure

Questo esempio è un modello dell'interfaccia della riga di comando per sviluppatori di Azure (azd). Un singolo azd up comando effettua il provisioning dell'infrastruttura, distribuisce il codice della funzione e carica i file di testo di esempio nella condivisione file di Azure.

  1. Accedere ad Azure. Lo script post-distribuzione usa i comandi dell'interfaccia della riga di comando di Azure, quindi è necessario eseguire l'autenticazione usando entrambi gli strumenti:

    azd auth login
    az login
    
  2. Effettuare il provisioning e distribuire tutti gli elementi seguenti:

    azd up
    

    Quando richiesto, selezionare la sottoscrizione di Azure e il percorso da usare. Il comando quindi:

    • Crea un gruppo di risorse, un account di archiviazione, Key Vault, un'app per le funzioni Flex Consumption con una configurazione di Durable Functions, un'istanza di Application Insights e un'identità gestita
    • Distribuisce il codice della funzione Python
    • Carica file di testo di esempio nella condivisione file di Azure
    • Esegue un controllo di salute

    Annotazioni

    Poiché i montaggi SMB di Azure Files non supportano ancora l'autenticazione tramite identità gestita, è necessario utilizzare una chiave dell'account di archiviazione. Come procedura consigliata, la distribuzione archivia questa chiave in Azure Key Vault e usa un riferimento a Key Vault in modo che la chiave non venga mai esposta nelle impostazioni dell'app. Questo approccio offre la gestione centralizzata dei segreti, il controllo e il supporto per la rotazione delle chiavi.

    La distribuzione richiede alcuni minuti. Al termine, viene visualizzato un riepilogo delle risorse create.

  3. Salvare i nomi delle risorse come variabili della shell per i passaggi rimanenti:

    RESOURCE_GROUP=$(azd env get-value AZURE_RESOURCE_GROUP)
    FUNCTION_APP_NAME=$(azd env get-value AZURE_FUNCTION_APP_NAME)
    FUNCTION_APP_URL=$(azd env get-value AZURE_FUNCTION_APP_URL)
    

Attivare l'orchestrazione

  1. Ottenere la chiave host della funzione:

    HOST_KEY=$(az functionapp keys list \
      --resource-group $RESOURCE_GROUP \
      --name $FUNCTION_APP_NAME \
      --query "functionKeys.default" \
      -o tsv)
    
  2. Avviare l'orchestrazione:

    curl -s -X POST "${FUNCTION_APP_URL}/api/start-analysis?code=${HOST_KEY}" | jq .
    

    La risposta include un ID istanza e gli URI di interrogazione dello stato.

    {
      "id": "abc123def456",
      "statusQueryGetUri": "https://...",
      "sendEventPostUri": "https://...",
      "terminatePostUri": "https://..."
    }
    

Verificare i risultati

  1. Controllare lo stato dell'orchestrazione. Usare l'statusQueryGetUri dalla risposta precedente o costruire manualmente l'URL:

    INSTANCE_ID="<instance-id-from-trigger-response>"
    
    curl -s "${FUNCTION_APP_URL}/api/orchestrators/TextAnalysisOrchestrator/${INSTANCE_ID}?code=${HOST_KEY}" | jq .
    

    Mentre l'orchestrazione è in esecuzione, runtimeStatus è Running. Al termine, la risposta sarà simile alla seguente:

    {
      "name": "TextAnalysisOrchestrator",
      "instanceId": "abc123def456",
      "runtimeStatus": "Completed",
      "output": {
        "results": [
          {
            "file": "sample1.txt",
            "word_count": 15,
            "char_count": 98,
            "sentiment": "positive"
          },
          {
            "file": "sample2.txt",
            "word_count": 18,
            "char_count": 120,
            "sentiment": "positive"
          },
          {
            "file": "sample3.txt",
            "word_count": 12,
            "char_count": 85,
            "sentiment": "neutral"
          }
        ],
        "total_words": 45,
        "total_chars": 303,
        "analysis_duration_seconds": 2.34
      }
    }
    

Suggerimento

L'app per le funzioni accede a tutti e tre i file in parallelo tramite il montaggio di archiviazione. L'app non richiede chiamate di rete per richiesta. La funzione li legge direttamente dalla condivisione montata usando l'I/O del file standard. Questo approccio illustra la potenza dei montaggi di archiviazione combinati con Durable Functions.

Pulire le risorse

Per evitare addebiti in corso, eliminare tutte le risorse create da questa esercitazione:

azd down --purge

Avviso

Questo comando elimina il gruppo di risorse e tutte le risorse in esso contenute, tra cui l'app per le funzioni, l'account di archiviazione e l'istanza di Application Insights.