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
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:
Every time when you trigger a new run of a YAML pipeline (or classic build pipeline), it will generate a unique BuildId
for this new pipeline run.
The predefined variable $(Build.BuildId)
can only return the BuildId
of current pipeline.
When you run the BuildCode
job in a pipeline run, the run has a unique BuildId
. If you run the Deploy
job in another pipeline run, this run also has a unique BuildId
that is different than other runs.
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.