Issues with Updating Azure Container App Using yamlConfigPath in AzureContainerApps@1 Task

Yasitha Gunarathne 40 Reputation points
2024-06-03T07:51:44.9133333+00:00

I am attempting to update an Azure Container App through an Azure Pipeline using the yamlConfigPath attribute of the AzureContainerApps@1 task. The Container App includes three containers:

A background services container.

A container handling incoming requests.

An init container for database migrations.

All three containers utilize the same Docker image, which is built in the pipeline and pushed to an Azure Container Registry repository. I aim to set the same environment variables for all three containers, except for one variable.

My Git repository has two branches: master and dev. I need to deploy these branches to two separate Container Apps.

This is my azure-pipelines.yml file.

trigger:
- xxxxxxx

pool: XXXXXXXXX

resources:
- repo: self

variables:
  # Container registry service connection established during pipeline creation
  dockerRegistryServiceConnection: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
  imageRepository: 'XXXXXXXXXXXXXX'
  containerRegistry: 'XXXXXXXXXXXXXXX.azurecr.io'
  dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
  tag: '$(Build.BuildId)'
  
  # Agent VM image name
  vmImageName: 'ubuntu-latest' 

stages:
- stage: Build
  displayName: Build and push stage
  variables:
  - ${{ if eq(variables['Build.SourceBranchName'], 'master') }}:
    - group: Backend Prod
  - ${{ if eq(variables['Build.SourceBranchName'], 'dev') }}:
    - group: Backend Dev   
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: $(vmImageName)
    steps:
    - task: Docker@2
      displayName: Build and push an image to container registry
      inputs:
        command: buildAndPush
        repository: $(imageRepository)
        dockerfile: $(dockerfilePath)
        containerRegistry: $(dockerRegistryServiceConnection)
        tags: |
          $(tag)
    - task: AzureContainerApps@1
      inputs:
        azureSubscription: 'ContainerAppConnection'
        containerAppName: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
        resourceGroup: 'xxxxxxxxxxxxx'
        yamlConfigPath: 'azure-container-app-template.yaml'

This is azure-container-app-template.yaml.

