Deploying CI Node Azure Functions to Deployment Slots

I’ll be honest, coming up with a title for this post was very difficult, but here we are.

If you’ve read through the previous posts on setting up Azure Functions with Node.js – we created the Azure Function, automated deployment to Azure, and dealt with some build issues.

Now comes the cool stuff: deploying your Node.js function to an Azure Deployment Slot.

What is an Azure Deployment Slot?

Think of a deployment slot as a staging ground where you can test out new code in the same codespace as your existing functions, and then, when you’re ready to go you can swap them. In our previous post on CI builds with YAML, we were always deploying straight to the live service, which could have unintended consequences if something goes wrong.

In my environment, I have the following configuration of a “noder” service and a “noder-staging” service. Creating noder-staging, was as easy as clicking add and giving it a name. You can see from the screenshot below that currently, noder is live.

YAML Parameters

Now, at some point, I’m going to take this YAML script a bit further and have it be able to deploy from AzureDevOps, so to do that, I want to introduce the functionality to allow users to select which slot to deploy to. To accomplish this, I create a parameter, populate it with values and then I’ll be able to use the user’s input throughout my script.

The below code creates a parameter called “DeploymentSlotName” and allows users to select either noder or staging as values (this is important as we’ll see later) and the default is set to staging when running as a CI Build.

parameters:
- name: DeploymentSlotName
  type: string
  default: 'staging'
  values:
    - noder
    - staging     

If I were to click “Run” I’d get this totally jazzy prompt.

If you want to see the value of your parameter at run-time, the script below is very helpful. Note the difference in syntax when calling the value of a parameter when compared to a variable.

  - script: echo "Deploying to slot - ${{ parameters.DeploymentSlotName }}"
    displayName: 'Debug Parameter DeploymentSlot'

AzureFunctionApp@1 to AzureWebApp@1

The last bit in our script is to tell our YAML Code to take the Deployment Slot name as a parameter to deploy it to. I had originally thought this would have been a simple task.

I was wrong.

  - task: AzureFunctionApp@1
    inputs:
      azureSubscription: $(azureSubscription)
      appType: 'functionAppLinux'
      appName: $(functionAppName)
      package: $(packagePath)
      slotName: ${{ parameters.DeploymentSlotName }}
    displayName: 'Deploy Azure Function App'

In all cases, AzureFunctionApp@1 ignores the “slotName” parameter. To get around this, I had to upgrade the slightly different “AzureWebApp@1” task.

  - task: AzureWebApp@1
    inputs:
      azureSubscription: $(azureSubscription)
      appName: $(functionAppName)
      package: $(packagePath)
      deployToSlotOrASE: true
      resourceGroupName: 'buildervalidation-rg'
      slotName: ${{ parameters.DeploymentSlotName }}

There are a few new parameters to note here;

  1. deployToSlotOrASE – this field needs to be enabled to true as it tells the task to use the specified name in your deployment slot variable.
  2. resourceGroupName – This is the resource group where your code is located. I would not hardcode this, but I did in my example, add another parameter. When deployToSlotOrASE is set to true, this parameter is required.

If you have configured things correctly, the next time you go to commit your code, you should see your function deploy to your default staging slot (and/or if selected to your production slot).

The “Real Name” of your Deployment Slot

It wasn’t until I switched task libraries to the AzureWebApp@1 task that I started to see why my code wasn’t deploying to my deployment slot, as the task interprets the name differently than it is presented in Azure.

As you can see here, the task is looking for a slot called noder-noder-staging, which does not exist.

When looking at the Azure Portal, the only item you need to pass in is the name of the function App itself (top left corner) and not the name listed in the slot below.