الدرس: معالجة الصور باستخدام FFmpeg على ملف ملفات Azure Share المثبت

في هذا الدرس، تقوم بنشر تطبيق بايثون يستخدم ملف ثنائي ffmpeg على مشاركة ملفات Azure المثبتة لمعالجة الصور في دالات Azure. عندما ترفع صورة إلى الحاوية، يتم تفعيل الوظيفة، وتستدعي ffmpeg من التركيب لتحويل الصورة، ثم تحفظ النتيجة مرة أخرى في التخزين. من خلال استضافة ملفات ثنائية كبيرة مثل ffmpeg على مشاركة مركبة بدلا من حزمة النشر الخاصة بك، تحافظ على عمليات النشر صغيرة وتبدأ بشكل بارد بسرعة.

في هذا البرنامج التعليمي، سوف تتعلّم:

  • نشر تطبيق وظيفة Flex Consumption مع مشاركة ملفات Azure المثبتة باستخدام Azure Developer CLI
  • رفع صورة عينة لتفعيل معالجة تعتمد على الكتلة
  • تحقق من أن الدالة التي استدعت ffmpeg من التركيب وحفظت الصورة المحولة

ملحوظة

عينات الكود لهذه المقالة متوفرة في مستودع Azure Functions Flex Consumption مع ملفات Azure OS Mount Samples Samples مستودع GitHub.

المتطلبات المسبقه

أمثلة واجهة السطر في هذا الدرس تستخدم بناء جملة Bash ويتم اختبارها في أجهزة Azure Cloud Shell (Bash) وLinux/macOS.

تهيئة مشروع العينة

كود نموذجي لهذا الدرس موجود في مستودع Azure Functions Flex Consumption with ملفات Azure OS Mount Samples Samples Repository على GitHub. يحتوي المجلد ffmpeg-image-processing على كود تطبيق الوظيفة، وقالب Bicep الذي يوفر موارد Azure المطلوبة، وسكريبت بعد النشر يرفع ملف ffmpeg الثنائي.

  1. افتح طرفية واذهب إلى الدليل الذي تريد استنساخ المستودع فيه.

  2. استنساخ المستودع:

    git clone https://github.com/Azure-Samples/Azure-Functions-Flex-Consumption-with-Azure-Files-OS-Mount-Samples.git
    
  3. اذهب إلى مجلد المشروع:

    cd Azure-Functions-Flex-Consumption-with-Azure-Files-OS-Mount-Samples/ffmpeg-image-processing
    
  4. قم بتهيئة azd البيئة. عند طلب ذلك، أدخل اسم البيئة مثل ffmpeg-processing:

    azd init
    

مراجعة الرمز

الأجزاء الثلاثة الرئيسية التي تجعل معالجة نظام التشغيل تعتمد على التركيب تعمل هي البنية التحتية التي تنشئ التركيب، والسكريبت الذي يرفع الملف الثنائي، وكود الدالة الذي يستدعيه.

تقوم الوحدة mounts.bicep بتكوين تركيب ملفات Azure SMB على تطبيق الوظائف. تحدد القيمة mountPath المسار المحلي الذي تظهر فيه الملفات أثناء وقت التشغيل. تمرر مفتاح الوصول إلى حساب التخزين كمعلمة، وتقوم المنصة بحلها أثناء التشغيل من خلال مرجع لخزنة المفاتيح:

@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]

نظرا لأن تركيبات ملفات Azure SMB لا تدعم بعد إدارة التحقق من هويتها، تحتاج إلى مفتاح حساب تخزين. كأفضل ممارسة، قم بتخزين هذا المفتاح في Azure Key Vault واستخدم مرجع Key Vault في إعداد التطبيق. إعداد التثبيت يشير إلى إعداد التطبيق باستخدام @AppSettingRef()، لذا لا يظهر المفتاح أبدا في قوالب العضلة ذات الرأس. تقوم الوحدة keyvault.bicep بإنشاء القبو، وتخزين المفتاح، وتمنح أدوار 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

يستدعي الملف main.bicep وحدات التثبيت و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
  ]
}

النشر باستخدام Azure Developer CLI

هذه العينة هي قالب Azure Developer CLI (azd). بنية تحتية واحدة azd up لتوفير الأوامر، تنشر كود الوظيفة، وترفع ملف ffmpeg إلى ملفات Azure، وتنشئ اشتراك Event Grid لمحفزات blob.

  1. تسجيل الدخول إلى أزور. سكريبت ما بعد النشر يستخدم أوامر Azure CLI، لذا تحتاج إلى المصادقة باستخدام كلا الأداتين:

    azd auth login
    az login
    
  2. توفير ونشر كل شيء:

    azd up
    

    عند الطلب، اختر اشتراك Azure والموقع المناسب. ثم الأمر:

    • ينشئ مجموعة موارد، حساب تخزين، خزنة مفاتيح، تطبيق دوال استهلاك مرن، مثيل Application Insights وهوية مدارة.
    • يقوم بنشر كود دالة بايثون.
    • يقوم بتحميل ورفع ملف ffmpeg الثنائي إلى مشاركة ملفات Azure.
    • ينشئ اشتراك في شبكة الأحداث بحيث تقوم عمليات رفع الكتل بتفعيل وظيفتك.
    • يجري فحص صحي.

    ملحوظة

    نظرا لأن تركيبات ملفات Azure SMB لا تدعم بعد المصادقة المدارة على الهوية، فهناك حاجة إلى مفتاح حساب تخزين. كأفضل ممارسة، يخزن النشر هذا المفتاح في Azure Key Vault ويستخدم مرجعا لخزنة المفاتيح حتى لا يتم كشف المفتاح أبدا في إعدادات التطبيق. يوفر هذا النهج إدارة مركزية للأسرار، والتدقيق، ودعم تدوير المفاتيح.

    يستغرق النشر بضع دقائق. عند الانتهاء، ترى ملخصا للموارد التي تم إنشاؤها.

  3. احفظ أسماء الموارد كمتغيرات shell للخطوات المتبقية:

    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)
    

معالجة صورة

  1. رفع صورة العينة المضمنة في المستودع إلى حاوية الإدخال. اشتراك شبكة الأحداث الذي يتم إنشاؤه أثناء النشر يقوم تلقائيا بتفعيل وظيفتك عند رفع blob.

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

    نصيحة

    إذا لم يطلق الزناد فورا، انتظر 10-15 ثانية، ثم تحقق من سجلات تنفيذ الوظيفة في بوابة Azure.

  2. تحقق من أن الدالة عالجت الصورة عن طريق سرد الكتل في حاوية الإخراج:

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

    يجب أن ترى sample_image.jpg ذلك في حاوية الإخراج.

  3. حمل الصورة المحولة:

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

ملحوظة

قد يكون التنفيذ الأول أبطأ قليلا (بداية باردة). الاستدعاءات اللاحقة تكون أسرع لأن حاوية الدالة تبقى دافئة ويتم تخزين ffmpeg مؤقتا. لتقليل البدء البارد، فكر في تمكين الدورات الجاهزة دائما.

تنظيف الموارد

لتجنب الرسوم المستمرة، احذف جميع الموارد التي أنشأها هذا الدرس:

azd down --purge

التحذير

يقوم هذا الأمر بحذف مجموعة الموارد وجميع الموارد فيها، بما في ذلك تطبيق الدالة، وحساب التخزين، ونسخة Application Insights الخاصة بها.