Skip to main content

Command Palette

Search for a command to run...

Automating Azure Container App Deployment with Terraform and ACR Integration

Updated
8 min read
Automating Azure Container App Deployment with Terraform and ACR Integration
C

Computer Scientist/ Cloud Engineer/DevOps Engineer / Technical writer

Prerequisites

  1. Azure account (active)

  2. Docker Desktop installed

  3. Python installed

  4. VS code installed (with Azure account and Azure CLI extensions installed)

  5. terraform installed

Before You Get Started

  1. Clone the starter repository. to your local environment

    • Create folder for your project: mkdir -p

    • Navigate into it: cd

    • Clone the repo: git clone

    • Confirm you can see lab1: ls

    • Navigate to lab1 and work from there: cd lab1

  2. Run the application locally to confirm it works. Check the repo for instructions on how to run it.

    • Follow instruction on readme to run without docker

    • Validation:

    • Homepage:

      Health check:

  • press ctrl+c to proceed

Step 1: Modify the Application and Run Locally

  1. Update the application using  environment variables so that the homepage (/) displays:

    • Your Full Name

    • Cloud Platform → Azure

    • Environment → test

    • Version → v1.0.0

    • Status → healthy

  2. For the environment variables, use export at run time before running uvicorn app.main:app --reload For example

    export ENGINEER_NAME="Alice Wonderland"
    export CLOUD_PLATFORM="Azure"
    export Environment="test"
    
    • Validation:

      • Homepage:
  • Health check:

Step 2: Containerize the Application

  • Write or update the Dockerfile if necessary

  • Ensure the application runs on a defined port

  • Start Docker Desktop and ensure it is running

  • Build and run the container locally: see repo for instruction

Validation

  • Image builds successfully
  • Container runs correctly

Step 3: Create Needed infrastructure using Terraform

For this project, the following Azure infrastructures should be created first before the deployment of the container app.

  1. Resource Group

  2. Azure Container Registry

  3. Virtual Network

  4. Subnet

  5. Log Analytics Workspace

  6. Container Apps Environment

Create terraform manifest file

  1. Create a terraform directory in the root directory and create two terraform manifest files: one for the dependency infrastructure and the other for container app
  • Create main.tf file: run: Nano main.tf

    • Create your manifest file or use the below template
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">= 3.65.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "lab1-RG"
  location = "westus"
}

resource "azurerm_container_registry" "acr" {
  name                = "lab1acr689"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  sku                 = "Basic"
  admin_enabled       = true
}

resource "azurerm_virtual_network" "vnet" {
  name                = "lab1-vnet"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  address_space       = ["10.0.0.0/16"]
}

resource "azurerm_subnet" "subnet" {
  name                 = "containerapps-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.0.0/23"]

  delegation {
    name = "containerapps-delegation"

    service_delegation {
      name = "Microsoft.App/environments"
    }
  }
}

resource "azurerm_log_analytics_workspace" "loganalytic" {
  name                = "lab1-loganalytic"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  sku                 = "PerGB2018"
  retention_in_days   = 30
}

resource "azurerm_container_app_environment" "env" {
  name                       = "lab1-containerapp-env"
  location                   = azurerm_resource_group.rg.location
  resource_group_name        = azurerm_resource_group.rg.name
  log_analytics_workspace_id = azurerm_log_analytics_workspace.loganalytic.id
  infrastructure_subnet_id   = azurerm_subnet.subnet.id
}
  1. Authenticate to Azure with your account (use work or school account option), run: az login

  2. Initialize terraform, plan and apply: run:

  • terraform init
  • terraform plan
  • terraform apply
  1. Authenticate to Azure Container Registry (ACR), Tag and push your image to ACR: run

Validation

  • Ensure ACR exists

Run: az acr show --name lab1acr689 --output table

  • Ensure Image exists in ACR: run

az acr repository list --name lab1acr689 --output table

  • Ensure Image tag matches version: run
az acr repository show-tags \

  --name lab1acr689 \

  --repository lab1-starter-app \

  --output table
  • On the portal

Step 4: Deploy Container App using terraform

  1. Create the second manifest file ( main.tf ) file and add your terraform code to deploy an azure container app.

  2. You could create your own manifest file or use the template below- run: nano main.tf. In your configuration, ensure:

    • Image is from ACR

    • External ingress is enabled

    • Target port matches container

    • Environment variables

    • Scaling settings

  3. Template for main.tf

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">= 3.65.0"
    }
  }
}

provider "azurerm" {
  features {}
}

# Existing resources
data "azurerm_resource_group" "rg" {
  name = "lab1-RG"
}

data "azurerm_container_registry" "acr" {
  name                = "lab1acr689"
  resource_group_name = "lab1-RG"
}

data "azurerm_container_app_environment" "env" {
  name                = "lab1-containerapp-env"
  resource_group_name = "lab1-RG"
}

# ✅ Create User Assigned Identity FIRST
resource "azurerm_user_assigned_identity" "uai" {
  name                = "lab1-containerapp-identity"
  resource_group_name = data.azurerm_resource_group.rg.name
  location            = data.azurerm_resource_group.rg.location
}