name: $(CONTAINER_APP_NAME)
properties:
  template:
    containers:
    - env:
      - name: APP_NAME
        value: $(APP_NAME)
      - name: APP_ENV
        value: $(APP_ENV)
      - name: APP_KEY
        value: $(APP_KEY)
      - name: APP_DEBUG
        value: $(APP_DEBUG)
      - name: APP_URL
        value: $(APP_URL)
      - name: LOG_CHANNEL
        value: $(LOG_CHANNEL)
      - name: LOG_LEVEL
        value: $(LOG_LEVEL)
      - name: DB_CONNECTION
        value: $(DB_CONNECTION)
      - name: DB_HOST
        value: $(DB_HOST)
      - name: DB_PORT
        value: $(DB_PORT)
      - name: DB_DATABASE
        value: $(DB_DATABASE)
      - name: DB_USERNAME
        value: $(DB_USERNAME)
      - name: DB_PASSWORD
        value: $(DB_PASSWORD)
      - name: BROADCAST_DRIVER
        value: $(BROADCAST_DRIVER)
      - name: CACHE_DRIVER
        value: $(CACHE_DRIVER)
      - name: FILESYSTEM_DRIVER
        value: $(FILESYSTEM_DRIVER)
      - name: QUEUE_CONNECTION
        value: $(QUEUE_CONNECTION)
      - name: SESSION_DRIVER
        value: $(SESSION_DRIVER)
      - name: SESSION_LIFETIME
        value: $(SESSION_LIFETIME)
      - name: REDIS_HOST
        value: $(REDIS_HOST)
      - name: REDIS_PASSWORD
        value: $(REDIS_PASSWORD)
      - name: REDIS_PORT
        value: $(REDIS_PORT)
      - name: MAIL_MAILER
        value: $(MAIL_MAILER)
      - name: MAIL_HOST
        value: $(MAIL_HOST)
      - name: MAIL_PORT
        value: $(MAIL_PORT)
      - name: MAIL_USERNAME
        value: $(MAIL_USERNAME)
      - name: MAIL_PASSWORD
        value: $(MAIL_PASSWORD)
      - name: MAIL_ENCRYPTION
        value: $(MAIL_ENCRYPTION)
      - name: MAIL_FROM_ADDRESS
        value: $(MAIL_FROM_ADDRESS)
      - name: MAIL_FROM_NAME
        value: $(MAIL_FROM_NAME)
      - name: AWS_ACCESS_KEY_ID
        value: $(AWS_ACCESS_KEY_ID)
      - name: AWS_SECRET_ACCESS_KEY
        value: $(AWS_SECRET_ACCESS_KEY)
      - name: AWS_DEFAULT_REGION
        value: $(AWS_DEFAULT_REGION)
      - name: AWS_BUCKET
        value: $(AWS_BUCKET)
      - name: AWS_USE_PATH_STYLE_ENDPOINT
        value: $(AWS_USE_PATH_STYLE_ENDPOINT)
      - name: AWS_URL
        value: $(AWS_URL)
      - name: SAAS_PORTAL_HOST
        value: $(SAAS_PORTAL_HOST)
      - name: INTERNAL_API_KEY
        value: $(INTERNAL_API_KEY)
      - name: INTERNAL_API_SECRET
        value: $(INTERNAL_API_SECRET)
      - name: TENANT_SUBDOMAIN
        value: $(TENANT_SUBDOMAIN)
      - name: SANCTUM_STATEFUL_DOMAINS
        value: $(SANCTUM_STATEFUL_DOMAINS)
      - name: SESSION_DOMAIN
        value: $(SESSION_DOMAIN)
      - name: AWS_ORIGINAL_VIDEO_BUCKET
        value: $(AWS_ORIGINAL_VIDEO_BUCKET)
      - name: AWS_STREAMING_VIDEO_BUCKET
        value: $(AWS_STREAMING_VIDEO_BUCKET)
      - name: AWS_STREAMING_VIDEO_BUCKET_URL
        value: $(AWS_STREAMING_VIDEO_BUCKET_URL)
      - name: AWS_MEDIACONVERT_ROLE
        value: $(AWS_MEDIACONVERT_ROLE)
      - name: AWS_MEDIACONVERT_QUEUE
        value: $(AWS_MEDIACONVERT_QUEUE)
      - name: CONTAINER_MODE
        value: SERVER
      image: $(CONTAINER_REGISTRY_LOGIN_SERVER)/$(CONTAINER_REPOSITORY):$(tag)
      name: $(CONTAINER_NAME_SERVER)
    - env:
      - name: APP_NAME
        value: $(APP_NAME)
      - name: APP_ENV
        value: $(APP_ENV)
      - name: APP_KEY
        value: $(APP_KEY)
      - name: APP_DEBUG
        value: $(APP_DEBUG)
      - name: APP_URL
        value: $(APP_URL)
      - name: LOG_CHANNEL
        value: $(LOG_CHANNEL)
      - name: LOG_LEVEL
        value: $(LOG_LEVEL)
      - name: DB_CONNECTION
        value: $(DB_CONNECTION)
      - name: DB_HOST
        value: $(DB_HOST)
      - name: DB_PORT
        value: $(DB_PORT)
      - name: DB_DATABASE
        value: $(DB_DATABASE)
      - name: DB_USERNAME
        value: $(DB_USERNAME)
      - name: DB_PASSWORD
        value: $(DB_PASSWORD)
      - name: BROADCAST_DRIVER
        value: $(BROADCAST_DRIVER)
      - name: CACHE_DRIVER
        value: $(CACHE_DRIVER)
      - name: FILESYSTEM_DRIVER
        value: $(FILESYSTEM_DRIVER)
      - name: QUEUE_CONNECTION
        value: $(QUEUE_CONNECTION)
      - name: SESSION_DRIVER
        value: $(SESSION_DRIVER)
      - name: SESSION_LIFETIME
        value: $(SESSION_LIFETIME)
      - name: REDIS_HOST
        value: $(REDIS_HOST)
      - name: REDIS_PASSWORD
        value: $(REDIS_PASSWORD)
      - name: REDIS_PORT
        value: $(REDIS_PORT)
      - name: MAIL_MAILER
        value: $(MAIL_MAILER)
      - name: MAIL_HOST
        value: $(MAIL_HOST)
      - name: MAIL_PORT
        value: $(MAIL_PORT)
      - name: MAIL_USERNAME
        value: $(MAIL_USERNAME)
      - name: MAIL_PASSWORD
        value: $(MAIL_PASSWORD)
      - name: MAIL_ENCRYPTION
        value: $(MAIL_ENCRYPTION)
      - name: MAIL_FROM_ADDRESS
        value: $(MAIL_FROM_ADDRESS)
      - name: MAIL_FROM_NAME
        value: $(MAIL_FROM_NAME)
      - name: AWS_ACCESS_KEY_ID
        value: $(AWS_ACCESS_KEY_ID)
      - name: AWS_SECRET_ACCESS_KEY
        value: $(AWS_SECRET_ACCESS_KEY)
      - name: AWS_DEFAULT_REGION
        value: $(AWS_DEFAULT_REGION)
      - name: AWS_BUCKET
        value: $(AWS_BUCKET)
      - name: AWS_USE_PATH_STYLE_ENDPOINT
        value: $(AWS_USE_PATH_STYLE_ENDPOINT)
      - name: AWS_URL
        value: $(AWS_URL)
      - name: SAAS_PORTAL_HOST
        value: $(SAAS_PORTAL_HOST)
      - name: INTERNAL_API_KEY
        value: $(INTERNAL_API_KEY)
      - name: INTERNAL_API_SECRET
        value: $(INTERNAL_API_SECRET)
      - name: TENANT_SUBDOMAIN
        value: $(TENANT_SUBDOMAIN)
      - name: SANCTUM_STATEFUL_DOMAINS
        value: $(SANCTUM_STATEFUL_DOMAINS)
      - name: SESSION_DOMAIN
        value: $(SESSION_DOMAIN)
      - name: AWS_ORIGINAL_VIDEO_BUCKET
        value: $(AWS_ORIGINAL_VIDEO_BUCKET)
      - name: AWS_STREAMING_VIDEO_BUCKET
        value: $(AWS_STREAMING_VIDEO_BUCKET)
      - name: AWS_STREAMING_VIDEO_BUCKET_URL
        value: $(AWS_STREAMING_VIDEO_BUCKET_URL)
      - name: AWS_MEDIACONVERT_ROLE
        value: $(AWS_MEDIACONVERT_ROLE)
      - name: AWS_MEDIACONVERT_QUEUE
        value: $(AWS_MEDIACONVERT_QUEUE)
      - name: CONTAINER_MODE
        value: WORKER
      image: $(CONTAINER_REGISTRY_LOGIN_SERVER)/$(CONTAINER_REPOSITORY):$(tag)
      name: $(CONTAINER_NAME_WORKER)
    initContainers:
    - env:
      - name: APP_NAME
        value: $(APP_NAME)
      - name: APP_ENV
        value: $(APP_ENV)
      - name: APP_KEY
        value: $(APP_KEY)
      - name: APP_DEBUG
        value: $(APP_DEBUG)
      - name: APP_URL
        value: $(APP_URL)
      - name: LOG_CHANNEL
        value: $(LOG_CHANNEL)
      - name: LOG_LEVEL
        value: $(LOG_LEVEL)
      - name: DB_CONNECTION
        value: $(DB_CONNECTION)
      - name: DB_HOST
        value: $(DB_HOST)
      - name: DB_PORT
        value: $(DB_PORT)
      - name: DB_DATABASE
        value: $(DB_DATABASE)
      - name: DB_USERNAME
        value: $(DB_USERNAME)
      - name: DB_PASSWORD
        value: $(DB_PASSWORD)
      - name: BROADCAST_DRIVER
        value: $(BROADCAST_DRIVER)
      - name: CACHE_DRIVER
        value: $(CACHE_DRIVER)
      - name: FILESYSTEM_DRIVER
        value: $(FILESYSTEM_DRIVER)
      - name: QUEUE_CONNECTION
        value: $(QUEUE_CONNECTION)
      - name: SESSION_DRIVER
        value: $(SESSION_DRIVER)
      - name: SESSION_LIFETIME
        value: $(SESSION_LIFETIME)
      - name: REDIS_HOST
        value: $(REDIS_HOST)
      - name: REDIS_PASSWORD
        value: $(REDIS_PASSWORD)
      - name: REDIS_PORT
        value: $(REDIS_PORT)
      - name: MAIL_MAILER
        value: $(MAIL_MAILER)
      - name: MAIL_HOST
        value: $(MAIL_HOST)
      - name: MAIL_PORT
        value: $(MAIL_PORT)
      - name: MAIL_USERNAME
        value: $(MAIL_USERNAME)
      - name: MAIL_PASSWORD
        value: $(MAIL_PASSWORD)
      - name: MAIL_ENCRYPTION
        value: $(MAIL_ENCRYPTION)
      - name: MAIL_FROM_ADDRESS
        value: $(MAIL_FROM_ADDRESS)
      - name: MAIL_FROM_NAME
        value: $(MAIL_FROM_NAME)
      - name: AWS_ACCESS_KEY_ID
        value: $(AWS_ACCESS_KEY_ID)
      - name: AWS_SECRET_ACCESS_KEY
        value: $(AWS_SECRET_ACCESS_KEY)
      - name: AWS_DEFAULT_REGION
        value: $(AWS_DEFAULT_REGION)
      - name: AWS_BUCKET
        value: $(AWS_BUCKET)
      - name: AWS_USE_PATH_STYLE_ENDPOINT
        value: $(AWS_USE_PATH_STYLE_ENDPOINT)
      - name: AWS_URL
        value: $(AWS_URL)
      - name: SAAS_PORTAL_HOST
        value: $(SAAS_PORTAL_HOST)
      - name: INTERNAL_API_KEY
        value: $(INTERNAL_API_KEY)
      - name: INTERNAL_API_SECRET
        value: $(INTERNAL_API_SECRET)
      - name: TENANT_SUBDOMAIN
        value: $(TENANT_SUBDOMAIN)
      - name: SANCTUM_STATEFUL_DOMAINS
        value: $(SANCTUM_STATEFUL_DOMAINS)
      - name: SESSION_DOMAIN
        value: $(SESSION_DOMAIN)
      - name: AWS_ORIGINAL_VIDEO_BUCKET
        value: $(AWS_ORIGINAL_VIDEO_BUCKET)
      - name: AWS_STREAMING_VIDEO_BUCKET
        value: $(AWS_STREAMING_VIDEO_BUCKET)
      - name: AWS_STREAMING_VIDEO_BUCKET_URL
        value: $(AWS_STREAMING_VIDEO_BUCKET_URL)
      - name: AWS_MEDIACONVERT_ROLE
        value: $(AWS_MEDIACONVERT_ROLE)
      - name: AWS_MEDIACONVERT_QUEUE
        value: $(AWS_MEDIACONVERT_QUEUE)
      - name: CONTAINER_MODE
        value: MIGRATOR
      image: $(CONTAINER_REGISTRY_LOGIN_SERVER)/$(CONTAINER_REPOSITORY):$(tag)
      name: $(CONTAINER_NAME_MIGRATOR)
