Deploy an Azure Functions app to Azure - Multi Stage Pipeline

Posted on March 11, 2023
devopsbeginnersazureazurefunctionazfunc-seriesarchitectazure devopsAzure Functions appMulti-stage pipeline

We already talked about the implementation of Azure Function App in a previous article

In this tutorial, we will be deploying our sample function app through a multi-stage pipeline. Let's walk through with very beginning by creating an Azure DevOps account.

Note: I will ensure that all resources in Azure are cleaned up by the time you read this article.

Let's see the steps we will be covering here.

  • Setup your Azure DevOps environment
  • Create the Azure function environment
    • Use Cloud Shell through the Azure portal
      • Create a Bash variable
      • Create Azure resources through the Bash variable
    • Create pipeline variable in Azure Pipeline
    • Create an environment
    • Create a service connection
  • Deploy an Azure Functions app to Azure

Setup your Azure DevOps environment

  1. Create an Azure DevOps account: If you don't have an Azure DevOps account yet, you can create one by signing up on the Azure DevOps website.
  2. Create a project: Once you have created your Azure DevOps account, you can create a new project. This is where you will manage all of your code, work items, and build/release pipelines. Here are detailed steps

Create the Azure function environment

Create a Free Azure subscription to create an environment of Azure function

Use Cloud Shell through the Azure portal

Cloud Shell

Create a Bash variable
  1. Configure the default region to deploy
az configure --defaults location=eastus
  1. Generate a random number, which we will use to create globally unique names for certain services in the next step.
resourceSuffix=$RANDOM
  1. Globally unique names for your Azure Function, and storage accounts.
sampleFunctionName="sample-func-${resourceSuffix}"
storageName="samplefuncstorage${resourceSuffix}"
  1. Create 1 more Bash variable to store the names of your resource group and service plan.
rgName='codehack-rg'
Create Azure resources through Bash variable
  1. Create a storage account using the above global variables
az storage account create \
  --name $storageName \
  --resource-group $rgName \
  --sku Standard_LRS
  1. Create a storage account using the above global variables
az functionapp create \
  --name $sampleFunctionName \
  --resource-group $rgName \
  --storage-account $storageName \
  --functions-version 4 \
  --consumption-plan-location eastus
  1. See if the function app running
az functionapp list \
  --resource-group $rgName \
  --query "[].{hostName: defaultHostName, state: state}" \
  --output table

See if the function app running

Create pipeline variable in Azure pipeline

  1. Go to the Azure DevOps project and under the pipeline, select "Library"

pipeline Library

  1. Select Variable Group
  2. Enter group name Release
  3. Click + to add a variable, and add two variables (You can find these values in the Azure portal )

ResourceGroupName | codehack-rg

sampleFunctionName | sample-func-16527

  1. Click "Save"

Create an environment

  1. Go to the "Environment"
  2. Type the Name of the Environment e.g. "spike"
  3. Click "Create" with default selection

Create a service connection

  1. Go to project settings
  2. Select Service Connection -> New Service Connection
  3. Select **"Azure Resource Manager" ** and select "Next"

Service Connection Step1

  1. Select "Service Principle"

Service Principle

  1. Select your Azure Subscription -> Give the name of the subscription e.g. "Resource Manager - Function - Demo"

Deploy an Azure Functions app to Azure

  1. From Azure DevOps, navigate to Pipelines.
  2. New Pipeline -> Select Repos Git -
  3. Select the Starter pipeline and then modify it as per the below example.

Let's see Multi-Stage Pipeline

Sample below is a template but not actual implementation

Which will deploy Build Angular Application, Deploy Function App, and then Deploy Angular App

# Multi-stage pipeline to deploy Angular app and C# function app to Azure

trigger:
- main

stages:
- stage: BuildAngular
  displayName: 'Build Angular App'
  jobs:
  - job: Build
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - task: NodeTool@0
      inputs:
        versionSpec: '14.x'
      displayName: 'Install Node.js'
    - script: |
        npm install -g @angular/cli
        npm install
      displayName: 'Install Angular CLI and dependencies'
    - script: |
        ng build --prod
      displayName: 'Build Angular app'

- stage: DeployFunctionApp
  displayName: 'Deploy Function App'
  dependsOn: BuildAngular
  jobs:
  - job: Deploy
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      azureSubscription: '<Azure subscription name>'
      resourceGroupName: '<resource group name>'
      functionAppName: '<function app name>'
      region: '<region name>'
    steps:
    - task: DotNetCoreCLI@2
      inputs:
        command: 'publish'
        publishWebProjects: true
        projects: '**/*.csproj'
        arguments: '-o $(Build.ArtifactStagingDirectory)'
      displayName: 'Publish Function App'
    - task: AzureRmWebAppDeployment@4
      inputs:
        ConnectionType: 'AzureRM'
        azureSubscription: $(azureSubscription)
        appType: 'functionApp'
        appName: $(functionAppName)
        package: '$(Build.ArtifactStagingDirectory)/**/*.zip'
        runtimeStack: DOCKER|microsoft/azure-functions-dotnet:4
        ResourceGroupName: $(resourceGroupName)
        SlotName: 'production'
        region: $(region)

- stage: DeployAngularApp
  displayName: 'Deploy Angular App'
  dependsOn: BuildAngular
  jobs:
  - job: Deploy
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      azureSubscription: '<Azure subscription name>'
      resourceGroupName: '<resource group name>'
      webAppName: '<web app name>'
      region: '<region name>'
    steps:
    - task: AzureWebApp@1
      inputs:
        azureSubscription: $(azureSubscription)
        appType: 'webAppLinux'
        appName: $(webAppName)
        package: '$(System.DefaultWorkingDirectory)/dist/<angular app name>'
        runtimeStack: 'NODE|14-lts'
        region: $(region)
        resourceGroupName: $(resourceGroupName)

You'll need to replace the placeholder values (<Azure subscription name>, <resource group name>, <function app name>, <web app name>, <region name>, and <angular app name>) with your actual values.

Following tweaks you might need to do it here.

  1. Also, you replace the variable section like the following to read the variable from Azure DevOps (It's already defined above)
   variables:
      - group: Release
  1. You can define the environment from Azure DevOps (It's already defined above)
environment: spike
  1. and Azure subscription name from Azure DevOps (It's already defined above)
 inputs:
    azureSubscription: 'Resource Manager - Function - Demo' 
  1. Make sure you $(functionAppName) and $(webAppName)
  $(webAppName): sample-func-web-16527
  $(functionAppName): sample-func-16527

Thanks for reading!


Posted on March 11, 2023
Profile Picture

Arun Yadav

Software Architect | Full Stack Web Developer | Cloud/Containers

Subscribe
to our Newsletter

Signup for our weekly newsletter to get the latest news, articles and update in your inbox.