# ✅ Assign AcrPull BEFORE app creation
resource "azurerm_role_assignment" "acr_pull" {
  scope                = data.azurerm_container_registry.acr.id
  role_definition_name = "AcrPull"
  principal_id         = azurerm_user_assigned_identity.uai.principal_id
}

# ✅ Container App uses the identity
resource "azurerm_container_app" "app" {
  name                         = "lab1-container-app"
  resource_group_name          = data.azurerm_resource_group.rg.name
  container_app_environment_id = data.azurerm_container_app_environment.env.id
  revision_mode                = "Single"

  identity {
    type         = "UserAssigned"
    identity_ids = [azurerm_user_assigned_identity.uai.id]
  }

  template {
    container {
      name   = "lab1-starter-app"
      image  = "${data.azurerm_container_registry.acr.login_server}/lab1-starter-app:v1.0.0"
      cpu    = 0.25
      memory = "0.5Gi"

      env {
        name  = "ENGINEER_NAME"
        value = "Celestina Odili"
      }

      env {
        name  = "CLOUD_PLATFORM"
        value = "Azure"
      }

      env {
        name  = "APP_NAME"
        value = "Cloud Lab Starter App"
      }

      env {
        name  = "ENVIRONMENT"
        value = "test"
      }

      env {
        name  = "APP_VERSION"
        value = "v1.0.0"
      }

      env {
        name  = "APP_STATUS"
        value = "healthy"
      }
    }

    min_replicas = 1
    max_replicas = 3
  }

  ingress {
    external_enabled = true
    target_port      = 8000

    traffic_weight {
      latest_revision = true
      percentage      = 100
    }
  }

  registry {
    server   = data.azurerm_container_registry.acr.login_server
    identity = azurerm_user_assigned_identity.uai.id
  }

  depends_on = [
    azurerm_role_assignment.acr_pull
  ]
}
  1. Initialize, plan and apply Terraform
  • Terraform init

  • Terraform plan

  • Terraform apply

Validation

  • Confirm that Container App is running and Public URL is available:

  • on the portal

  • run the command shown

az containerapp show 
-- name lab1-container-app \
--resource-group lab1-RG \
--query "properties.provisioningState" \

az containerapp show
--name <APP_NAME>
--resource-group <RESOURCE_GROUP>
--query "properties.provisioningState"

  • A revision is active:

  • on the portal

  • Page loads successfully

  • All resources are created successfully and Environment is active

Challenges and Resolutions

During this project, I encountered both development and infrastructure-related challenges that required troubleshooting and adjustments.

On the development side, I initially had issues creating and activating a Python virtual environment. Using python3 -m venv .venv and source .venv/bin/activate did not work in my Windows environment. I resolved this by switching to python -m venv .venv and activating it with source .venv/Scripts/activate, which is the correct approach for Windows systems.

On the infrastructure side, I faced repeated deployment issues when using a single Terraform configuration file for all resources. These issues included unintended resource recreation, destroy conflicts, and situations where the Azure Container App deployed successfully but failed to pull the container image from Azure Container Registry (ACR). To address this, I restructured the Terraform setup into two stages: one for provisioning core infrastructure (Resource Group, ACR, networking, and Container Apps environment) and another dedicated to deploying the Container App itself. This separation reduced dependency conflicts, improved deployment reliability, and better reflected a production-style DevOps workflow.

Additionally, I observed that if the container image could not be pulled from ACR, the Container App would still be created but would fail to start. This reinforced the importance of ensuring correct image tagging, availability, and authentication, as the application cannot run unless Azure successfully retrieves the container image.

Conclusion

This project highlights how Azure Container Apps simplifies application deployment while still requiring a clear understanding of how its components interact. From routing traffic through Azure’s ingress to ensuring the container port aligns perfectly with the application’s listening port, every configuration detail plays a critical role in making the application accessible and reliable.

The challenges encountered—ranging from local environment setup issues to Terraform deployment conflicts—reinforced the importance of choosing the right tools and structuring infrastructure thoughtfully. Refactoring the Terraform configuration into separate stages not only resolved deployment errors but also introduced a more maintainable, production-aligned workflow.

Additionally, the experience underscored key operational concepts such as the dependency on container images being successfully pulled from Azure Container Registry and the flexibility provided by environment variables in managing application configuration without modifying code.

Overall, while the setup works effectively, there is clear room for improvement in a production scenario. Enhancing security using Azure Key Vault can also be used in place of managed identity. Also, implementing a robust CI/CD pipeline, would ensure the system is more scalable and automated. This project serves as a strong foundation for building more resilient cloud-native applications using modern DevOps practices.

C

Hello there!!!

Have you tried reproducing this project? I would love to hear your thoughts—where do you think it could be improved?

Feel free to share your experience so we can learn and grow together.

More from this blog

Celestina Odili

30 posts

This blog explores Cloud Computing and DevOps with a focus on practical, hands-on learning and real-world projects.

I share tutorials and insights on tools like Azure, AWS, Terraform, Docker, Kubernetes, CI/CD pipelines, and Infrastructure as Code (IaC), breaking down complex concepts into simple, actionable steps.

You’ll also find my personal learning journey, experiments, and lab projects to help you follow along and build your own skills step by step.