Changes for building and deploying in Google Cloud

This document guides you through the differences between Container Registry and Artifact Registry when building container images with Cloud Build and deploying them to Google Cloud runtime environments such as Cloud Run or Google Kubernetes Engine.

In this guide, comparisons focus on standard Artifact Registry repositories, regular Artifact Registry repositories that are independent of Container Registry and support all Artifact Registry features. If your administrator set up repositories with gcr.io domain support, requests to gcr.io hostnames are automatically redirected to a corresponding Artifact Registry repository and default service accounts that have access to Container Registry have equivalent default permissions for Artifact Registry.

To learn about the differences between Container Registry and Artifact Registry using a Docker client, see Changes to pushing and pulling with Docker.

Use this information to help you adapt existing commands, configuration, or documentation focused on Container Registry with Cloud Build.

Before you begin

This document assumes that you have:

  1. Enabled Artifact Registry in your project.
  2. Enabled the Cloud Build API and the API for any other Google Cloud service you are using with Artifact Registry.

Changes to the workflow

When you use Cloud Build with Container Registry within the same project, the workflow looks like this:

  1. Build, tag, and push an image to the repository with Cloud Build, using a Dockerfile or a build config file.

    The following example builds the image my-image, tags it with tag1, and pushes it to the host gcr.io in the project my-project:

    gcloud builds submit --tag gcr.io/my-project/my-image:tag1
    
  2. Google Cloud runtime environments, such as Cloud Run and Google Kubernetes Engine pull images from the registry.

    For example, this command deploys the image from the previous step to Cloud Run as my-service.

    gcloud run deploy my-service --image gcr.io/my-project/my-image:tag1
    

The Container Registry workflow combines administrator responsibilities with building and deploying.

  • When you enable some Google Cloud APIs, the Container Registry API is enabled automatically. This means users of these services have implicit access to Container Registry in the same project. For example, users who can run builds in Cloud Build can push images to registries and add registry hosts by default.
  • The Cloud Build service account has permissions to create Cloud Storage storage buckets. This means that the account can automatically add Container Registry hosts to a project the first time that it pushes an image to the host. It also means that the account can create, read, and write to storage buckets across the entire project, including buckets that are not used by Container Registry.

In Artifact Registry, there is a clear separation of administrator and build roles that changes the steps in the build and deploy workflow. To adapt the Container Registry workflow for Artifact Registry, make the following changes. Each step links to additional information about modifying the workflow.

  1. New: Enable the Artifact Registry API.

    You must enable the Artifact Registry API. Cloud Build and runtime environments such as Cloud Run and GKE do not automatically enable the API for you.

  2. New: Create the target Docker repository if it doesn't already exist. You must create a repository before you can push any images to it. Pushing an image can't trigger creation of a repository and the Cloud Build service account does not have permissions to create repositories.

  3. Changed: Build, tag, and push an image to the repository with Cloud Build, using a Dockerfile or a build config file.

    The following example command is the same as the Container Registry example, but uses a Artifact Registry repository path for the image.

    gcloud builds submit --tag us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag1
    
  4. Changed: Deploy the image to a Google Cloud runtime environment such as Cloud Run or GKE.

    The following example command is the same as the Container Registry example, but uses the Artifact Registry repository path for the image.

    gcloud run deploy my-service --image us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag1
    

In addition, Artifact Registry uses different roles than Container Registry to control access to images. You need to configure permissions in the following situations:

  • Cloud Build or Google Cloud runtime environments are in a different project than Artifact Registry.
  • You use custom service accounts for Google Cloud services such as Cloud Build or GKE instead of the default service accounts.
  • You granted permissions to other user or service accounts.

Enabling the API

Key points:

The following comparison describes enabling the API for each service:

Container Registry

When you enable the following Google Cloud APIs, the Container Registry API is also automatically enabled:

  • App Engine flexible environment
  • Cloud Build
  • Cloud Run functions
  • Cloud Run
  • Container Scanning or On-Demand Scanning in Artifact Analysis
  • Google Kubernetes Engine

