Home > Mobile >  How to deploy an Azure function into a function app through a CI/CD pipeline?
How to deploy an Azure function into a function app through a CI/CD pipeline?

Time:11-13

I have a CI/CD pipeline that creates the infrastructure to create the function app, storage container and app insights to the azure portal. I have an Azure function in Linux and I want to know how to link this azure function to the function app during the deployment process.

This is the template.json that I am using to deploy my current infrastructure:

{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
    "subscriptionId": {
        "type": "string"
    },
    "name": {
        "type": "string"
    },
    "location": {
        "type": "string"
    },
    "hostingPlanName": {
        "type": "string"
    },
    "serverFarmResourceGroup": {
        "type": "string"
    },
    "alwaysOn": {
        "type": "bool"
    },
    "use32BitWorkerProcess": {
        "type": "bool"
    },
    "storageAccountName": {
        "type": "string"
    },
    "netFrameworkVersion": {
        "type": "string"
    },
    "sku": {
        "type": "string"
    },
    "skuCode": {
        "type": "string"
    },
    "workerSize": {
        "type": "string"
    },
    "workerSizeId": {
        "type": "string"
    },
    "numberOfWorkers": {
        "type": "string"
    }
},
"variables": {},
"resources": [
    {
        "apiVersion": "2018-11-01",
        "name": "[parameters('name')]",
        "type": "Microsoft.Web/sites",
        "kind": "functionapp",
        "location": "[parameters('location')]",
        "tags": {},
        "dependsOn": [
            "microsoft.insights/components/templateforarm",
            "[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
            "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
        ],
        "properties": {
            "name": "[parameters('name')]",
            "siteConfig": {
                "appSettings": [
                    {
                        "name": "FUNCTIONS_EXTENSION_VERSION",
                        "value": "~4"
                    },
                    {
                        "name": "FUNCTIONS_WORKER_RUNTIME",
                        "value": "node"
                    },
                    {
                        "name": "WEBSITE_NODE_DEFAULT_VERSION",
                        "value": "~14"
                    },
                    {
                        "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
                        "value": "[reference('microsoft.insights/components/templateforarm', '2015-05-01').InstrumentationKey]"
                    },
                    {
                        "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
                        "value": "[reference('microsoft.insights/components/templateforarm', '2015-05-01').ConnectionString]"
                    },
                    {
                        "name": "AzureWebJobsStorage",
                        "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                        
                    },
                    {
                        "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                        "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                    },
                    {
                        "name": "WEBSITE_CONTENTSHARE",
                        "value": "[concat(toLower(parameters('name')), 'a8cc')]"
                    }
                ],
                "use32BitWorkerProcess": "[parameters('use32BitWorkerProcess')]",
                "netFrameworkVersion": "[parameters('netFrameworkVersion')]"
            },
            "serverFarmId": "[concat('/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
            "clientAffinityEnabled": false
        }
    },
    {
        "apiVersion": "2018-11-01",
        "name": "[parameters('hostingPlanName')]",
        "type": "Microsoft.Web/serverfarms",
        "location": "[parameters('location')]",
        "kind": "",
        "tags": {},
        "dependsOn": [],
        "properties": {
            "name": "[parameters('hostingPlanName')]",
            "workerSize": "[parameters('workerSize')]",
            "workerSizeId": "[parameters('workerSizeId')]",
            "numberOfWorkers": "[parameters('numberOfWorkers')]"
        },
        "sku": {
            "Tier": "[parameters('sku')]",
            "Name": "[parameters('skuCode')]"
        }
    },
    {
        "apiVersion": "2020-02-02-preview",
        "name": "templateforarm",
        "type": "microsoft.insights/components",
        "location": "westus2",
        "tags": {},
        "dependsOn": [],
        "properties": {
            "ApplicationId": "[parameters('name')]",
            "Request_Source": "IbizaWebAppExtensionCreate",
            "Flow_Type": "Redfield",
            "Application_Type": "web",
            "WorkspaceResourceId": "[concat('/subscriptions/', parameters('subscriptionId'), '/resourcegroups/defaultresourcegroup-wus2/providers/microsoft.operationalinsights/workspaces/defaultworkspace-', parameters('subscriptionId'),'-wus2')]"
        }
    },
    {
        "apiVersion": "2019-06-01",
        "type": "Microsoft.Storage/storageAccounts",
        "name": "[parameters('storageAccountName')]",
        "location": "[parameters('location')]",
        "tags": {},
        "sku": {
            "name": "Standard_LRS"
        },
        "properties": {
            "supportsHttpsTrafficOnly": true,
            "minimumTlsVersion": "TLS1_2"
        }
    }
]
}

This is the folder structure that I have for my azure function, app insights, storage container and function app infrastructure.

-azure
 -azure_functions
   -my_function
     -arm
       -dev.json
       -prod.json
       -template.json
     -my_function_code
       -index.json
       -function.json
     -host.json
     -local.settings.json
     -package-lock.json
     -package.json
     -proxies.json
     -release.yml

This is the yml file that I use to deploy the app insights, storage container and function app.

trigger:
  none

pr:
  branches:
    include:
      - main
  paths:
    include:
        - azure/azure_functions/my_function/

