Continuous deployment for Artifact Registry container images

05 Jan, 2023
Xebia Background Header Wave

Continuous deployment to Cloud Run works out-of-the-box when you own the application code. However, you don’t always own the application code. You might use suppliers that publish container images to your Artifact Registry. Therefore, this blog shows how to configure a continuous deployment pipeline for container images.

Target implementation

Suppliers publish container images to trigger application deployments. To track changes, applications are deployed using Terraform tracked by a Git repository. The process is shown below:


Get the example code on GitHub.

Artifact Registry notifications

Artifact Registry (and Container Registry) publish notifications to the gcr Pub/Sub topic. These notifications include the action (insert/delete) and the digest/tag of the container image. We are interested in the insert-events and the image digests to update the application infrastructure.

Cloud Build triggers

Pub/Sub easily integrates with Cloud Build. Simply configuring a trigger for Pub/Sub events suffices. The next trigger is configured to act on Artifact Registry insert-events for specific application images:

resource "google_cloudbuild_trigger" "gitops_application_update" {


  pubsub_config {
    topic =

  substitutions = {
    _ACTION       = "$("
    _IMAGE_DIGEST = "$("

  filter = "_ACTION.matches('INSERT') && _IMAGE_DIGEST.startsWith('')"

Application deployment

The application (and associated infrastructure) is deployed using Terraform. The Terraform configuration is tracked by Git to ensure that the Terraform state doesn’t drift. To keep the Terraform configuration up to date, the deployment pipeline commits the new application version. To keep the application infrastructure up to date, the deployment pipeline applies the Terraform configuration.

resource "google_cloudbuild_trigger" "gitops_application_update" {


  build {
    source {
      repo_source {
        project_id = var.project_id
        repo_name  =
        branch_name = "main"

    step {
        name = ""
        entrypoint = "bash"
        args = [


            echo "${each.value.variable_name} = \"$${_IMAGE_DIGEST}\"" > variables.${each.key}.auto.tfvars

            git add variables.${each.key}.auto.tfvars
            git commit -m "Set ${each.key} version to $${_IMAGE_DIGEST}"
            git push

    step {
      name = "hashicorp/terraform:1.2.9"
      args = ["init", "-no-color"]

    step {
      name = "hashicorp/terraform:1.2.9"
      args = ["apply", "-no-color", "-lock-timeout=300s", "-auto-approve"]


While continuous deployment is great, checks and balances are necessary. This example blindly releases the application to production. In reality, this will break your production environment. To comfortably release to production, extend the deployment pipeline with quality gates that test the container image.

This example uses Cloud Build to automate the deployment process. The demonstrated process has two outputs: updated GitOps repository and updated application infrastructure. For production use case, it would make sense to split the two outputs to separate processes. To govern the process, the process could be implemented using Cloud Workflows.


Continuous deployment for container images is enabled by Artifact Registry notifications. By subscribing Cloud Build triggers to these notifications, you release application updates automatically. While this blog uses a Terraform-based GitOps deployment, you can implement any deployment process with Cloud Build.

Image by Pexels from Pixabay

Laurens Knoll
As a cloud consultant I enjoy taking software engineering practices to the cloud. Continuously improving the customers systems, tools and processes by focusing on integration and quality.

Get in touch with us to learn more about the subject and related solutions

Explore related posts