azure-devopsazure-pipelinesdocker-imageazure-container-registryazure-container-apps

ContainerApp not pulling images from new Azure Container Registry


I have a Container App in Azure Cloud and I have created a new Azure Container Registry(ACR). With my pipeline I am generating image in my acr and then updating the container app to use the new ACR and pull new latest image from it. The images are successfully being created in the ACR however the container app is still not using the new ACR.

In my pipeline, first I am building new Image in the ACR:

parameters:
  - name: build_specific
    displayName: "(Optional) Build the specific Docker Image. Enter path to Dockerfile from Docker folder."
    type: object
    default:
  - name: dso_key
    displayName: "DSO key used for the ACR name."
    type: string
  - name: acr_subdir
    displayName: "Name of the ACR subfolder."
    type: string
  - name: pip_extra_index_url
    type: string
    default: "https://$(GLOBAL_FEED_NAME_PREFIX)$(FEED_NAME_SUFFIX):$(FEED-PAT)@pkgs.dev.azure.com/ADD"

jobs:
  - job: BuildCode
    displayName: "Create and run ACR tasks"
    pool:
      name: "Basic_Pool_Ubuntu"

    steps:
      - checkout: self
        submodules: true
      - checkout: templates
      - task: AzureKeyVault@2
        inputs:
          connectedServiceName: $(VAR_SERVICE_CONNECTION)
          keyVaultName: $(GLOBAL_KV_NAME)
          secretsFilter: "DEVOPS-PAT, FEED-PAT"
          runAsPreJob: false
      - task: PipAuthenticate@1
        inputs:
          artifactFeeds: '$(GLOBAL_FEED_NAME_PREFIX)$(FEED_NAME_SUFFIX)'
          onlyAddExtraIndex: true
      - task: AzureCLI@2
        displayName: "Create ACR Tasks"
        name: "createACRTask"
        inputs:
          azureSubscription: "$(VAR_SERVICE_CONNECTION)"
          scriptType: "bash"
          scriptLocation: "inlineScript"
          inlineScript: |
            ACR_NAME=$(GLOBAL_STAGE_LOWER)$(GLOBAL_DEPLOYMENT_LOWER)acr
            BRANCH_NAME=$(echo "$(Build.SourceBranch)" | sed 's/refs\a/heads\///g')
            CONTEXT="$(Build.Repository.Uri)#${BRANCH_NAME}"
            TASK_NAME=${VAR_STAGE_LOWER}_${{ parameters.dso_key }}_${{ parameters.acr_subdir }}
            IMAGE_NAME=${VAR_STAGE_LOWER}/${{ parameters.dso_key }}/${{ parameters.acr_subdir }}

            echo "Building file: ./$(Build.Repository.Name)/${{ parameters.build_specific }}"

            # Build command into azcommand for debugging purposes
            azcommand="az acr build \
              --registry ${ACR_NAME} \
              --image ${IMAGE_NAME}:cb$(Build.BuildId) \
              --image ${IMAGE_NAME}:latest \
              --file ./$(Build.Repository.Name)/${{ parameters.build_specific }} \
              --build-arg PIP_EXTRA_INDEX_URL=${{ parameters.pip_extra_index_url }} \
              ./$(Build.Repository.Name)/
            "
            # echo ${azcommand} # Uncomment to see exact command

            # Execute command without any parameter
            ${azcommand}


this works fine and in the next stage I am run az containerapp update with the following code:

parameters:
  - name: dso_key
    displayName: "DSO key used for the ACR name."
    type: string
  - name: acr_subdir
    displayName: "Name of the ACR subfolder."
    type: string

