Sam Hooke

GitLab CI: Using a private project's container in a Dockerfile

In GitLab, if you have a Container Registry set up for a private project (“Project A”), and you wish to use one of those containers in the FROM <image> field of a Dockerfile in another project (“Project B”) to create a new container, which you will then push to Project B’s Container Registry, e.g.:

.gitlab-ci.yml
# Project B

my_stage:
	image: docker:latest
	script:
		# Specify the name of the container we want to create in Project B's
		# Container Registry.
		- TAG="$CI_REGISTRY_IMAGE/my_container:1.2.3"

		# Execute the Dockerfile (see below) which pulls a base image from
		# Project A's Container Registry and uses it to build a new image.
		- docker build --pull --tag "$TAG" .

		# Push the new image to Project B's Container Registry.
		- docker push "$TAG"
Dockerfile
# Project B

# Use image from Project A as base.
FROM your.gitlab.address.com:5000/project/group/container:1.2.3

# ...configuring image for Project B...

Then you might get a 403 Forbidden error as follows:

ERROR: failed to authorize: failed to fetch anonymous token: unexpected status from GET request to https://your.gitlab.address.com/blah 403 Forbidden

The problem is that the instance of Docker running in Project B’s container does not have permission to access Project A’s Container Registry, even if both projects are part of the same group.

This is subtly different from the previous note about using the container as an image: within GitLab CI, because this time it is not the GitLab Runner trying to pull the images, but the Docker process running within the container launched by the GitLab Runner.

You can fix this by using docker login to authenticate with Project A’s Container Registry before doing docker build. Then you have to do docker logout and docker login to Projet B’s Container Registry before being able to docker push the new container to Project B’s Container Registry.

The steps are as follows:

  1. On Project A (the one with the Container Registry), go to Settings > Access Tokens.
  2. Choose a token name, e.g. ci_pull_containers.
  3. Set role to “Developer”.
  4. Check the box for read_registry.
  5. Click “Create project access token”:
GitLab CI: Create project access token
  1. On Project B (the one wanting to access Projet A’s Container Registry), go to Settings > CI/CD > Variables.
  2. Click Add variable to open up a modal.
  3. Set the key as PROJECT_A_REGISTRY_USER and paste the token name, e.g. ci_pull_containers.
  4. Click Add variable to save the new variable.
  5. Click Add variable to open up a modal.
  6. Set the key as PROJECT_A_REGISTRY_PASSWORD and paste the access token.
  7. Click Add variable to save the new variable.
  8. Modify your .gitlab-ci.yml to docker login to your.gitlab.address.com:5000 using PROJECT_A_REGISTRY_USER and PROJECT_A_REGISTRY_PASSWORD, and then docker logout and docker login as CI_REGISTRY_USER (which is automatically created by GitLab CI for read-write access to the project’s own Container Registry):
.gitlab-ci.yml
# Project B

my_stage:
	image: docker:latest
	script:
		# Specify the name of the container we want to create in Project B's
		# Container Registry.
		- TAG="$CI_REGISTRY_IMAGE/my_container:1.2.3"

		# Log in to Project A's Container Registry using the variables set in
		# steps 8 and 11.
		- docker login your.gitlab.address.com:5000 --username $PROJECT_A_REGISTRY_USER --password $PROJECT_A_REGISTRY_PASSWORD

		# Execute the Dockerfile (see below) which pulls a base image from
		# Project A's Container Registry and uses it to build a new image.
		- docker build --pull --tag "$TAG" .

		# Log out, then log in to Project B's Container Registry using the
		# variables that are automatically generated by GitLab CI.
		- docker logout
		- docker login --username $CI_REGISTRY_USER --password $CI_REGISTRY_PASSWORD $CI_REGISTRY

		# Push the new image to Project B's Container Registry.
		- docker push "$TAG"
  1. That’s it! CI jobs run on Project B will now be able to access images from Project A in the Dockerfile, and then push them to their own (Project B’s) Container Registry.
  2. Note that when the token expires you will need to create a new one and update PROJECT_A_REGISTRY_PASSWORD.