azureterraformazure-container-appsazure-rm

How do I deploy an Azure Container App from scratch using terraform/azurerm?


I am trying to deploy an Azure Container App from scratch on my Azure Subscription using Terraform with azurerm (4.27.0). I want my container app image managed by Azure Container Registry. Here is my code:

resource "azurerm_resource_group" "rg" {
  name     = "<RESOURCE_GROUP_NAME>"
  location = var.location
}

resource "azurerm_container_registry" "cr" {
  name                = "<CONTAINER_REGISTRY_NAME>"
  resource_group_name = azurerm_resource_group.rg.name
  location            = var.location
  sku                 = "Standard"
}

resource "azurerm_container_app_environment" "cae" {
  name                       = "<CONTAINER_APP_ENVIRONMENT_NAME>"
  location                   = var.location
  resource_group_name        = azurerm_resource_group.rg.name
  log_analytics_workspace_id = var.workspace_id
  logs_destination           = "log-analytics"
}

resource "azurerm_user_assigned_identity" "id" {
  name                = "<IDENTITY_NAME>"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_role_assignment" "role_assignment" {
  scope                = azurerm_container_registry.cr.id
  role_definition_name = "acrpull"
  principal_id         = azurerm_user_assigned_identity.id.principal_id
  depends_on           = [azurerm_user_assigned_identity.id]
}

resource "azurerm_container_app" "ca" {
  name                         = "<CONTAINER_APP_NAME>"
  container_app_environment_id = azurerm_container_app_environment.cae.id
  resource_group_name          = azurerm_resource_group.rg.name
  revision_mode                = "Single"

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

  registry {
    server   = azurerm_container_registry.cr.login_server
    identity = azurerm_user_assigned_identity.id.id
  }

  template {
    container {
      name   = "<CONTAINER_NAME>"
      image  = "${azurerm_container_registry.cr.login_server}/<CONTAINER_IMAGE_NAME>:CONTAINER_IMAGE_TAG"
      cpu    = 0.5
      memory = "1Gi"
    }
  }

  depends_on = [azurerm_role_assignment.role_assignment]
}

When I run terraform apply, I get this error:

│ Error: creating Container App (Subscription: "<SUBSCRIPTION_ID>"
│ Resource Group Name: "<RESOURCE_GROUP_NAME>"
│ Container App Name: "<CONTAINER_APP_NAME>"): polling after CreateOrUpdate: polling failed: the Azure API returned the following error:
│
│ Status: "Failed"
│ Code: "ContainerAppOperationError"
│ Message: "Failed to provision revision for container app '<CONTAINER_APP_NAME>'. Error details: The following field(s) are either invalid or missing. Field 'template.containers.<CONTAINER_APP_NAME>.image' is invalid with details: 'Invalid value: \"<CONTAINER_REGISTRY_LOGIN_SERVER>/<CONTAINER_IMAGE_NAME>:<CONTAINER_IMAGE_TAG>\": GET https:: MANIFEST_UNKNOWN: manifest tagged by \"<CONTAINER_IMAGE_TAG>\" is not found; map[Tag:<CONTAINER_IMAGE_TAG>]';.."
│ Activity Id: ""

I understand that I am trying to pull an image from my newly created container registry, even though it doesn't contain any. But I am deploying my infrastructure from scratch: at this stage, I want to create my first image, and I expect that we can do this from terraform.

Is there a way to do that? Thanks by advance.


Solution

  • Deploy an Azure Container App from scratch using terraform/azurerm

    As suggested in the comments, Terraform natively doesn't support to push the Docker images to ACR. We can do that using CLI, however if you What everything to be provisioned using single configuration you can use null resource local exec provisioner to run the CLI commands as per the requirement.

    I tried a demo configuration as per the requirement to use null resource that pass CLI command as per the requirement and able to provision the requirement successfully.

    For this to work, we need a docker file in the same directory where we need are executing terraform, or we need to specify the Dockerfile path target directory.

    Demo configuration:

    resource "null_resource" "push_image" {
      provisioner "local-exec" {
        interpreter = ["pwsh", "-Command"]
        command     = <<EOT
          az acr build --registry ${var.container_registry_name} --image ${var.container_image_name}:${var.container_image_tag} --file dockerfile .
        EOT
      }
    }
    
    
    resource "azurerm_user_assigned_identity" "identity" {
      name                = var.identity_name
      resource_group_name = azurerm_resource_group.rg.name
      location            = var.location
    }
    
    resource "azurerm_role_assignment" "acr_pull" {
      scope                = azurerm_container_registry.acr.id
      role_definition_name = "acrpull"
      principal_id         = azurerm_user_assigned_identity.identity.principal_id
    }
    
    resource "azurerm_container_app_environment" "env" {
      name                       = var.container_app_env_name
      location                   = var.location
      resource_group_name        = azurerm_resource_group.rg.name
      log_analytics_workspace_id = var.log_analytics_workspace_id
      logs_destination           = "log-analytics"
    }
    
    resource "azurerm_container_app" "app" {
      name                         = var.container_app_name
      container_app_environment_id = azurerm_container_app_environment.env.id
      resource_group_name          = azurerm_resource_group.rg.name
      revision_mode                = "Single"
    
      identity {
        type         = "UserAssigned"
        identity_ids = [azurerm_user_assigned_identity.identity.id]
      }
    
      registry {
        server   = azurerm_container_registry.acr.login_server
        identity = azurerm_user_assigned_identity.identity.id
      }
    
      template {
        container {
          name   = var.container_name
          image  = "${azurerm_container_registry.acr.login_server}/${var.container_image_name}:${var.container_image_tag}"
          cpu    = 0.5
          memory = "1Gi"
        }
      }
    
      depends_on = [
        null_resource.push_image,
        azurerm_role_assignment.acr_pull
      ]
    }
    

    Deployment:

    enter image description here

    enter image description here

    Refer:

    https://www.mytechramblings.com/posts/how-to-push-a-container-image-into-acr-using-terraform/

    https://learn.microsoft.com/en-us/azure/container-registry/container-registry-get-started-docker-cli?tabs=azure-cli