diff --git a/README.md b/README.md index 4c4aa8a..207c535 100644 --- a/README.md +++ b/README.md @@ -89,10 +89,11 @@ Last updated: 2025-10-01 ## Deployment Approaches -> Each scenario includes detailed deployment guides that explain different approaches: +Here are a few deployment examples that show different ways you can approach: -1. [High-Decay](./scenario1-high-decay) (Writable Approach), click here for [quick deployment guide](./scenario1-high-decay/DEPLOYMENT.md) -2. [Optimized](./scenario2-optimized) (Mounted Package Approach), click here to see a [deployment template sample](./scenario2-optimized/az-functionapps-cicd-pipeline-template.yml) +1. [VS manual deployment](./_deployment-options/VS-deployment-extension-manual-approach.md) - VS extension manual approach +2. [Writable Approach](./_deployment-options/az-functionapps-cicd-pipeline-template-writable.yml) - Deployment pipeline ADO approach +3. [Mounted Package Approach](./_deployment-options/az-functionapps-cicd-pipeline-template-optimized.yml) - Deployment pipeline ADO approach ### High-Decay (Writable Approach) @@ -135,7 +136,7 @@ Last updated: 2025-10-01
- Total views + Total views

Refresh Date: 2025-10-01

diff --git a/_deployment-options/VS-deployment-extension-manual-approach.md b/_deployment-options/VS-deployment-extension-manual-approach.md new file mode 100644 index 0000000..2b92d05 --- /dev/null +++ b/_deployment-options/VS-deployment-extension-manual-approach.md @@ -0,0 +1,257 @@ +# Function App manual deployment - Overview + +Costa Rica + +[![GitHub](https://badgen.net/badge/icon/github?icon=github&label)](https://github.com) +[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/) +[brown9804](https://github.com/brown9804) + +Last updated: 2025-10-01 + +---------- + +> [!NOTE] +> Here are a few examples that demonstrate the deployment process and the creation of E2E solution. Please feel free to use them as references if needed. +> - [Demo: Azure Implementation - PDF Layout Extraction with Azure AI Document Intelligence Supporting Multiple Document Versions with Visual Selection Cues (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-MultiLayout-VisualCue-AzureAI-Document-Processing) +> - [Demo: Automated PDF Invoice Processing with Open Framework (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-OpenFramework) +> - [Demo: PDF Layout Extraction with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Layouts-Processing-Fapp-DocIntelligence) +> - [Demo: Automated PDF Invoice Processing with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-DocIntelligence) + +## Function App Hosting Options + +> In the context of Azure Function Apps, a `hosting option refers to the plan you choose to run your function app`. This choice affects how your function app is scaled, the resources available to each function app instance, and the support for advanced functionalities like virtual network connectivity and container support. + +> [!TIP] +> +> - `Scale to Zero`: Indicates whether the service can automatically scale down to zero instances when idle. +> - **IDLE** stands for: +> - **I** – Inactive +> - **D** – During +> - **L** – Low +> - **E** – Engagement +> - In other words, when the application is not actively handling requests or events (it's in a low-activity or paused state). +> - `Scale Behavior`: Describes how the service scales (e.g., `event-driven`, `dedicated`, or `containerized`). +> - `Virtual Networking`: Whether the service supports integration with virtual networks for secure communication. +> - `Dedicated Compute & Reserved Cold Start`: Availability of always-on compute to avoid cold starts and ensure low latency. +> - `Max Scale Out (Instances)`: Maximum number of instances the service can scale out to. +> - `Example AI Use Cases`: Real-world scenarios where each plan excels. + +
+Flex Consumption + +| Feature | Description | +|--------|-------------| +| **Scale to Zero** | `Yes` | +| **Scale Behavior** | `Fast event-driven` | +| **Virtual Networking** | `Optional` | +| **Dedicated Compute & Reserved Cold Start** | `Optional (Always Ready)` | +| **Max Scale Out (Instances)** | `1000` | +| **Example AI Use Cases** | `Real-time data processing` for AI models, `high-traffic AI-powered APIs`, `event-driven AI microservices`. Ideal for fraud detection, real-time recommendations, NLP, and computer vision services. | + +
+ +
+Consumption + +| Feature | Description | +|--------|-------------| +| **Scale to Zero** | `Yes` | +| **Scale Behavior** | `Event-driven` | +| **Virtual Networking** | `Optional` | +| **Dedicated Compute & Reserved Cold Start** | `No` | +| **Max Scale Out (Instances)** | `200` | +| **Example AI Use Cases** | `Lightweight AI APIs`, `scheduled AI tasks`, `low-traffic AI event processing`. Great for sentiment analysis, simple image recognition, and batch ML tasks. | + +
+ +
+Functions Premium + +| Feature | Description | +|--------|-------------| +| **Scale to Zero** | `No` | +| **Scale Behavior** | `Event-driven with premium options` | +| **Virtual Networking** | `Yes` | +| **Dedicated Compute & Reserved Cold Start** | `Yes` | +| **Max Scale Out (Instances)** | `100` | +| **Example AI Use Cases** | `Enterprise AI applications`, `low-latency AI APIs`, `VNet integration`. Ideal for secure, high-performance AI services like customer support and analytics. | + +
+ +
+App Service + +| Feature | Description | +|--------|-------------| +| **Scale to Zero** | `No` | +| **Scale Behavior** | `Dedicated VMs` | +| **Virtual Networking** | `Yes` | +| **Dedicated Compute & Reserved Cold Start** | `Yes` | +| **Max Scale Out (Instances)** | `Varies` | +| **Example AI Use Cases** | `AI-powered web applications`, `dedicated resources`. Great for chatbots, personalized content, and intensive AI inference. | + +
+ +
+Container Apps Env. + +| Feature | Description | +|--------|-------------| +| **Scale to Zero** | `No` | +| **Scale Behavior** | `Containerized microservices environment` | +| **Virtual Networking** | `Yes` | +| **Dedicated Compute & Reserved Cold Start** | `Yes` | +| **Max Scale Out (Instances)** | `Varies` | +| **Example AI Use Cases** | `AI microservices architecture`, `containerized AI workloads`, `complex AI workflows`. Ideal for orchestrating AI services like image processing, text analysis, and real-time analytics. | + +
+ +## Function App: Configure/Validate the Environment variables + +> [!NOTE] +> This example is using system-assigned managed identity to assign RBACs (Role-based Access Control). + +- Under `Settings`, go to `Environment variables`. And `+ Add` the following variables: + + - `COSMOS_DB_ENDPOINT`: Your Cosmos DB account endpoint 🡢 `Review the existence of this, if not create it` + - `COSMOS_DB_KEY`: Your Cosmos DB account key 🡢 `Review the existence of this, if not create it` + - `COSMOS_DB_CONNECTION_STRING`: Your Cosmos DB connection string 🡢 `Review the existence of this, if not create it` + - `invoicecontosostorage_STORAGE`: Your Storage Account connection string 🡢 `Review the existence of this, if not create it` + - `FORM_RECOGNIZER_ENDPOINT`: For example: `https://.cognitiveservices.azure.com/` 🡢 `Review the existence of this, if not create it` + - `FORM_RECOGNIZER_KEY`: Your Documment Intelligence Key (Form Recognizer). 🡢 + - `FUNCTIONS_EXTENSION_VERSION`: `~4` 🡢 `Review the existence of this, if not create it` + - `WEBSITE_RUN_FROM_PACKAGE`: `1` 🡢 `Review the existence of this, if not create it` + - `FUNCTIONS_WORKER_RUNTIME`: `python` 🡢 `Review the existence of this, if not create it` + - `FUNCTIONS_NODE_BLOCK_ON_ENTRY_POINT_ERROR`: `true` (This setting ensures that all entry point errors are visible in your application insights logs). 🡢 `Review the existence of this, if not create it` + + image + + image + + image + + image + + - Click on `Apply` to save your configuration. + + image + +## Function App: Develop the logic + +- You need to install [VSCode](https://code.visualstudio.com/download) +- Install python from Microsoft store: + + image + +- Open VSCode, and install some extensions: `python`, and `Azure Tools`. + + image + + image + +- Click on the `Azure` icon, and `sign in` into your account. Allow the extension `Azure Resources` to sign in using Microsoft, it will open a browser window. After doing so, you will be able to see your subscription and resources. + + image + +- Under Workspace, click on `Create Function Project`, and choose a path in your local computer to develop your function. + + image + +- Choose the language, in this case is `python`: + + image + +- Select the model version, for this example let's use `v2`: + + image + +- For the python interpreter, let's use the one installed via `Microsoft Store`: + + image + +- Choose a template (e.g., **Blob trigger**) and configure it to trigger on new PDF uploads in your Blob container. + + image + +- Provide a function name, like `BlobTriggerContosoPDFInvoicesDocIntelligence`: + + image + +- Next, it will prompt you for the path of the blob container where you expect the function to be triggered after a file is uploaded. In this case is `pdfinvoices` as was previously created. + + image + +- Click on `Create new local app settings`, and then choose your subscription. + + image + +- Choose `Azure Storage Account for remote storage`, and select one. I'll be using the `invoicecontosostorage`. + + image + +- Then click on `Open in the current window`. You will see something like this: + + image + +- Now we need to update the function code to extract data from PDFs and store it in Cosmos DB, use this an example: + + > 1. **PDF Upload**: A PDF file is uploaded to the Azure Blob Storage container (`pdfinvoices`). + > 2. **Trigger Azure Function**: The upload triggers the Azure Function `BlobTriggerContosoPDFLayoutsDocIntelligence`. + > 3. **Initialize Clients**: Sets up connections to Azure Document Intelligence and Cosmos DB. + > - Initializes the `DocumentAnalysisClient` using the `FORM_RECOGNIZER_ENDPOINT` and `FORM_RECOGNIZER_KEY` environment variables. + > - Initializes the `CosmosClient` using Azure Active Directory (AAD) via `DefaultAzureCredential`. + > 4. **Read PDF from Blob Storage**: Reads the PDF content from the blob into a byte stream. + > 5. **Analyze PDF**: Uses Azure Document Intelligence to analyze the layout of the PDF. + > - Calls `begin_analyze_document` with the `prebuilt-layout` model. + > - Waits for the analysis to complete and retrieves the layout result. + > 6. **Extract Layout Data**: Parses and structures the layout data from the analysis result. + > - Extracts lines, tables, and selection marks from each page. + > - Logs styles (e.g., handwritten content) and organizes data into a structured dictionary. + > 7. **Save Data to Cosmos DB**: Saves the structured layout data to Cosmos DB. + > - Ensures the database (`ContosoDBDocIntellig`) and container (`Layouts`) exist or creates them. + > - Inserts or updates the layout data using `upsert_item`. + > 8. **Logging (Process and Errors)**: Logs each step of the process, including success messages and detailed error handling for debugging and monitoring. + + - Update the function_app.py, for example see the code used in each demo: + - [Demo: Azure Implementation - PDF Layout Extraction with Azure AI Document Intelligence Supporting Multiple Document Versions with Visual Selection Cues (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-MultiLayout-VisualCue-AzureAI-Document-Processing) + - [Demo: Automated PDF Invoice Processing with Open Framework (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-OpenFramework) + - [Demo: PDF Layout Extraction with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Layouts-Processing-Fapp-DocIntelligence) + - [Demo: Automated PDF Invoice Processing with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-DocIntelligence) + + | Template Blob Trigger | Function Code updated | + | --- | --- | + | image | image| + + - Now, let's update the `requirements.txt`, see the code used in each demo: + - [Demo: Azure Implementation - PDF Layout Extraction with Azure AI Document Intelligence Supporting Multiple Document Versions with Visual Selection Cues (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-MultiLayout-VisualCue-AzureAI-Document-Processing) + - [Demo: Automated PDF Invoice Processing with Open Framework (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-OpenFramework) + - [Demo: PDF Layout Extraction with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Layouts-Processing-Fapp-DocIntelligence) + - [Demo: Automated PDF Invoice Processing with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-DocIntelligence) + + | Template `requirements.txt` | Updated `requirements.txt` | + | --- | --- | + | image | image| + + - Since this function has already been tested, you can deploy your code to the function app in your subscription. If you want to test, you can use run your function locally for testing. + - Click on the `Azure` icon. + - Under `workspace`, click on the `Function App` icon. + - Click on `Deploy to Azure`. + + image + + - Select your `subscription`, your `function app`, and accept the prompt to overwrite: + + image + + - After completing, you see the status in your terminal: + + image + + image + +> [!IMPORTANT] +> If you need a hand with the code, just check out some of the examples, they’ve got extra information. +> - [Demo: Azure Implementation - PDF Layout Extraction with Azure AI Document Intelligence Supporting Multiple Document Versions with Visual Selection Cues (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-MultiLayout-VisualCue-AzureAI-Document-Processing) +> - [Demo: Automated PDF Invoice Processing with Open Framework (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-OpenFramework) +> - [Demo: PDF Layout Extraction with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Layouts-Processing-Fapp-DocIntelligence) +> - [Demo: Automated PDF Invoice Processing with Doc Intelligence (full-code approach)](https://github.com/MicrosoftCloudEssentials-LearningHub/PDFs-Invoice-Processing-Fapp-DocIntelligence) diff --git a/scenario2-optimized/az-functionapps-cicd-pipeline-template.yml b/_deployment-options/az-functionapps-cicd-pipeline-template-optimized.yml similarity index 99% rename from scenario2-optimized/az-functionapps-cicd-pipeline-template.yml rename to _deployment-options/az-functionapps-cicd-pipeline-template-optimized.yml index c5ff478..f64b01f 100644 --- a/scenario2-optimized/az-functionapps-cicd-pipeline-template.yml +++ b/_deployment-options/az-functionapps-cicd-pipeline-template-optimized.yml @@ -1,3 +1,4 @@ +# Example # Azure DevOps CI/CD Pipeline Template for Azure Functions # This template provides a complete CI/CD workflow for building and deploying Azure Function Apps # It includes both build and deployment stages with support for deployment slots and multi-environment deployments diff --git a/_deployment-options/az-functionapps-cicd-pipeline-template-writable.yml b/_deployment-options/az-functionapps-cicd-pipeline-template-writable.yml new file mode 100644 index 0000000..947ae0c --- /dev/null +++ b/_deployment-options/az-functionapps-cicd-pipeline-template-writable.yml @@ -0,0 +1,325 @@ +# Example +# Azure DevOps CI/CD Pipeline Template for Azure Functions +# This template provides a complete CI/CD workflow for building and deploying Azure Function Apps +# It includes both build and deployment stages with support for deployment slots and multi-environment deployments + +parameters: + # Build Configuration (Optional) + # Specifies whether to build in Debug or Release mode + buildConfiguration: 'Release' + + # Branch Name (Required) + # The Git branch to build from (e.g., 'main', 'develop', 'feature/xyz') + branchName: '' + + # Artifact Name (Optional) + # Name for the resulting build artifact + artifactName: 'Setup' + + # NuGet Feed (Required) + # Your Azure DevOps NuGet feed name (e.g., 'MyOrganization/MyFeed') + nugetFeed: '' + + # .NET SDK Version (Optional) + # The version of .NET SDK to use for building + dotnetVersion: '6.0.x' + + # Azure Subscription (Required for deployment) + # The name of your Azure DevOps service connection to Azure + azureSubscription: '' + + # Function App Name (Required for deployment) + # The name of your Azure Function App resource + functionAppName: '' + + # Resource Group Name (Required for deployment) + # The name of the Azure resource group containing your Function App + resourceGroupName: '' + + # Deploy to Slot (Optional) + # Whether to use deployment slots for zero-downtime deployments + deployToSlot: false + + # Slot Name (Optional, required if deployToSlot is true) + # Name of the deployment slot if using slots + slotName: 'staging' + + # Environment (Optional) + # Target environment name (dev/test/prod) + environment: 'dev' + + # Swap After Deployment (Optional) + # Whether to swap slots after successful deployment + swapAfterDeployment: true + + # App Settings (Optional) + # Array of application settings to configure (key-value pairs) + appSettings: [] + + # Deployment Method (Optional) + # The method used to deploy the Function App + # Valid options: + # - 'auto': Lets Azure decide the best deployment method based on the app type and configuration. + # - 'zipDeploy': Basic ZIP deployment that extracts files to the wwwroot folder. + # - 'zipDeployWithRestartAppSetting': Sets WEBSITE_RUN_FROM_PACKAGE=1 and deploys as a ZIP package (run-from-package). + # - 'runFromPackage': Sets WEBSITE_RUN_FROM_PACKAGE to a URL of your package. + # - 'webDeploy': Uses MSDeploy (Web Deploy) protocol for deployment. + # For writable deployments prefer 'zipDeploy' or 'webDeploy'. + deploymentMethod: 'zipDeploy' + + # Writable Deployment + # true => deploy files to wwwroot (writable approach). Pre-deploy step will remove WEBSITE_RUN_FROM_PACKAGE. + # false => keep mounted/package behavior (run-from-package). Use 'zipDeployWithRestartAppSetting' or 'runFromPackage'. + writableDeployment: true + +stages: + ################################################# + # BUILD STAGE + # Compiles the code and creates deployment packages + ################################################# + - stage: Build + displayName: Build ${{ parameters.artifactName }} for ${{ parameters.branchName }} + jobs: + - job: Build + displayName: Build Function App + steps: + # Step 1: Checkout the correct branch + # This step fetches the source code from the repository + - checkout: self + clean: true # Remove any previous files + persistCredentials: true # Keep git credentials for potential later git operations + fetchDepth: 0 # Fetch full history + displayName: Checkout ${{ parameters.branchName }} + + # Step 2: Ensure branch synchronization + # This ensures we're working with the latest code from the specified branch + # It fetches all remote branches and resets the local branch to match the remote + - script: | + git fetch --all + git clean -fd + git reset --hard origin/${{ parameters.branchName }} + displayName: Synchronize with ${{ parameters.branchName }} + + # Step 3: Install .NET Core SDK + # Ensures the correct .NET SDK version is available for building + - task: UseDotNet@2 + inputs: + packageType: 'sdk' + version: '${{ parameters.dotnetVersion }}' + displayName: Install .NET SDK Version ${{ parameters.dotnetVersion }} + + # Step 4: Restore NuGet Packages + - task: NuGetCommand@2 + inputs: + command: 'restore' + restoreSolution: '**/*.sln' + feedsToUse: 'select' + vstsFeed: '${{ parameters.nugetFeed }}' + displayName: Restore NuGet Packages + + # Step 5: Build the Solution + - task: DotNetCoreCLI@2 + displayName: Publish Function App + inputs: + command: 'publish' + projects: '**/*.csproj' + arguments: '--configuration ${{ parameters.buildConfiguration }} --output $(Build.ArtifactStagingDirectory)/publish' + publishWebProjects: false # Ensures we publish all projects, not just web projects + zipAfterPublish: false # Don't zip during publish, we'll do that in next step for more control + + # Step 6: Archive Published Artifacts + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: '$(Build.ArtifactStagingDirectory)/publish' + includeRootFolder: false # Don't include the publish folder itself in the archive + archiveType: 'zip' # Create a ZIP archive + archiveFile: '$(Build.ArtifactStagingDirectory)/archives/${{ parameters.artifactName }}-${{ parameters.environment }}-${{ parameters.branchName }}.zip' + replaceExistingArchive: true # Overwrite any existing archive with the same name + displayName: Archive Function App Package + + # Step 7: Publish Archived Build Artifacts + - task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: '$(Build.ArtifactStagingDirectory)/archives' + ArtifactName: 'archives' # Name of the artifact feed in Azure DevOps + publishLocation: 'Container' # Publish to the pipeline's artifact storage + displayName: Publish Function App Artifacts + + ################################################# + # DEPLOYMENT STAGE + # Deploys the built artifacts to Azure Function App + # This stage will only run if the required deployment parameters are provided + ################################################# + - stage: Deploy + displayName: Deploy to ${{ parameters.environment }} Environment + dependsOn: Build # Only run after Build stage completes successfully + condition: and(succeeded(), ne('${{ parameters.azureSubscription }}', ''), ne('${{ parameters.functionAppName }}', ''), ne('${{ parameters.resourceGroupName }}', '')) + jobs: + - deployment: DeployFunctionApp + displayName: Deploy Function App + # Create an environment in Azure DevOps for tracking deployments + environment: ${{ parameters.environment }}-${{ parameters.functionAppName }} + strategy: + # Define a standard deployment strategy + runOnce: + deploy: + steps: + # Step 1: Download the artifacts from the build stage + # This retrieves the ZIP package created in the Build stage + # The deployment job automatically downloads artifacts to $(Pipeline.Workspace) + - download: current + artifact: archives + displayName: Download Build Artifacts + + # --- PRE-DEPLOY: Prepare app for writable deployment --- + # If writableDeployment is true we remove the WEBSITE_RUN_FROM_PACKAGE app setting (recommended) + # This converts the app from mounted-package (run-from-package) to writable wwwroot. + ${{ if eq(parameters.writableDeployment, true) }}: + - task: AzureCLI@2 + displayName: 'Prepare app for writable deployment: unset WEBSITE_RUN_FROM_PACKAGE' + inputs: + azureSubscription: '${{ parameters.azureSubscription }}' + scriptType: 'bash' + scriptLocation: 'inlineScript' + inlineScript: | + set -e + APP_NAME='${{ parameters.functionAppName }}' + RG='${{ parameters.resourceGroupName }}' + # If using slot, include slot argument + SLOT_ARG='' + if [ '${{ parameters.deployToSlot }}' = 'true' ]; then + # Note: azure CLI slot argument uses --slot (no quotes) + SLOT_ARG="--slot ${{ parameters.slotName }}" + fi + + # Option A (default): delete the app setting key (recommended to fully remove run-from-package) + echo "Deleting WEBSITE_RUN_FROM_PACKAGE app setting (if present)..." + az webapp config appsettings delete --name "$APP_NAME" --resource-group "$RG" --setting-names WEBSITE_RUN_FROM_PACKAGE $SLOT_ARG || true + + # Optional: display current setting (for diagnostics) + echo "Current WEBSITE_RUN_FROM_PACKAGE value (if any):" + az webapp config appsettings list --name "$APP_NAME" --resource-group "$RG" $SLOT_ARG --query "[?name=='WEBSITE_RUN_FROM_PACKAGE']" -o table || true + + echo "App prepared for writable deployment." + + # --- DEPLOY PACKAGE --- + # This deploys the ZIP package to the Azure Function App using the specified deployment method. + - task: AzureFunctionApp@1 + inputs: + azureSubscription: '${{ parameters.azureSubscription }}' # Azure service connection + appType: 'functionApp' # Specifies this is a Function App + appName: '${{ parameters.functionAppName }}' # Name of the Function App in Azure + # Configure slot deployment if enabled + ${{ if eq(parameters.deployToSlot, true) }}: + deployToSlotOrASE: true # Deploy to a slot + resourceGroupName: '${{ parameters.resourceGroupName }}' # Resource group containing the Function App + slotName: '${{ parameters.slotName }}' # Name of the slot to deploy to + ${{ if ne(parameters.deployToSlot, true) }}: + deployToSlotOrASE: false # Deploy directly to production + package: '$(Pipeline.Workspace)/archives/${{ parameters.artifactName }}-${{ parameters.environment }}-${{ parameters.branchName }}.zip' # Path to the ZIP package + deploymentMethod: '${{ parameters.deploymentMethod }}' # Use the specified deployment method + displayName: Deploy to Azure Function App ${{ parameters.functionAppName }} using ${{ parameters.deploymentMethod }} + + # Step 3: Configure Application Settings + # This sets up environment variables and app settings for the Function App + # Only runs if appSettings parameter is provided + - task: AzureAppServiceSettings@1 + condition: and(succeeded(), gt(length('${{ parameters.appSettings }}'), 0)) + inputs: + azureSubscription: '${{ parameters.azureSubscription }}' + appName: '${{ parameters.functionAppName }}' + resourceGroupName: '${{ parameters.resourceGroupName }}' + ${{ if eq(parameters.deployToSlot, true) }}: + slotName: '${{ parameters.slotName }}' + appSettings: '${{ parameters.appSettings }}' + displayName: Configure Application Settings + + # Step 4: Swap Slots (if enabled) + # This swaps the staging slot with production for zero-downtime deployments + # Only runs if deployToSlot and swapAfterDeployment are both true + - task: AzureAppServiceManage@0 + condition: and(succeeded(), eq(parameters.deployToSlot, true), eq(parameters.swapAfterDeployment, true)) + inputs: + azureSubscription: '${{ parameters.azureSubscription }}' + Action: 'Swap Slots' + WebAppName: '${{ parameters.functionAppName }}' + ResourceGroupName: '${{ parameters.resourceGroupName }}' + SourceSlot: '${{ parameters.slotName }}' + displayName: Swap Deployment Slots + + # --- POST-DEPLOY: Restart the app if using writableDeployment (good to clear state) --- + ${{ if eq(parameters.writableDeployment, true) }}: + - task: AzureCLI@2 + displayName: 'Restart Function App (writable deployment)' + inputs: + azureSubscription: '${{ parameters.azureSubscription }}' + scriptType: 'bash' + scriptLocation: 'inlineScript' + inlineScript: | + APP_NAME='${{ parameters.functionAppName }}' + RG='${{ parameters.resourceGroupName }}' + SLOT_ARG='' + if [ '${{ parameters.deployToSlot }}' = 'true' ]; then + SLOT_ARG="--slot ${{ parameters.slotName }}" + fi + + echo "Restarting $APP_NAME..." + az webapp restart --name "$APP_NAME" --resource-group "$RG" $SLOT_ARG || true + echo "Restart completed." + + # Step 5: Verify Deployment + # This checks if the deployment was successful + - script: | + echo "Deployment to ${{ parameters.functionAppName }} completed successfully" + echo "Environment: ${{ parameters.environment }}" + echo "Deployment Method: ${{ parameters.deploymentMethod }}" + if [ '${{ parameters.deployToSlot }}' = 'true' ]; then + echo "Deployed to slot: ${{ parameters.slotName }}" + fi + echo "Function App URL: https://${{ parameters.functionAppName }}${{ if eq(parameters.deployToSlot, true) }}-${{ parameters.slotName }}${{ end }}.azurewebsites.net" + displayName: Verify Deployment + + ################################################# + # OPTIONAL: SMOKE TEST STAGE + # Runs basic tests against the deployed Function App + # This stage will only run if the deployment stage succeeds + ################################################# + - stage: SmokeTest + displayName: Run Smoke Tests + dependsOn: Deploy + condition: and(succeeded(), ne('${{ parameters.azureSubscription }}', ''), ne('${{ parameters.functionAppName }}', '')) + jobs: + - job: TestFunctionApp + displayName: Test Function App Endpoints + steps: + # Run basic health check tests against the deployed Function App + # This ensures the deployment is functioning correctly + - task: PowerShell@2 + inputs: + targetType: 'inline' + script: | + # Define the base URL for the Function App (slot-aware) + $baseUrl = "https://${{ parameters.functionAppName }}.azurewebsites.net" + if ('${{ parameters.deployToSlot }}' -eq 'true') { + $baseUrl = "https://${{ parameters.functionAppName }}-${{ parameters.slotName }}.azurewebsites.net" + } + + Write-Host "Running health check against $baseUrl" + + try { + # You can replace this with actual endpoint tests specific to your Function App + $response = Invoke-WebRequest -Uri $baseUrl -Method Get -TimeoutSec 30 -ErrorAction Stop + Write-Host "Health check status code: $($response.StatusCode)" + + if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 400) { + Write-Host "##vso[task.complete result=Succeeded;]Health check passed" + } else { + Write-Warning "Health check returned unexpected status code: $($response.StatusCode)" + } + } catch { + Write-Warning "Health check failed: $_" + } + failOnStderr: false + pwsh: true + displayName: Run Function App Health Check + continueOnError: true # Continue even if health check fails diff --git a/scenario1-high-decay/README.md b/scenario1-high-decay/README.md index 4527344..91e1beb 100644 --- a/scenario1-high-decay/README.md +++ b/scenario1-high-decay/README.md @@ -147,7 +147,7 @@ Last updated: 2025-08-27
- Total views + Total views

Refresh Date: 2025-10-01

diff --git a/scenario1-high-decay/terraform-infrastructure/README.md b/scenario1-high-decay/terraform-infrastructure/README.md index ded8fe5..b2d63da 100644 --- a/scenario1-high-decay/terraform-infrastructure/README.md +++ b/scenario1-high-decay/terraform-infrastructure/README.md @@ -126,7 +126,7 @@ graph TD;
- Total views + Total views

Refresh Date: 2025-10-01

diff --git a/scenario2-optimized/README.md b/scenario2-optimized/README.md index be9cb9f..1f5f856 100644 --- a/scenario2-optimized/README.md +++ b/scenario2-optimized/README.md @@ -150,7 +150,7 @@ Last updated: 2025-09-05
- Total views + Total views

Refresh Date: 2025-10-01

diff --git a/scenario2-optimized/terraform-infrastructure/README.md b/scenario2-optimized/terraform-infrastructure/README.md index d05f621..e3b679e 100644 --- a/scenario2-optimized/terraform-infrastructure/README.md +++ b/scenario2-optimized/terraform-infrastructure/README.md @@ -126,7 +126,7 @@ graph TD;
- Total views + Total views

Refresh Date: 2025-10-01