Deploy Python-based Azure Functions using Azure DevOps

Important note: this blog post covers in-preview services that are subject to change before launch. As such I’ll update this post as / when required to reflect official guidance from the Functions team on the best approach to deployments. Additionally, for the purpose of this post I am not deploying App Settings as there are existing methods that continue to work.

Know your versions

As this is under-development software it is important to provide context on versions that were used to produce this blog post. The key version being that of the Azure Functions Core Tools. The version installed and working here is 2.3.199-1. Python support currently sits at Python 3.6 with the underlying Functions tools needing .Net Core 2.1.502.

Foundation

Before working through this post it’s important that you are familiar with the Azure Functions (version 2) Python support. At the time of writing the best place to go for this is the Microsoft Docs site. Once you undestand the development and lifecycle of them then you’re ready for the rest of this post.

You will need to make sure you have a target Linux Function App in Azure ready for deployment as per the “Create Linux function app in Azure” section of the documentation.

When you have a working Python Function check it into an Azure Repos Git repository.

Define the Azure Pipelines Build

As a starting point ensure you have a Service Principal-based connection into the Azure Subscription you are going to deploy your Python Function to. This avoids anyone having to know usernames and passwords which is 👍.

The easiest way to setup your Build is to import the following YAML build definition and make the changes to the three locations (**yourfoldername**, **yourfunctionname**, **your azure subscription connection**).

My approach assumes that your Python Functions are stored as sub-folders inside Git. This allows you to store multiple unrelated Functions in a single repository which works in my scenerio as I am manually triggering builds because I don’t need to deploy all Functions at once.

You might be wondering why all this inline code is inside an Azure CLI task – the answer is that the actual deployment to Azure requires an active Azure CLI session.

I could probably break some of the earlier steps out into one or more Bash script task steps if I wanted, but for ease of maintenance I just made them a single script. I could also make the inline script an artefact in the repository and maintain it that way.

A lot of the work involved in the inline script (a copy of which is at the bottom of this post) is the result of a few items:

  • The requirement for the Azure Functions Core Tools to be installed
  • .Net Core is required by the Azure Functions Core Tools
  • Python 3.6 is required for Azure Functions Python support. The age of the Ubuntu distribution running the Azure DevOps hosted build agent means it doesn’t have Python 3.6 installed and Ubuntu don’t provide it (only Python 3.5). When these hosts are updated by Microsoft to a more modern Ubuntu release then this script will become much simpler
  • The need to re-initialise the Functions environment after check-out from Git with ‘init’ which overwrites our existing requirements.txt file
  • The need to manually restore any Extensions used in the Function.

My approach is functional, but there are clearly some sharp edges to it 🙂

There is also an implicit requirement (no pun intended!) on developers to maintain an up-to-date requirements.txt file, particularly as the Functions core Python and Functions Python runtime are both listed.

If you can’t (or don’t want to) use the XAML build definition above the visual definition setup is very simple – as shown below.

Build Definition

… and the inline script for you to use …

Depending on the complexity of your Python Functions and the location of your build Agent versus your Function App you should see a deployment complete within a few minutes (I’ve averaged around 7 minutes for a Python Function App with three Functions and a deployment package of 48MB).

Happy Days 😎

3 thoughts on “Deploy Python-based Azure Functions using Azure DevOps

  1. Hello Simon! I’m new to Azure pipelines, what is the input azureSubscription and how I get it? when is it used?

    1. Hi Pablo – the ‘azureSubscription’ value in the YAML definition is the display name of the Azure Subscription or Service Connection you will be deploying with.

      In my case I have an existing Service Principal connection called “MS FTE MSDN” and that value is what is contained in the YAML.

      The easiest way to find this value is to look at Project Settings > Pipelines > Service Connections in the Azure DevOps portal.

      When you define a designer-based build you will find this under the ‘Azure Subscription’ property on many Build Steps.

      Build step definition

      This information is required as it is the service connection into Azure for your Pipeline. If you didn’t have this you would be unable to deploy to Azure.

      Let me know if this doesn’t make sense!

      1. Thanks Simon! after i little lookup i found the option for creating a service principal under Project Settings and from there on it was intuitive.

        Thanks a lot!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s