jobs:
  - deployment: Deploy
    displayName: "Deploy Container App"
    environment: "$(Build.Repository.Name)-$(Build.SourceBranchName)"

    pool:
      name: "Basic_Pool_Ubuntu"

    strategy:
      runOnce:
        deploy:
          steps:
            - checkout: self
            - checkout: templates
            - task: Bash@3
              inputs:
                targetType: "filePath"
                filePath: "$(Build.Repository.LocalPath)/templates/helper_scripts/deployment_branch_gate.sh"
                arguments: $ENV_SOURCE_BRANCH $ENV_DEPLOYMENT_BRANCH
              env:
                ENV_SOURCE_BRANCH: $(Build.SourceBranchName)
                ENV_DEPLOYMENT_BRANCH: $(VAR_DEPLOYMENT_BRANCH)
              name: "Branch_Gate"
              condition: not(and(eq(variables['overwritebranchgate'], 'true'), eq(variables['VAR_DEPLOYMENT_BRANCH'], 'develop')))
            - task: AzureCLI@2
              displayName: "Deploy Container App"
              name: "DeployContainerApp"
              inputs:
                azureSubscription: "$(VAR_SERVICE_CONNECTION)"
                scriptType: "bash"
                scriptLocation: "inlineScript"
                inlineScript: |

                  CONTAINERAPP_NAME="$(VAR_CONTAINERAPP_NAME)"
                  RESOURCE_GROUP="$(VAR_RESOURCE_GROUP_NAME)"

                  ACR_NAME="$(GLOBAL_STAGE_LOWER)$(GLOBAL_DEPLOYMENT_LOWER)acr.azurecr.io"
                  IMAGE_NAME="${VAR_STAGE_LOWER}/${{ parameters.dso_key }}/${{ parameters.acr_subdir }}"
                  TAG="cb$(Build.BuildId)"

                  CPU="$(VAR_CONTAINERAPP_CPU)"
                  RAM="$(VAR_CONTAINERAPP_RAM)"
                  MIN_SCALE="$(VAR_CONTAINERAPP_MINSCALE)"
                  MAX_SCALE="$(VAR_CONTAINERAPP_MAXSCALE)"
                  SCALE_HTTP_CONCURRENCY="$(VAR_CONTAINERAPP_SCALE_HTTP)"
                  ENV_VARS="$(VAR_ENVS)"

                  revision=$(bash pipeline-templates/helper_scripts/containerapp/update_container_app.sh \
                      "$CONTAINERAPP_NAME" \
                      "$RESOURCE_GROUP" \
                      "$ACR_NAME" \
                      "$IMAGE_NAME" \
                      "$TAG" \
                      "$CPU" \
                      "$RAM" \
                      "$MIN_SCALE" \
                      "$MAX_SCALE" \
                      "$SCALE_HTTP_CONCURRENCY" \
                      "$ENV_VARS")

                  echo "Deployed Revision '$revision'"
                  echo "##vso[task.setvariable variable=revision]$revision"

this is the update_container_app.sh:

CONTAINERAPP_NAME=$1
RG=$2

ACR=$3
REPO=$4
TAG=$5
CPU=$6 # 0.25-4
RAM=$7 # 0.1-8
MIN_SCALE=$8
MAX_SCALE=$9
SCALE_HTTP_CONCURRENCY=${10}
ENV_VARS=${11}

IMAGE="${ACR}/${REPO}:${TAG}"

container_revision=$(az containerapp update -n ${CONTAINERAPP_NAME} -g ${RG} \
    --image ${IMAGE} \
    --cpu ${CPU} \
    --memory "${RAM}Gi" \
    --min-replicas ${MIN_SCALE} \
    --max-replicas ${MAX_SCALE} \
    --scale-rule-name "http-scale-rule" \
    --scale-rule-type "http" \
    --scale-rule-http-concurrency ${SCALE_HTTP_CONCURRENCY} \
    --only-show-errors \
    --set-env-vars ${ENV_VARS} | jq -r ".properties.latestRevisionName")

echo $container_revision

Solution

  • Based on my attempt, when running the 'az containerapp update' command and use the parameter '--image' (or -i) to pass an new image (registry/imageName:tag), if the specified image tag does not existing in the registry, the command will not throw any error/warning message for this. It still runs successfully and will not make update to container app. And from the output JSON of this command, we can see it still use the old image tag on the container app.


    Based on the YAML you provided, you seem run the BuildCode job and Deploy job in two different YAML pipelines.

    What you need to know that:

    You should put the BuildCode job and Deploy job in the same pipeline so that they can be executed in a same pipeline run every time. If so, the $(Build.BuildId) will return the same value in the two jobs every time.