With the default permissions, users who can run builds in Cloud Build, scan containers with Artifact Analysis, or deploy containers to Google Cloud runtimes implicitly have access to images in Container Registry when the registry is in the same project.

Artifact Registry

You must enable the Artifact Registry API. Services such as Cloud Build, Cloud Run, and GKE do not automatically enable the Artifact Registry API.

You can enable multiple APIs in the same project using gcloud. For example, to enable the Cloud Build API and the Artifact Registry API, run the command:

gcloud services enable
    artifactregistry.googleapis.com \
    cloudbuild.googleapis.com

Adding registries and repositories

Key points:

  • You must create an Artifact Registry Docker repository before you push an image to it.
  • Container Registry stores all images in a single multi-region in the same storage bucket. In Artifact Registry, you can create multiple repositories in the same region or multi-region with separate access policies.

The following comparison describes repository setup in each service:

Container Registry

In Container Registry you can add up to four registry hosts to your project. You add a registry host by pushing the first image.

  1. To add a registry such as gcr.io to your project, an account with the Storage Admin role at the project level pushes an initial image.

    For example, if the gcr.io host does not exist in the project my-project, pushing the image gcr.io/my-project/my-image:1.0 triggers the following steps:

    1. Add the gcr.io host to the project
    2. Create a storage bucket for gcr.io in the project.
    3. Store the image as gcr.io/my-project/my-image:1.0
  2. After this initial push, you can then grant permissions to the storage bucket for other users.

By default Cloud Build has the required permissions to create a storage bucket, so the initial image push and subsequent pushes are indistinguishable.

Within a project, a registry host stores all images in the same storage bucket. In the following example, the project my-project has two images called web-app in the registry gcr.io. One is directly under the project ID my-project. The other image is in the repository team1.

gcr.io/my-project/web-app
gcr.io/my-project/team1/web-app

Artifact Registry

Cloud Build does not have permissions to create a standard repository on the Artifact Registry pkg.dev domain.

An account with the Artifact Registry Repository Administrator role must create the repository before you push images to it. You can then grant permissions to the repository for other users.

In Artifact Registry each repository is a separate resource. Therefore, all image paths must include a repository.

Valid image paths:

us-central1-docker.pkg.dev/my-project/team1/web-app:1.0
us-central1-docker.pkg.dev/my-project/team2/web-app:1.0

Invalid image path (does not include a repository) :

us-central1-docker.pkg.dev/my-project/web-app:1.0

The following examples show situations where pushing an image to a missing repository fails.

  • Pushing an image to us-central1-docker.pkg.dev/my-project/team1 if us-central1-docker.pkg.dev/my-project/team1 does not exist.
  • Pushing an image to us-central1-docker.pkg.dev/my-project/team2 when us-central1-docker.pkg.dev/my-project/team1 exists, but us-central1-docker.pkg.dev/my-project/team2 does not exist.

Granting permissions

Key points:

  • Google Cloud services have equivalent read or write access to both Container Registry and Artifact Registry. However, the default Cloud Build service account can't create standard repositories on the pkg.dev domain.
  • Grant the appropriate Artifact Registry roles to other accounts that access Artifact Registry.
  • Container Registry supports access control at the storage bucket level. Artifact Registry supports access control at the repository level.

The following comparison describes permissions for each service:

Container Registry

Container Registry uses the Cloud Storage roles to control access. Cloud Build has the required permissions in the Storage Admin role to add Container Registry hosts to a project.

Storage Object Viewer at the storage bucket level
Pull (read) images from existing registry hosts in the project.
Storage Legacy Bucket Writer at the storage bucket level
Push (write) and pull (read) images for existing registry hosts in the project.
Storage Admin at the project level
Add a registry host to a project by pushing an initial image to the host.

After the initial image push to a registry, you grant Cloud Storage roles to other accounts that require access to the storage bucket. Note that any account with all permissions in the Storage Admin role can read, write, and delete storage buckets and storage objects across the entire project.

Permissions on a storage bucket apply to all repositories in the registry. For example, any user with Storage Object Viewer permissions on the bucket for gcr.io/my-project can read images in all these repositories:

