This is part 2 of the blog series where we create a build and release pipeline in Azure DevOps that will deploy an App Engine Flexible Environment in GCP.

You can find the first part here where we walked through creating a build pipeline that built and pushed two Docker images to Google Cloud Registry. In this part, we will create the release pipeline that will run a Dockerised gcloud program to deploy our application to GCP.

Before We Start

To deploy our application to App Engine, we will be using a Dockerised gcloud program running inside our pipeline agent. These steps have been modified from Thomas Ruble's medium article and could apply to deploy anything else to GCP.

  1. Upload the key to the service account we created in the previous blog part (Creating a GCP Project section) into our project in Azure DevOps.

    • Navigate to "Pipelines" > "Library" > "Secure files (tab)" > "+ Secure file".
    • Upload the secure file and click “OK”.
    • Click on the secure file to edit. Rename the file to something more meaningful in our context (e.g., sa-key-dev.json).
    • Click "save" to save the secure file.
    • Azure Secure File
  2. In our source code repository, create the following helper scripts and a docker-compose file. Ensure that the helper scripts are not within any of the ASP.NET projects you created.

    • Project Folder Structure


    • This file will use a gcloud image from Google Cloud Registry to run 2 helper scripts ( and
    • The above environment variables will be supplied via the release pipeline to support multiple project environments.

    • This script authenticates the service account with the supplied key file (e.g. sa-key-dev.json) which we will be downloading into the agent when we are setting up our release pipeline.

    • This script specifies the commands needed for us to deploy our application.
    • --stop-previous-version: To stop the previously running version of our service.
    • --quiet: To disable all interactive prompts when running gcloud commands. gcloud app deploy would normally get user confirmation before deploying an application.
  3. Push the local code changes up to Azure DevOps.

Release Pipeline

Now that we have set up our Dockerised gcloud program, it is time to create our release pipeline.

Create Azure Release Pipeline

  1. Navigate to "Pipelines" > "Releases" > "New Pipeline".
  2. Start with an "Empty Job".
  3. Add an Artifact:
    • Use "Azure Repo" as the "Source Type", selecting our <Project> and <Source(repository)>.
  4. Add a Stage:
    • Start with an "Empty Job".
    • Name the stage something relevant (e.g., App Engine Dev).
  5. Click on "View stage tasks" to customise the tasks.
    • Release Pipeline Dev Stage
      • You can do this by hovering over "# job, # tasks".
    • For "Agent job", customise the "Agent Specification" so that it is running on "ubuntu-18.04".

Create tasks for the Agent job

We will now need to create tasks for the Agent to run. Each of the following represents a task in the agent job.

  1. "Download secure file"

    • This downloads the service account key we have uploaded to Azure DevOps earlier onto the agent machine so that it can be used in our pipeline to authenticate.
    • In "Output Variables" > "Reference", give it a name that you can reference from the next task (e.g., sakey).
  2. "Command line"

    • We then need to copy the service account key file that we have just downloaded to our source code directory.
    • Ensure that the destination directory is in the same directory as where your docker-compose.yaml is.
    • For example:
  3. "Command line" (Optional)

    • You would only need to do this if you would like to check that you have got the path correct in the last step.
      • You should see both docker-compose.yaml and sa-key-dev.json in the same directory.
  4. "Command line"

    • We will now need to assign the two bash scripts ( and permission to execute as they do not have it by default.
  5. "Docker Compose"

    • This task will run the Dockerised gcloud program that we have setup in our source code.
    • "Container Registry Type": "Container Registry"
    • "Docker Registry Service Connection":
      • Select the service connection that you have configured for Google Container Registry in the previous blog post (Create GCR Service Connection in Azure section).
    • "Docker Compose file":
      • Use the Browse button ( ... ) to select the docker-compose.yaml file in your source code repository.
    • "Environment Variables":
    • "Action": "Run a specific service image"
    • "Service Name": gcloud
    • "Run in background":
      • Ensure this is not checked.
    • "Advanced Options" > "Working Directory"
      • Ensure that it is the directory that the docker-compose.yaml is in.
  • Release Pipeline Agent Jobs
    • All the tasks in the release pipeline.

Getting shared tag variable

As mentioned in the previous blog post, we will need the value of the tag variable to specify which image to deploy.

  1. In the same release pipeline, navigate to the "Variables" tab.

    • "Variables group" > "Link Variable group" > select the variable group we created in the previous blog part (Shared Variable section).
    • Ensure that "Releases" is selected for the "Variable group scope".

    Link Variable Group

  2. In the stage for deploying to our dev App Engine, we have to update the "Docker Compose task". We need to add LATEST_TAG with the value of the latestTag from our variable group to the "Environment Variables", so that docker-compose.yaml can access it.

    Docker Compose Environment Variables

App Engine Deployed

Have a go at creating a release! After the release pipeline has run successfully, you will be able to see your App Engine application with its 2 versions in GCP.

App Engine Versions

Closing Remarks

In this blog series, we have covered how to build and deploy an App Engine Flex application from Azure Pipelines for a development environment. As mentioned earlier, you can also extend this to support an additional deployment environment, such as production. You can do this by creating a separate stage and adding additional tasks to the new stage in the build and release pipeline. Hopefully this has been helpful to you in your journey!