stages:
- stage: Validation
  displayName: Validate Templates
  jobs:
  - job: Validate
    steps:
       - task: AzureResourceGroupDeployment@2
         displayName: "Validate Test"
         inputs:
            azureSubscription: "test-group-SPN"
            resourceGroupName: "test-group"
            location: "West US 2"
            csmFile: azure/azure_functions/my_function/arm/template.json
            csmParametersFile: 
            azure/azure_functions/my_function/arm/test.json
            deploymentMode: Validation

       - task: PublishBuildArtifacts@1
         displayName: "Publish Artifact: ARM Template"
         inputs:
             PathtoPublish: ./azure/azure_functions/my_function/arm
             ArtifactName: arm

- stage: TEST
  displayName: Deploy stage Test
  dependsOn: Build
  condition: succeeded()
  jobs:
     - deployment: Deploy
       displayName: Deploy
       environment: eventconnector-test           
       strategy:
          runOnce:
            deploy:
              steps:
               - task: AzureResourceManagerTemplateDeployment@3
                 displayName: 'Deploy App Insights, Storage Container & Function App'
                 inputs:
                     deploymentScope: 'Resource Group'
                     azureResourceManagerConnection: 'eventconnector-test-group-SPN'
                     subscriptionId: 'XXXX'
                     action: 'Create Or Update Resource Group'
                     resourceGroupName: 'eventconnector-test-group'
                     location: 'West US 2'
                     templateLocation: 'Linked artifact'
                     csmFile: '$(Pipeline.Workspace)/arm/template.json'
                     csmParametersFile: '$(Pipeline.Workspace)/arm/test.json'
                     deploymentMode: 'Incremental'

There's another yml file that I was able to create to deploy my azure function but this doesn't link to the current function app that I defined previously.

trigger:
  none

pr:
  branches:
    include:
      - main
paths:
  include:
  - azure/azure_functions/my_function/

stages:
- stage: Build
  displayName: Build stage
  jobs:
  - job: Build
    displayName: Build
    pool:
       vmImage: ubuntu-latest
    steps:
    - task: NodeTool@0
      inputs:
         versionSpec: '14.x'
      displayName: 'Install Node.js'

    - script: |
        npm install --prefix azure/azure_functions/my_function/

      displayName: 'Prepare binaries'

    - task: ArchiveFiles@2
      displayName: 'Archive files'
      inputs:
         rootFolderOrFile: 'azure/azure_functions/my_function/'
         includeRootFolder: false
         archiveType: zip
         archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
         replaceExistingArchive: true

    - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
      artifact: drop

  - stage: TEST
    displayName: Deploy stage Test
    dependsOn: Build
    condition: succeeded()
    jobs:
    - deployment: Deploy
      displayName: Deploy
      environment: eventconnector-test
      pool:
        vmImage: ubuntu-latest
      strategy:
         runOnce:
            deploy:
              steps:
                - task: AzureFunctionApp@1
                  displayName: 'Azure Functions App Deploy: '
                  inputs:
                  azureSubscription: 'test-group-SPN'
                  appType: functionAppLinux
                  appName: 'my_function'
                  package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'

How can I link this azure function to be deployed in the function app that I declared in my first yml file?

CodePudding user response:

After doing some research I found out that I just needed to add the following code at the end of my yml file to deploy my azure function into the function app:

- task: AzureCLI@1
  displayName: 'Deploy Azure function'
  inputs:
    azureSubscription: 'XXX'
    scriptType: 'ps'
    scriptLocation: 'inlineScript'
    inlineScript: |
     az functionapp deployment source config-zip -g XXX -n azure_func_app_name --src $(Pipeline.Workspace)/drop/$(Build.BuildId).zip

Below is the final yml code that deploys the function app, app insights, storage and drops the azure function.

trigger:
  none

pr:
  branches:
    include:
      - main
  paths:
    include:
        - azure/azure_functions/my_function/

stages:
    - stage: Validation
      displayName: Validate Templates
      jobs:
      - job: Validate
        steps:
          - task: AzureResourceGroupDeployment@2
          displayName: "Validate Test"
     inputs:
        azureSubscription: "test-group-SPN"
        resourceGroupName: "test-group"
        location: "West US 2"
        csmFile: azure/azure_functions/my_function/arm/template.json
        csmParametersFile: 
        azure/azure_functions/my_function/arm/test.json
        deploymentMode: Validation

   - task: PublishBuildArtifacts@1
        displayName: "Publish Artifact: ARM Template"
        inputs:
         PathtoPublish: ./azure/azure_functions/my_function/arm
         ArtifactName: arm

    - stage: TEST
       displayName: Deploy stage Test
       dependsOn: Build
       condition: succeeded()
       jobs:
        - deployment: Deploy
          displayName: Deploy
          environment: eventconnector-test           
          strategy:
          runOnce:
          deploy:
          steps:
           - task: AzureResourceManagerTemplateDeployment@3
             displayName: 'Deploy App Insights, Storage Container & Function App'
             inputs:
                 deploymentScope: 'Resource Group'
                 azureResourceManagerConnection: 'eventconnector-test-group-SPN'
                 subscriptionId: 'XXXX'
                 action: 'Create Or Update Resource Group'
                 resourceGroupName: 'eventconnector-test-group'
                 location: 'West US 2'
                 templateLocation: 'Linked artifact'
                 csmFile: '$(Pipeline.Workspace)/arm/template.json'
                 csmParametersFile: '$(Pipeline.Workspace)/arm/test.json'
                 deploymentMode: 'Incremental'

          - task: AzureCLI@1
            displayName: 'Deploy Azure function'
            inputs:
            azureSubscription: 'XXX'
            scriptType: 'ps'
            scriptLocation: 'inlineScript'
            inlineScript: |
                az functionapp deployment source config-zip -g XXX -n azure_func_app_name --src $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
  • Related