Shawn Eary
Shawn Eary

Reputation: 750

Barebones Python Function App via IaC for Azure

I need a bare minimum Bicep file to create an EMPTY Python 3.11 Function App in Azure via Infrastructure as Code (IaC). I do not want App Insights support. I should be able to deploy to a preexisting resource group named rg-py-func-tst via this one line command:

az deployment group create --resource-group rg-py-func-tst --template-file main.bicep

I've looked at samples on Git, tried exporting templates directly out of Azure, and even briefly attempted to use Azure Resource Manager (ARM) templates. Through all of that, this Bicep seems most reasonable to me:

// Created by Microsoft Copilot and Google Gemini
// This Bicep script deploys an EMPTY Python 3.11 Function App named
// 'shawnopyFuncTest' without App Insights, at service level Y1. 
// It creates a storage account named 'pyfunctest100', an app service
// plan named 'pyfunctestAppService', and the function app itself.
//
// I do not have the Python code yet. The Python code will be
// deployed in a separate project. I just want to create an 
// empty Python Function App

@description('Name of the storage account')
param storageAccountName string = 'pyfunctest100'

@description('Name of the app service plan')
param appServicePlanName string = 'pyfunctestAppService'

@description('Name of the function app')
param functionAppName string = 'shawnopyFuncTest'

@description('Location for all resources')
param location string = resourceGroup().location

// Define the storage account resource
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}

// Define the app service plan resource
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
  name: appServicePlanName
  location: location
  kind: 'linux'
  sku: {
    name: 'Y1'
    tier: 'Dynamic'
  }
  properties:{
    reserved: true
  }
}

// Define the function app resource (Updated API version)
resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp,linux'
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      linuxFxVersion: 'Python|3.11'
      appSettings: [
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'python'
        }
        {
          name: 'AzureWebJobsStorage'
          value: storageAccount.properties.primaryEndpoints.blob
        }
      ]
    }
  }
}

output storageAccountName string = storageAccount.name
output appServicePlanName string = appServicePlan.name
output functionAppName string = functionApp.name

I've ran the above deployment in two completely separate Azure tenants and the result is always the same. My resource group rg-py-func-tst is populated with: a Storage Account named pyfunctest100; an App Service Plan named pyfunctestAppService; and, a Function App named shawnopyFuncTest. That's what I want; unfortunately, that isn't the end of the story.

When I open my newly deployed empty Function App shawnopyFuncTest, I see the text "Error" in the Runtime Version field: Azure Portal Function App Page showing Runtime Version of Error

But what I expect to see for an empty Python function app is this: Azure Portal Function App Page for a Fresh Empty Python Function App Runtime Version is 4.1036.2.2

Can someone please help me correct the Bicep that MS Copilot and Gemini created? If not, can you provide a simpler, more clean template that still does what I need?

Upvotes: 0

Views: 79

Answers (1)

evgeny
evgeny

Reputation: 1170

According to the docs you can (should) target specific runtime version by passing FUNCTIONS_EXTENSION_VERSION value via appSettings. See modifed example below.

enter image description here



// Created by Microsoft Copilot and Google Gemini
// This Bicep script deploys an EMPTY Python 3.11 Function App named
// 'shawnopyFuncTest' without App Insights, at service level Y1. 
// It creates a storage account named 'pyfunctest100', an app service
// plan named 'pyfunctestAppService', and the function app itself.
//
// I do not have the Python code yet. The Python code will be
// deployed in a separate project. I just want to create an 
// empty Python Function App

@description('Name of the storage account')
param storageAccountName string = 'pyfunctest100'

@description('Name of the app service plan')
param appServicePlanName string = 'pyfunctestAppService'

@description('Name of the function app')
param functionAppName string = 'shawnopyFuncTest'

@description('Location for all resources')
param location string = resourceGroup().location

// Define the storage account resource
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}

// Define the app service plan resource
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
  name: appServicePlanName
  location: location
  kind: 'linux'
  sku: {
    name: 'Y1'
    tier: 'Dynamic'
  }
  properties:{
    reserved: true
  }
}

// Define the function app resource (Updated API version)
resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp,linux'
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      linuxFxVersion: 'Python|3.11'
      appSettings: [
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'python'
        }
        {
          name: 'AzureWebJobsStorage'
          value: storageAccount.properties.primaryEndpoints.blob
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
      ]
    }
  }
}

output storageAccountName string = storageAccount.name
output appServicePlanName string = appServicePlan.name
output functionAppName string = functionApp.name


Upvotes: 1

Related Questions