Condividi tramite


Esercitazione: Elaborare immagini usando FFmpeg su una condivisione file di Azure montata

In questa esercitazione si implementa un'app Python che utilizza un binario ffmpeg su una condivisione file di Azure montata per elaborare le immagini con Azure Functions. Quando si carica un'immagine nel contenitore, la funzione viene attivata, chiama ffmpeg dal montaggio per convertire l'immagine e salva il risultato nell'archiviazione. Ospitando file binari di grandi dimensioni come ffmpeg su un'unità di rete montata invece che nel pacchetto di distribuzione, le distribuzioni rimangono leggere e l'avvio a freddo è rapido.

In questa esercitazione, farai:

  • Distribuire un'app funzione Flex Consumption con una condivisione montata di Azure Files usando il CLI per sviluppatori di Azure.
  • Caricare un'immagine di esempio per attivare l'elaborazione basata su BLOB
  • Verificare che la funzione denominata ffmpeg dal montaggio e che l'immagine convertita sia stata salvata

Prerequisiti

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

Inizializzare il progetto di esempio

Il codice di esempio per questa esercitazione è disponibile nel repository GitHub Azure Functions Flex Consumption with Azure Files OS Mount Samples. La ffmpeg-image-processing 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 il file binario ffmpeg.

  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/ffmpeg-image-processing
    
  4. Inizializza l'ambiente azd. Quando richiesto, immettere un nome di ambiente, ffmpeg-processingad esempio :

    azd init
    

Esaminare il codice

I tre componenti chiave che rendono il lavoro di elaborazione basato sul montaggio del sistema operativo sono l'infrastruttura che crea il montaggio, lo script che carica il file binario e il codice della funzione che lo chiama.

Il mounts.bicep modulo configura un'installazione SMB di Azure Files nell'applicazione di 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 dell'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 la cassetta di sicurezza, archivia la chiave e concede i ruoli di controllo degli accessi basati sul 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: 'tools'
        shareName: 'tools'
        mountPath: '/mounts/tools/'
      }
    ]
  }
  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, carica il file binario ffmpeg in File di Azure e crea la sottoscrizione di Event Grid per i trigger del blob.

  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. Gestire e distribuire tutto:

    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, un'istanza di Application Insights e un'identità gestita.
    • Distribuisce il codice della funzione Python.
    • Scarica e carica il file binario ffmpeg nella condivisione di file di Azure.
    • Crea una sottoscrizione Event Grid affinché i caricamenti BLOB attivino la tua funzione.
    • Esegue un controllo di integrità.

    Annotazioni

    Poiché le condivisioni SMB di Azure Files non supportano ancora l'autenticazione tramite identità gestita, è necessaria 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)
    STORAGE_ACCOUNT=$(azd env get-value AZURE_STORAGE_ACCOUNT_NAME)
    FUNCTION_APP_NAME=$(azd env get-value AZURE_FUNCTION_APP_NAME)
    INPUT_CONTAINER=$(azd env get-value AZURE_STORAGE_INPUT_CONTAINER)
    OUTPUT_CONTAINER=$(azd env get-value AZURE_STORAGE_OUTPUT_CONTAINER)
    

Elaborare un'immagine

  1. Caricare l'immagine di esempio inclusa nel repository nel contenitore di input. La sottoscrizione di Event Grid creata durante la distribuzione attiva automaticamente la funzione quando viene caricato un blob.

    az storage blob upload \
      --container-name $INPUT_CONTAINER \
      --name sample_image.png \
      --file sample_image.png \
      --account-name $STORAGE_ACCOUNT \
      --auth-mode login
    

    Suggerimento

    Se il trigger non viene attivato immediatamente, attendere 10-15 secondi e quindi controllare i log di esecuzione della funzione nel portale di Azure.

  2. Verificare che la funzione abbia elaborato l'immagine elencando i BLOB nel contenitore di output:

    az storage blob list \
      --container-name $OUTPUT_CONTAINER \
      --account-name $STORAGE_ACCOUNT \
      --auth-mode login \
      -o table
    

    Verrà visualizzato sample_image.jpg nel contenitore di output.

  3. Scaricare l'immagine convertita:

    az storage blob download \
      --container-name $OUTPUT_CONTAINER \
      --name sample_image.png \
      --file ./output_image.png \
      --account-name $STORAGE_ACCOUNT \
      --auth-mode login
    

Annotazioni

La prima esecuzione potrebbe essere leggermente più lenta (avvio a freddo). Le chiamate successive sono più veloci perché il contenitore di funzioni rimane caldo e ffmpeg viene memorizzato nella cache. Per ridurre al minimo l'avvio a freddo, provare ad abilitare istanze sempre pronte.

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.