How to build and push a docker image in a Terraform Docker Provider by GCP Cloud Build

Viewed 207

References

Terraform Docker Provider

Terraform Google Provider

GCP Cloud Build

Context Details

  1. The deployemnt is done by CICD based on the GCP Cloud Build (and the cloud build service account has an 'owner' role for relevant projects).

  2. Inside a 'cloudbuild.yaml' file there is a step with a 'hashicorp/terraform' worker an a command like 'terraform apply'.

Goal

To build and push a docker image into a GCP Artefact Registry, so that it can be used in a container optimised compute engine deployment in other TF resources.

Issue

As the Terraform Google Provider does not have resources to work with the Artefact Registry docker images, I have to use the Terraform Docker Provider.

The docker image is described as:

resource "docker_registry_image" "my_image" {
  name = "europe-west2-docker.pkg.dev/${var.my_project_id}/my-docker-reg/my-vm-image:test"
  build {
    context = "${path.module}/image"
    dockerfile = "Dockerfile"
  }
}

According to the comment Creating and pushing a docker image to a google cloud registry using terraform: For pushing images, the only way to set credentials is to declare them at the provider level.

Therefore the registry_auth block is to be provided as described in the Terraform Docker Provider documentation.

On one hand, as described in the GCP Artefact Registry authentication documentation You do not need to configure authentication for Cloud Build. So I use this for configuration (as it is to be executed under the Cloud Build service account):

provider "docker" {
  registry_auth {
    address  = "europe-west2-docker.pkg.dev"
  }
}

and the Cloud Build job (terraform step) failed with an error:

Error: Error loading registry auth config: could not open config file from filePath: /root/.docker/config.json. Error: open /root/.docker/config.json: no such file or directory

  with provider["registry.terraform.io/kreuzwerker/docker"],
  on my-vm-image.tf line 6, in provider "docker":
   6: provider "docker" {

as the Docker Provider mandatory would like to get some credentials for authentication...

So, another option is to try an 'access token' as descibed in the comment and documentation.

The access token for the cloud build service account can be retrieved by a step in the cloud build yaml:

## Get Cloud Build access token
- id: "=> get CB access token =>"
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'sh'
  args:
    - '-c'
    - |
      access_token=$(gcloud auth print-access-token) || exit 1
      echo ${access_token} > /workspace/access_token || exit 1

and later used in the TF step as a variable value:

...
access_token=$(cat /workspace/access_token)
...
terraform apply -var 'access_token=${access_token}' ....
...

So the Terraform Docker Provider is supposed to be configured according to the example gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://LOCATION-docker.pkg.dev from the GCP Artefact Registry authentication documentation:

provider "docker" {
  registry_auth {
    address  = "europe-west2-docker.pkg.dev"
    username = "oauth2accesstoken"
    password = var.access_token
  }
}

But the Cloud Build job (terraform step) failed again:

Error: Error pushing docker image: Error pushing image: unauthorized: failed authentication

Questions

So, if I dont' try any completely different alternative approach, how the Terraform Docker Provider works within the GCP Cloud Build? What is to be done for a correct authentication?

1 Answers

As the Terraform Google Provider does not have resources to work with the Artefact Registry docker images

First, I don't understand the above sentence. Here is Google's Artifact Registry resource.

Second, why use docker_registry_image? Or even docker provider?

If you provide your service account with the right role (no need for full ownership, roles/artifactregistry.writer will do) then you can push images built by Cloud Build to Artifact Registry without any problem. Just set the image name to docker in the necessary build steps.

For example:

steps:
  - id: build
    name: docker
    args:
      - build
      - .
      - '-t'
      - LOCATION-docker.pkg.dev/PROJECT_ID/ARTIFACT_REGISTRY_REPO/IMAGE
  - id: push
    name: docker
    args:
      - push
      - LOCATION-docker.pkg.dev/PROJECT_ID/ARTIFACT_REGISTRY_REPO/IMAGE
Related