Deploying Azure Function App with Terraform and BitBucket Cloud
The scenario describes one or more developers committing their changes of code for a serverless Azure Function App ("Function-as-a-Service") and managing the required Azure environment resources only by a declaration in Terraform scheme in the code repository to remain the Single Point of Truth (SPOT).
We want to use the events on the repository connected with the specified Terraform Cloud Workspace, e.g. the commit push or the successful merge of a Pull Request to a specific branch, to trigger specific updates in certain environments. Typically, there are some development or quality-check environments, and of course the production.
In the scenario, Terraform will listen to the master branch of the repository, and uses the declared configuration of the environment to set up Azure Cloud with the required resources, which will already be prepared to be connected to the repository to listen to, as to keep the application up to date if further code changes appear.
Preparations
- Create a Terraform cloud account
- Download Terraform CLI for testing purposes
- Prepare a new BitBucket Cloud repository
- Connect Terraform and BitBucket
- Prepare Azure Subscription
- Create a function app
Create a new Terraform Cloud workspace and connect it to your BitBucket Cloud repository.
Add the required environmental variables to deploy to the Azure Cloud Platform.
Terraform Configuration
The following will be specified as a Terraform configuration file (v0.12), e.g. terraform.tf, in the root directory of the project. Multiple files and the module scheme usage are possible, but for simplicity, only one file is used in this scenario. Replace placeholder values with the specific ones of your own setup.
variable "prefix" {
description = "The Prefix used for all resources in this example"
default = "AllInData"
}
variable "location" {
description = "The Azure Region in which all resources in this example should be created."
default = "westeurope"
}
provider "azurerm" {
version = "~>2.0"
features {}
}
resource "azurerm_resource_group" "terraformDemo-rg" {
name = "${var.prefix}_Terraform_Demo"
location = var.location
}
resource "azurerm_storage_account" "terraformDemo-storage" {
name = "allindatatfdemostorage"
resource_group_name = azurerm_resource_group.terraformDemo-rg.name
location = azurerm_resource_group.terraformDemo-rg.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_app_service_plan" "terraformDemo-appplan" {
name = "${var.prefix}-slotAppServicePlan"
location = azurerm_resource_group.terraformDemo-rg.location
resource_group_name = azurerm_resource_group.terraformDemo-rg.name
sku {
tier = "Standard"
size = "S1"
}
}
resource "azurerm_function_app" "terraformDemo-funcapp" {
name = "${var.prefix}-funcapp"
location = azurerm_resource_group.terraformDemo-rg.location
resource_group_name = azurerm_resource_group.terraformDemo-rg.name
app_service_plan_id = azurerm_app_service_plan.terraformDemo-appplan.id
storage_connection_string = azurerm_storage_account.terraformDemo-storage.primary_connection_string
app_settings = {
"APPINSIGHTS_INSTRUMENTATIONKEY" = "XXXXXXXXX",
"FUNCTIONS_WORKER_RUNTIME" = "dotnet",
"FUNCTIONS_EXTENSION_VERSION" = "~2" ,
"WEBSITE_RUN_FROM_PACKAGE" = ""
}
version = "~2"
https_only = true
site_config {
always_on = true
ftps_state = "Disabled"
http2_enabled = true
}
provisioner "local-exec" {
command = "az functionapp deployment source config --ids ${azurerm_function_app.terraformDemo-funcapp.id} --repo-url https://bitbucket.org/XXX/YYY --branch master --manual-integration"
}
}
Test configuration locally
After installing the Terraform CLI locally on your machine, it is possible to test the configuration without the need of triggering events in the git repository. Currently, the environmental state is persisted on the machine executing the commands. Note, that there will be a fuzzified state mix-up if the state is not persisted remotely in a central storage and the commands are triggered from a different machine.
Terraform Cloud does not know what your local machine knows about the Azure Cloud environment, but there is a solution for this, which I added as a notification at the end of this article.
For testing your Terraform configuration, run the plan command. This just checks with the target environment, but no changes will be applied, so it is saved to execute the command.
terraform plan
For the execution of the Terraform configuration plan (pre-saved or newly processed), use the apply command. It will ask you if you are sure to execute, and if you are, you enter yes to the command line. This is for the local machine. On Terraform Cloud, you can configure in your workspace settings, if an intermitting manual confirmation is required, so both options of supervised and unsupervised execution are possible.
terraform apply
Run remotely on Terraform Cloud
After the correct configuration of our workspace in Terraform Cloud, we add a connection to a BitBucket Cloud repository and add the required Environment variables for Azure Deployment.
If you push code changes to the BitBucket Cloud repository, the Terraform Cloud workspace will recognize those changes nearly immediately and starts the execution of the configuration.
Review your workspace, if the Terraform plan has been successfully placed, and confirm the execution.
You can now revise the Azure Cloud Platform, and see (maybe with some minor delay) the creation and build-up of the declared environment by Terraform.
Remote state provider
If you mix the deployment with Terraform Cloud and the local command line, the persisted states get mixed up. The states are stored on the running machine (Terraform Cloud or your local machine), so what you really want in this case is a remote storage for the states. So while we are using Azure Cloud Platform in this scenario, we can store the states there, in a separate and remote Storage Account.