skip to Main Content

I’m currently working with Terraform Cloud to create an Azure Container App using Terraform as part of my Infrastructure as Code (IaC) efforts. I’m using a null_resource with the local-exec provisioner to execute a script that builds a Docker image and pushes it to Azure Container Registry (ACR). However, I’ve run into a limitation where the script doesn’t execute as intended because Terraform Cloud runs in a remote environment.

Here’s a snippet of my configuration (sample):

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "East US"
}

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

resource "null_resource" "deploy_image_acr" {
  triggers = {
    deploy_time = timestamp()
  }

  provisioner "local-exec" {
    command = "./deploy_to_acr.sh ${var.client_id} ${var.client_secret} ${var.tenant_id} ${var.subscription_id} ${azurerm_container_registry.acr.name} ${var.image_name}"
  }

  depends_on = [azurerm_container_registry.acr]
}

Bash Script:

#!/bin/bash

# Login to Azure with the Service Principal
az login --service-principal -u "$1" -p="$2" --tenant "$3"

# Set the desired subscription
az account set --subscription "$4"

# Remove all existing images
for repo in $(az acr repository list --name "$5" --output tsv); do
  az acr repository delete --name "$5" --repository "$repo" --yes
done

# Build and push the new image

docker build -t <image_name> .. 

az acr login --name $5

docker tag <image_name> $5.azurecr.io/<image_name>

docker push $5.azurecr.io/<image_name>

The Problem:
When I try to apply this configuration in Terraform Cloud, the local-exec provisioner does not execute the script because it’s designed to run on the local machine where Terraform is executed.

Questions:

  • Is there a way to execute scripts that are defined in a null_resource or any other resource on my local machine while using Terraform Cloud?
  • If local execution isn’t possible, what alternative approaches can I use to run Docker commands or scripts as part of my deployment workflow?

2

Answers


  1. Chosen as BEST ANSWER

    To execute scripts defined in a null_resource or any other resource on my local machine while using Terraform Cloud:

    Solution: Ensure that your execution mode is set to local in your workspace. This will store the state file inside Terraform while all infrastructure provisioning occurs on your local machine.

    Terraform File Example:

    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "4.2.0"
        }
      }
      
      cloud {
        organization = "org-name"
        
        workspaces {
          name = "wk-space"
        }
      }
    }
    

    Setting to Look For in Terraform Cloud:

    Navigate to Workspace Settings > Execution Mode.

    Terraform Cloud Execution Mode

    Documentation: Terraform Cloud Execution Mode


  2. Here is the updated Terraform configuration and CLI script to pull and push the image to ACR.

    Note: Make sure to place both the .tf and .ps1 files in the same directory.

    Main.tf

    provider "azurerm" {
      features {}
      subscription_id = ""
    }
    
    resource "azurerm_resource_group" "rg" {
      name     = "example-resources"
      location = "West Europe"
    }
    resource "azurerm_container_registry" "acr" {
      name                     = "venaktacrtesting"
      resource_group_name      = azurerm_resource_group.rg.name
      location                 = azurerm_resource_group.rg.location
      sku                      = "Premium"
      admin_enabled            = true
    }
    
    resource "null_resource" "Powershell_script1" {
      provisioner "local-exec" {
        command = <<-EOT
          powershell -ExecutionPolicy Bypass -File ${path.module}/ACR.ps1 -ACRName "${azurerm_container_registry.acr.name}" -ACRLoginServer "${azurerm_container_registry.acr.login_server}" -ACRUsername "${azurerm_container_registry.acr.admin_username}" -ACRPassword "${azurerm_container_registry.acr.admin_password}"
        EOT
      }
      depends_on = [azurerm_container_registry.acr]
    }
    
    

    The below CLI commands will download, tag, and push the images to the specified ACR repository

    ACR.ps1

    param (
        [string]$ACRName,
        [string]$ACRLoginServer,
        [string]$ACRUsername,
        [string]$ACRPassword
    )
    
    az acr login --name $ACRName --username $ACRUsername --password $ACRPassword
    $repolist = az acr repository list -n $ACRLoginServer
    foreach ($repolists in $repolist) {
        az acr repository delete -n $ACRLoginServer --repository $repolists --yes
    }
    docker pull nginx
    docker tag nginx $ACRLoginServer/sampleimage/nginx:v1
    docker push $ACRLoginServer/sampleimage/nginx:v1
    

    Terraform apply

    enter image description here

    After running the Terraform script, the images are downloaded locally, tagged with a different name, and then pushed to the ACR.

    enter image description here

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search