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:
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
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.
Here you can read about modes: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/deployment-modes#incremental-mode.
This should be done manually. or using the command line.
What regards, existing resources you can check
existing
:https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/existing-resource
Answer to comments
That is correct, check https://github.com/Azure/deployment-stacks/issues/117 and https://github.com/Azure/bicep/issues/10782
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,
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.
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.
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’splan
use to preview deployment effects before they are plan.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.