gcr.io/my-project/team1
gcr.io/my-project/team2
gcr.io/my-project/test
gcr.io/my-project/production

Artifact Registry

Artifact Registry has its own roles to control access. These roles provide clear separation between administrator and repository user roles.

Cloud Build has permissions in the Artifact Registry Writer role since it only needs to push and pull images with standard repositories on the pkg.dev domain.

Only accounts that manage repositories should have the Artifact Registry Repository Administrator or Artifact Registry Administrator role.

Artifact Registry Reader
List artifacts and repositories. Download artifacts.
Artifact Registry Writer
List artifacts and repositories. Download artifacts, upload new artifact versions, and add or update tags.
Artifact Registry Repository Administrator
Artifact Registry Writer permissions and permissions to delete artifacts and tags.
Artifact Registry Administrator
Artifact Registry Repository Administrator permissions and permissions to create, update, delete, and grant permissions to repositories.

You can apply these permissions at the repository level. For example:

  • Grant access to Team 1 for us-central1-docker.pkg.dev/my-project/team1
  • Grant access to Team 2 for us-central1-docker.pkg.dev/my-project/team2.

For details about granting Artifact Registry permissions, see the access control documentation.

Building and pushing images

Key points:

  • You must create an Artifact Registry Docker repository before you push an image to it.
  • The Artifact Registry hostnames are different than Container Registry hostnames.

Cloud Build can build, tag, and push an image in a single step.

With Container Registry, Cloud Build can successfully push an image to a registry host that doesn't exist yet in the Google Cloud project. For this initial image push, Cloud Build has permissions to automatically add the registry host to the project.

To adapt a Container Registry workflow:

  1. Set up your repositories before you push images to them.
  2. Update the image paths in your or build config file or gcloud builds submit commands.

Building with a build config file

Replace Container Registry paths for images that you build with the path to an existing Artifact Registry repository.

The following example cloudbuild.yaml file builds the image us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag1:

steps:
- name: 'gcr.io/cloud-builders/docker'
  args: [ 'build', '-t', 'us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag1', '.' ]
images:
- 'us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag1'

You can then build the image with the command:

gcloud builds submit --config cloudbuild.yaml

Building with a Dockerfile

Replace Container Registry paths for images that you build with the path to an existing Artifact Registry repository.

The following example command builds the image us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag1 with a Dockerfile in the current directory:

gcloud builds submit --tag us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag1

Deploying images

Key point:

  • The Artifact Registry hostnames are different than Container Registry hostnames.

To adapt a Container Registry workflow, update image paths in your deployment configuration and deployment commands. The following sections show examples for Cloud Build, Cloud Run, and GKE, but the same approach applies for any other Google Cloud services that deploy images.

Cloud Build

Replace Container Registry paths for images that you deploy with the path to an existing Artifact Registry repository.

The following example cloudbuild.yaml file deploys the sample image us-docker.pkg.dev/cloudrun/container/hello.

steps:
- name: 'gcr.io/cloud-builders/gcloud'
  args:
  - 'run'
  - 'deploy'
  - 'cloudrunservice'
  - '--image'
  - 'us-docker.pkg.dev/cloudrun/container/hello'
  - '--region'
  - 'us-central1'
  - '--platform'
  - 'managed'
  - '--allow-unauthenticated'

Cloud Run

Replace Container Registry paths for images that you deploy with the path to an existing Artifact Registry repository.

For example, this command deploys the sample image us-docker.pkg.dev/cloudrun/container/hello.

gcloud run deploy my-service --image us-docker.pkg.dev/cloudrun/container/hello

GKE

Replace Container Registry paths for images that you build with the path to an existing Artifact Registry repository.

The following examples for Artifact Registry use the sample image us-docker.pkg.dev/artifact-registry-samples/containers/gke/hello-app:1.0.

Creating a cluster from the command line:

kubectl create deployment hello-server --image=us-docker.pkg.dev/artifact-registry-samples/containers/gke/hello-app:1.0

Specifying an image in a deployment manifest:

In a deployment manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-app
  template:
    metadata:
      labels:
        run: my-app
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/artifact-registry-samples/containers/gke/hello-app:1.0