resourceGroup: $(CONTAINER_APP_RESOURCE_GROUP)
type: Microsoft.App/containerApps

The issue I am encountering is that the variables are not being applied to the azure-container-app-template.yaml file. I receive the following error:

ERROR: The containerapp '$(CONTAINER_APP_NAME)' does not exist
##[error]Error: Unable to update Azure Container App from YAML configuration file via 'az containerapp update' command.

Is there a way to ensure that the variables from variable groups are available for the azure-container-app-template.yaml file?

Alternatively, could you suggest a different method to achieve this deployment setup?

Azure Container Apps
Azure Container Apps
An Azure service that provides a general-purpose, serverless container platform.
324 questions
Azure Startups
Azure Startups
Azure: A cloud computing platform and infrastructure for building, deploying and managing applications and services through a worldwide network of Microsoft-managed datacenters.Startups: Companies that are in their initial stages of business and typically developing a business model and seeking financing.
187 questions
0 comments No comments
{count} votes

Accepted answer
  1. Ryan Hill 26,866 Reputation points Microsoft Employee
    2024-06-03T21:45:28.6133333+00:00

    Hi @Yasitha Gunarathne,

    It's great to hear you've resolved your issue, and it's incredibly helpful that you've shared your solution for others to find! As the Microsoft Q&A community guidelines state that authors can't accept their own answers but only those from others, I'll make sure to repost your solution. This way, if you wish, you can Accept it accordingly.


    Your original issue is that environment variables weren't being applied to your yaml that you set in yamlConfigPath in the AzureContainerApps@1 task. I did take a look at AzureContainerApps@1 - Azure Container Apps Deploy v1 task | Microsoft Learn, and based on

    In cases where the yamlConfigPath argument is provided, the YAML file will be passed through to the corresponding az containerapp command, either create or update depending on your scenario. For more information on the intended behavior when the YAML configuration file is provided, please see the documents linked for the corresponding commands.

    I don't believe the task ever supported tokenized replacement. It simply takes the file configured for that property and runs it. However, to resolve your issue, you added a step to your pipeline that will correctly replace the environment variables to a new yaml file, and you use that generated file in the task. I do believe there is merit in an ask such as this and would encourage you submitting a request feature at https://github.com/microsoft/azure-container-apps/issues/new.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Yasitha Gunarathne 40 Reputation points
    2024-06-03T18:02:19.01+00:00

    After spending several hours troubleshooting, I have found a solution to the issue I posted about earlier. I wanted to share this solution to help others who might face the same problem in the future.

    To resolve the issue of variables not being applied to the azure-container-app-template.yaml file, I wrote an inline script in the azure-pipelines.yml file. This script creates a new .yaml file by replacing the variables in the azure-container-app-template.yaml using the Linux command envsubst. The newly created file is then provided to the yamlConfigPath attribute of the AzureContainerApps@1 task.

    Here is the updated azure-pipelines.yml file:

    trigger:
    - xxxxxxx
    
    pool: XXXXXXXXX
    
    resources:
    - repo: self
    
    variables:
      # Container registry service connection established during pipeline creation
      dockerRegistryServiceConnection: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
      imageRepository: 'XXXXXXXXXXXXXX'
      containerRegistry: 'XXXXXXXXXXXXXXX.azurecr.io'
      dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
      tag: '$(Build.BuildId)'
      
      # Agent VM image name
      vmImageName: 'ubuntu-latest' 
    
    stages:
    - stage: Build
      displayName: Build and push stage
      variables:
      - ${{ if eq(variables['Build.SourceBranchName'], 'master') }}:
        - group: Backend Prod
      - ${{ if eq(variables['Build.SourceBranchName'], 'dev') }}:
        - group: Backend Dev   
      jobs:
      - job: Build
        displayName: Build
        pool:
          vmImage: $(vmImageName)
        steps:
        - script: |
            envsubst < azure-container-app-template.yaml > azure-container-app-template-processed.yaml
          displayName: 'Substitute environment variables in template'     
          env:
            TAG: $(tag)  
        - task: Docker@2
          displayName: Build and push an image to container registry
          inputs:
            command: buildAndPush
            repository: $(imageRepository)
            dockerfile: $(dockerfilePath)
            containerRegistry: $(dockerRegistryServiceConnection)
            tags: |
              $(tag)
        - task: AzureContainerApps@1
          inputs:
            azureSubscription: 'ContainerAppConnection'
            containerAppName: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
            resourceGroup: 'xxxxxxxxxxxxx'
            yamlConfigPath: 'azure-container-app-template-processed.yaml'
    
    

    In the original azure-container-app-template.yaml file, I used variables in the format $(CONTAINER_APP_NAME). To work with the envsubst command, I changed the variable format as shown below:

    name: $CONTAINER_APP_NAME
    properties:
      template:
        containers:
        - env:
          - name: APP_NAME
            value: $APP_NAME
          - name: APP_ENV
            value: $APP_ENV
          - name: APP_KEY
            value: $APP_KEY
    

    This approach ensures that the environment variables are correctly substituted in the template file before deploying the Azure Container App. I hope this helps others who encounter a similar issue.

    0 comments No comments