Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zero-downtime deployment of Azure Functions with Terraform

I have an Azure Function App where the necessary cloud infrastructure is scripted by Terraform. The relation to application archive is implemented via azurerm_storage_blob and the app_settings property WEBSITE_RUN_FROM_PACKAGE.

// ...

resource "azurerm_storage_blob" "archive" {
  name                   = "application.zip"
  storage_account_name   = var.storage_account_name
  storage_container_name = var.storage_container_name
  type                   = "Block"
  source                 = "dist/application.zip"
}

resource "azurerm_function_app" "app" {
  name                      = "function-app"
  resource_group_name       = var.resource_group_name
  location                  = var.location
  app_service_plan_id       = var.azurerm_app_service_plan_id
  storage_connection_string = var.storage_connection_string

  app_settings = {
    // ...
    WEBSITE_RUN_FROM_PACKAGE     = "https://${var.storage_account_name}.blob.core.windows.net/${var.storage_container_name}/${azurerm_storage_blob.archive.name}${var.storage_account_sas}"
  }
}

// ...

To deploy a new version of the Function App, I taint the azurerm_storage_blob and run terraform apply. During the execution of the command the Function App isn't avialable for sevaral seconds.

How can I implemented a zero-downtime deployment with Terraform?


I found two approaches but couldn't solve the problem.

  1. Terraform's create_before_destroy shouldn't be working because the azurerm_function_app is updated by Terraform.
  2. Terraform's azurerm_app_service_slot isn't ready for Function Apps (#1307, #4684)
like image 513
sschmeck Avatar asked Nov 22 '25 02:11

sschmeck


1 Answers

TL;DR: the azurerm_app_service_slot issues are resolved by PR#6435 and documented by Terraform and Microsoft. This answer doesn't yet cover that completely. To avoid deleting and then recreating your blob, change your blob name when your code changes and add HASH to your app_settings:

resource "azurerm_storage_blob" "archive" {
  name                   = "application.${var.package_version}.zip"
  ...
}

resource "azurerm_function_app" "app" {
  ...
}

resource "azurerm_function_app_slot" "slotStaging" {
  name                       = "stag"
  function_app_name          = azurerm_function_app.app.name
  ...
  app_settings = {
    ...
    HASH = base64encode(filesha256("dist/application.zip"))
  }
}

resource "null_resource" "swapSlots" {
  triggers = {
    HASH = azurerm_function_app.app.app_settings.HASH
  }
  provisioner "local-exec" {
    command = "sleep 1m && az functionapp deployment slot swap -g ${azurerm_resource_group.resourceGroup.name} -n ${azurerm_function_app.functionApp.name} --slot ${azurerm_function_app_slot.slotStaging.name} --target-slot production"
  }
  depends_on = [azurerm_function_app.functionApp]
}

Explanation: There is a first issue impacting you described at https://github.com/terraform-providers/terraform-provider-azurerm/issues/1990. Basically that Terraform wont detect changes to the content of your zip and needs a mechanism to do so. Making sure the package version name is in the blob name ensure it is updated when a new change happens. It can be any name change, it just seems more elegant to rely on semver.

So long as your code is updated to the bucket and the HASH of it is part of your function's config (as automatically calculated), then Terraform will know to update the function to reload the new code. This will happen as a no downtime configuration change such that the previous code version will be invalidated and a new container will be composed and deployed to your host to handle the next request it is ready to catch.

WIP The default slot is production. Pushing your updated code into the stag slot followed by the swapping from stag to production

The slot is transitioned with az functionapp deployment slot swap -g MyResourceGroup -n MyUniqueApp --slot staging --target-slot production which can be run in a null_resource.

like image 89
Erik Erikson Avatar answered Nov 24 '25 23:11

Erik Erikson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!