skip to Main Content

How does Bicep (ARM) keep track of the state?

I’m used to Terraform, which will keep track of state, and add/remove resources depending on the configuration. But with Bicep (ARM), I’m confused.

I’m currently deploying my Bicep file to a resource group from GitHub actions:

- name: Deploy
  uses: azure/arm-deploy@v2
  with:
    deploymentName: ${{ github.run_number }}
    scope: resourcegroup
    resourceGroupName: ${{ env.AZURE_RESOURCE_GROUP_NAME }}
    template: ./infrastructure/main.bicep
    parameters: >
      environmentType=${{ env.ENVIRONMENT }}
    failOnStdErr: false

It generates a series of deployments:

enter image description here

But when I remove resources from the file, they’re not deleted. Instead, Bicep (ARM) decides to ignore them.

  • Where does the Bicep (ARM) store state?
  • How does Bicep (ARM) know it should delete resources not in the file?
  • How can I add existing resources to the state?

main.bicep:

@description('The Azure region into which the resources should be deployed.')
param location string = resourceGroup().location

@description('The type of environment. This must be dev or prod.')
@allowed([
  'dev'
  'prod'
])
param environmentType string

@description('A unique suffix to add to resource names that need to be globally unique.')
@maxLength(13)
param resourceNameSuffix string = uniqueString(resourceGroup().id)

var appServiceAppName = 'todo-website-${resourceNameSuffix}'
var appServicePlanName = 'todo-website-plan'
var appStorageAccountName = 'todoweb${resourceNameSuffix}'

// Define the SKUs for each component based on the environment type.
var environmentConfigurationMap = {
  dev: {
    appServicePlan: {
      sku: {
        name: 'F1'
        capacity: 1
      }
    }
    appStorageAccount: {
      sku: {
        name: 'Standard_LRS'
      }
    }
  }
  prod: {
    appServicePlan: {
      sku: {
        name: 'S1'
        capacity: 2
      }
    }
    appStorageAccount: {
      sku: {
        name: 'Standard_ZRS'
      }
    }
  }
}

var appStorageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${appStorageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${appStorageAccount.listKeys().keys[0].value}'

resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
  name: appServicePlanName
  location: location
  sku: environmentConfigurationMap[environmentType].appServicePlan.sku
}

resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = {
  name: appServiceAppName
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
    siteConfig: {
      appSettings: [
        {
          name: 'appStorageAccountConnectionString'
          value: appStorageAccountConnectionString
        }
      ]
    }
  }
}

resource appStorageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: appStorageAccountName
  location: location
  kind: 'StorageV2'
  sku: environmentConfigurationMap[environmentType].appStorageAccount.sku
}

2

Answers


  1. Where does Bicep (ARM) store state?

    The bicep does not have a state. It has by default incremental deployment or complete deployment.

    The nearest thing it does is incremental deployment, which means when you change resources, it will keep old resources as is and make the necessary changes.

    Regarding incremental deployment, you can see what has been deployed in Azure Portal at the Subscription or Resource level as you already have mentioned.

    It is worth noting that if you make some manual changes in resources via the portal or CLI if the change parameters are not part of the bicep, these manual changes will be kept by redeploying the bicep. Or there are situations like if you change the SA username for the MSSQL instance manually, and try to redeploy it will give an error.

    enter image description here

    Here you can read about modes: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/deployment-modes#incremental-mode.

    How does Bicep (ARM) know that it should delete resources not present in the file?

    This should be done manually. or using the command line.

    How can I add existing resources to the state?

    What regards, existing resources you can check existing:

    https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/existing-resource

    Answer to comments

    You say: It is worth noting that if you make some manual changes in resources via the portal or CLI if the change parameters are not part of the bicep, these manual changes will be kept by redeploying the bicep. – So, Bicep isn’t capable for detecting "drift", i.e. resource changes, but it would first consider the resource, the next time I change some of its attributes in the Bicep file?

    That is correct, check https://github.com/Azure/deployment-stacks/issues/117 and https://github.com/Azure/bicep/issues/10782

    When using Terraform, if I try to create a resource that already exist, Terraform will fail. How does Bicep behave in this case? Would it modify the existing resource, re-create it, or simply fail?

    As far as I have tried with most common Azure resources, it does not fail, if you try to deploy a resource Group or a Ressource with bicep and that resource Group or a Ressource exists, it will adapt it and Carey on. Of course, it will return the object information when so. For instance, I created a Ressource Group manually and tried deploying bicep using the same name, and it worked fine, I tried doing it for Application Insihgt and a key vault, and both, worked fine.

    If you deploy bicep on an existing resource group or resources with the same name,

    Are there any positive aspects of Bicep’s approach to IaC: incremental deployment? I have experience with both Terraform and AWS CDK (CloudFormation), and coming from this background, Bicep seems very simplistic and feature-lacking, but maybe I don’t understand its strengths and design ideas.

    Bicep indeed lacks features compared to Terraform, and the main benefit of Terraform is state, but some clients chose to use Bicep because Microsoft supports it and gets updates. I used Terraform and Bicep, both have cons and pros, bottom line I am happy for both, in most cases the clients I Work for decide to use Bicep. And it works fine.

    With all that said, I encourage you to have at least 2 environments non-production and production, if you want to make an experiment do it on a non-production like dev or test. and when you are confident, deploy it to production.

    There are features like lock resources to ensure you do not delete resources recently, and you can split your deployment into the president and non-persistence resources, like a database or key vault etc.

    Login or Signup to reply.
  2. This is an interesting question to ask. Bicep doesn’t have a state file, comparing it to Terraform in that way could be misleading, something I also struggled to understand having use Terraform first before bicep.

    Bicep takes it’s state directly from Azure, Terraform maintains a state file which it uses as it’s source of truth. By default when you run Terraform Plan or Apply it will also run a refresh command against the infrastructure in Azure to compare it to the state in Azure and modify the state file if needed.

    ARM has 2 deployment modes:

    • Complete mode: Resource Manager deletes resources that exist in the resource group but aren’t specified in the template.

    • Incremental mode: Resource Manager leaves unchanged resources that exist in the resource group but aren’t specified in the template. Resources in the template are added to the resource group.

    But when I remove resources from the file, they’re not deleted. Instead, Bicep (ARM) decides to ignore them.

    This is because By default ARM uses Incremental mode. If you want the resources to be deleted when removed from the bicep template file, you have to use Complete mode, by passing the --mode complete parameter.

    Also Bicep preview feature is what-if similar to terraform’s plan use to preview deployment effects before they are plan.

    How can I add existing resources to the state?

    Bicep has no statefile, but you can reference existing resources by adding the existing keyword to the Bicep resource block, similar to Terraform’s [data block][4].

    To fully manage the resource with Bicep (e.g migrating from portal-deployed to Bicep), write your Bicep code using the actual resource block without the existing keyword. Unlike Terraform, you don’t need to import the state. There’s no need to worry about running Terraform state import commands, just writing your Bicep code is sufficient. Then, of course your preview command to be sure you don’t break things.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search