Can I create an Azure Container Apps in Terraform? Yes, you can!

This post has been republished via RSS; it originally appeared at: New blog articles in Microsoft Tech Community.

Dapr (Distributed Application Runtime) is a runtime that helps you build resilient stateless and stateful microservices. This sample shows how to deploy a Dapr application to Azure Container Apps using Terraform modules and the AzAPI Provider instead of an Azure Resource Manager (ARM) or Bicep template like in the original tutorial Deploy a Dapr application to Azure Container Apps with an Azure Resource Manager or Bicep template. You can find the code of this sample along with Terraform modules under this Azure Sample.

 

In this sample you will learn how to:

 

  • Use Terraform and AzAPI Provider to deploy a microservice-based application to Azure Contains Apps.
  • Create an Azure Blob Storage for use as a Dapr state store
  • Deploy an Azure Container Apps environment to host one or more Azure Container Apps
  • Deploy two Dapr-enabled Azure Container Apps: one that produces orders and one that consumes orders and stores them
  • Verify the interaction between the two microservices.

 

With Azure Container Apps, you get a fully managed version of the Dapr APIs when building microservices. When you use Dapr in Azure Container Apps, you can enable sidecars to run next to your microservices that provide a rich set of capabilities. Available Dapr APIs include Service to Service calls, Pub/Sub, Event Bindings, State Stores, and Actors. In this sample, you deploy the same applications from the Dapr Hello World quickstart. The application consists of:

 

  • A client (Python) container app to generate messages.
  • A service (Node) container app to consume and persist those messages in a state store

 

The following architecture diagram illustrates the components that make up this tutorial:

 

azure-container-apps-microservices-dapr.png

 

Prerequisites

 

What is AzAPI Provider?

The AzAPI Provider is a very thin layer on top of the Azure ARM REST APIs. This provider compliments the AzureRM provider by enabling the management of Azure resources that are not yet or may never be supported in the AzureRM provider such as private/public preview services and features. The AzAPI provider enables you to manage any Azure resource type using any API version. This provider complements the AzureRM provider by enabling the management of new Azure resources and properties (including private preview). For more information, see Overview of the Terraform AzAPI provider.

 

Terraform modules

This sample contains Terraform modules to create the following resources:

The following table contains the code of the modules/contains_apps/main.tf Terraform module used to create the Azure Container Apps environment, Dapr components, and Container Apps.

 

 

terraform { required_version = ">= 1.0" required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.3.0" } azapi = { source = "Azure/azapi" version = "0.4.0" } } experiments = [module_variable_optional_attrs] } locals { module_tag = { "module" = basename(abspath(path.module)) } tags = merge(var.tags, local.module_tag) } resource "azapi_resource" "managed_environment" { name = var.managed_environment_name location = var.location parent_id = var.resource_group_id type = "Microsoft.App/managedEnvironments@2022-03-01" tags = local.tags body = jsonencode({ properties = { daprAIInstrumentationKey = var.instrumentation_key appLogsConfiguration = { destination = "log-analytics" logAnalyticsConfiguration = { customerId = var.workspace_id sharedKey = var.primary_shared_key } } } }) lifecycle { ignore_changes = [ tags ] } } resource "azapi_resource" "daprComponents" { for_each = {for component in var.dapr_components: component.name => component} name = each.key parent_id = azapi_resource.managed_environment.id type = "Microsoft.App/managedEnvironments/daprComponents@2022-03-01" body = jsonencode({ properties = { componentType = each.value.componentType version = each.value.version ignoreErrors = each.value.ignoreErrors initTimeout = each.value.initTimeout secrets = each.value.secrets metadata = each.value.metadata scopes = each.value.scopes } }) } resource "azapi_resource" "container_app" { for_each = {for app in var.container_apps: app.name => app} name = each.key location = var.location parent_id = var.resource_group_id type = "Microsoft.App/containerApps@2022-03-01" tags = local.tags body = jsonencode({ properties: { managedEnvironmentId = azapi_resource.managed_environment.id configuration = { ingress = try(each.value.configuration.ingress, null) dapr = try(each.value.configuration.dapr, null) } template = each.value.template } }) lifecycle { ignore_changes = [ tags ] } }

 

 

As you can see, the module uses an azapi_resource to create the resources. You can use an azapi_resource to fully manage any Azure (control plane) resource (API) with full CRUD. Example Use Cases:

  • New preview service
  • New feature added to existing service
  • Existing feature / service not currently covered

For more information, see Overview of the Terraform AzAPI provider.

 

Deploy the sample

You can use the deploy.sh bash script to deploy the sample:

 

 

#!/bin/bash # Terraform Init terraform init # Terraform validate terraform validate -compact-warnings # Terraform plan terraform plan -compact-warnings -out main.tfplan # Terraform apply terraform apply -compact-warnings -auto-approve main.tfplan

 

 

This command deploys the Terraform modules that create the following resources:

 

  • The Container Apps environment and associated Log Analytics workspace for hosting the hello world Dapr solution.
  • An Application Insights instance for Dapr distributed tracing.
  • The nodeapp app server running on targetPort: 3000 with dapr enabled and configured using: "appId": "nodeapp" and "appPort": 3000.
  • The daprComponents object of "type": "state.azure.blobstorage" scoped for use by the nodeapp for storing state.
  • The headless pythonapp with no ingress and Dapr enabled that calls the nodeapp service via dapr service-to-service communication.

 

Verify the result

 

Confirm successful state persistence

You can confirm that the services are working correctly by viewing data in your Azure Storage account.

  1. Open the Azure portal in your browser.
  2. Navigate to your storage account.
  3. Select Containers from the menu on the left side.
  4. Select state.
  5. Verify that you can see the file named order in the container.
  6. Select on the file.
  7. Select the Edit tab.
  8. Select the Refresh button to observe updates.

 

View Logs

Data logged via a container app are stored in the ContainerAppConsoleLogs_CL custom table in the Log Analytics workspace. You can view logs through the Azure portal or from the command line. Wait a few minutes for the analytics to arrive for the first time before you query the logged data.

 

  1. Open the Azure portal in your browser.
  2. Navigate to your log analytics workspace.
  3. Select Logs from the menu on the left side.
  4. Run the following Kusto query.

 

ContainerAppConsoleLogs_CL 
| project TimeGenerated, ContainerAppName_s, Log_s
| order by TimeGenerated desc

The following images shows the type of response to expect from the command.

 

logs.png

Clean up resources

Once you are done, run the following command to delete your resource group along with all the resources you created in this tutorial.

 

az group delete \
  --resource-group $RESOURCE_GROUP

 

Since pythonapp continuously makes calls to nodeapp with messages that get persisted into your configured state store, it is important to complete these cleanup steps to avoid ongoing billable operations.

 

Next steps

 

 

Conclusion

 

If you have any feedback, please write a comment below or submit an issue or a PR on GitHub. If you found this article and companion sample useful, please like the article below and give a star to the project on GitHub, thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.