Skip to content

05 - Infrastructure as Code (Consumption)

Define and deploy a complete Consumption (Y1) environment with Bicep. This plan is simpler than Flex: no VNet integration requirement, no private endpoints, and no mandatory managed identity (recommended for app access patterns).

Prerequisites

Tool Version Purpose
Azure CLI 2.61+ Run Bicep deployments
Bicep latest Author ARM resources as code
Target path infra/consumption/main.bicep Consumption IaC template location

What You'll Build

You will deploy storage, a Linux Consumption plan, and a Python Function App via Bicep, then validate the deployed app metadata with Azure CLI.

Infrastructure Context

Plan: Consumption (Y1) | Network: Public internet only | VNet: ❌ Not supported

Consumption has no VNet integration or private endpoint support. All traffic flows over the public internet. Storage uses connection string authentication.

flowchart TD
    INET[Internet] -->|HTTPS| FA[Function App\nConsumption Y1\nLinux Python 3.11]

    FA -->|System-Assigned MI| ENTRA[Microsoft Entra ID]
    FA -->|"AzureWebJobsStorage__accountName\n+ connection string"| ST[Storage Account\npublic access]
    FA --> AI[Application Insights]

    subgraph STORAGE[Storage Services]
        ST --- FS[Azure Files\ncontent share]
    end

    NO_VNET["⚠️ No VNet integration\nNo private endpoints"] -. limitation .- FA

    style FA fill:#0078d4,color:#fff
    style NO_VNET fill:#FFF3E0,stroke:#FF9800
    style STORAGE fill:#FFF3E0
flowchart TD
    A[Bicep template] --> B[Storage account]
    A --> C[Linux Consumption plan Y1]
    A --> D[Function App]
    D --> E[CLI validation]

Steps

Step 1 - Set variables

export RG="rg-func-consumption-demo"
export APP_NAME="func-consumption-demo-001"
export STORAGE_NAME="stconsumptiondemo001"
export LOCATION="koreacentral"

Step 2 - Create the resource group

az group create --name "$RG" --location "$LOCATION"
CLI element Explanation
Command(s) az group create
Key flags --name, --location
Variables $RG, $LOCATION
Expected result Azure CLI returns provisioning details; confirm the resource name and successful provisioning state before continuing.

Step 3 - Author infra/consumption/main.bicep

Use a Consumption plan resource with Y1/Dynamic SKU and classic app settings on the Function App:

param location string = resourceGroup().location
param appName string
param storageName string

resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}

resource plan 'Microsoft.Web/serverfarms@2023-12-01' = {
  name: 'asp-${appName}'
  location: location
  kind: 'linux'
  sku: {
    name: 'Y1'
    tier: 'Dynamic'
  }
  properties: {
    reserved: true
  }
}

resource app 'Microsoft.Web/sites@2023-12-01' = {
  name: appName
  location: location
  kind: 'functionapp,linux'
  properties: {
    serverFarmId: plan.id
    siteConfig: {
      linuxFxVersion: 'Python|3.11'
      appSettings: [
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'python'
        }
        {
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
        }
        {
          name: 'WEBSITE_CONTENTSHARE'
          value: toLower('cs-${appName}')
        }
      ]
    }
    httpsOnly: true
  }
}
!!! info "Simplified vs production template"
    The Bicep template above is a simplified standalone example for learning. The repository's production template at `infra/consumption/main.bicep` uses shared modules, identity-based host storage with RBAC role assignments, Application Insights, and a `baseName` parameter convention. For production deployments, use the full template.

To deploy using the repository's production template instead:

```bash
az deployment group create \
  --resource-group "$RG" \
  --template-file "infra/consumption/main.bicep" \
  --parameters baseName="func-consumption-demo"
| Command/Parameter | Purpose | | --- | --- | | az deployment group create | Deploy a Bicep/ARM template to a resource group. | | --resource-group | Resource group that contains the resource. | | --template-file | Path to the Bicep/ARM template. | | --parameters | Template parameter values. |

Step 4 - Deploy the Bicep template

az deployment group create \
  --resource-group "$RG" \
  --template-file "infra/consumption/main.bicep" \
  --parameters baseName="func-consumption-demo"
| Command/Parameter | Purpose | | --- | --- | | az deployment group create | Deploy a Bicep/ARM template to a resource group. | | --resource-group | Resource group that contains the resource. | | --template-file | Path to the Bicep/ARM template. | | --parameters | Template parameter values. |

Parameter names

The simplified template above uses appName and storageName parameters. The production template at infra/consumption/main.bicep uses a single baseName parameter that derives all resource names automatically.

Step 5 - Validate resulting host plan

az functionapp show \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --query "{kind:kind,state:state,defaultHostName:defaultHostName}" \
  --output json
| Command/Parameter | Purpose | | --- | --- | | az functionapp show | Show details of the function app. | | --name | Name of the target resource. | | --resource-group | Resource group that contains the resource. | | --query | JMESPath query selecting fields from the response. | | --output | Output format. |

Not available on Consumption

VNet integration requires Flex Consumption, Premium, or Dedicated plan.

Not available on Consumption

Private endpoints require Flex Consumption, Premium, or Dedicated plan.

Verification

Deployment output excerpt:

{
  "id": "/subscriptions/<subscription-id>/resourceGroups/rg-func-consumption-demo/providers/Microsoft.Resources/deployments/main",
  "name": "main",
  "properties": {
    "provisioningState": "Succeeded"
  }
}

Function app validation output:

{
  "defaultHostName": "func-consumption-demo-001.azurewebsites.net",
  "kind": "functionapp,linux",
  "state": "Running"
}

Next Steps

Automate deployments in CI/CD with GitHub Actions.

Next: 06 - CI/CD

See Also

Sources