20

How should I authenticate if I want to use an image from the Gitlab Registry as a base image of another CI build?

According to https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#using-a-private-docker-registry I first have to manually login on the runner machine. Somehow it feels strange to login with an existing Gitlab user.

Is there a way to use the CI variable "CI_BUILD_TOKEN" (which is described as "Token used for authenticating with the GitLab Container Registry") for authentication to pull the base image from Gitlab Registry?

EDIT: I found out that I can use images from public projects. But I don't really want to make my docker projects public.

UPDATE: Starting with Gitlab 8.14 you can just use the docker images from the build in docker registry. See https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#support-for-gitlab-integrated-registry

Martin Sadowski
  • 203
  • 1
  • 2
  • 5

6 Answers6

17

All of the above answers including the acepted one are deprecated, This is possible in 2021:

https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#access-an-image-from-a-private-container-registry


TL;DR

Set the CI/CD variable DOCKER_AUTH_CONFIG value with appropriate authentication information in following format:

Step 1:

# The use of "-n" - prevents encoding a newline in the password.
echo -n "my_username:my_password" | base64

# Example output to copy
bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=

Step 2 (This JSON is the value to be set for DOCKER_AUTH_CONFIG variable):

{
    "auths": {
        "registry.example.com:5000": {
            "auth": "(Base64 content from above)"
        }
    }
}
humble_wolf
  • 1,497
  • 19
  • 26
9

Now it's possible, they have included that option months ago.

Use gitlab-ci-tokenas user and the variable $CI_BUILD_TOKEN as password.

This example works on GitLab 8.13.6. It builds the test image if needed, and in the next stage uses it to perform syntax checks:

build_test:
  stage: build_test_image
  script:
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:test -f dockerfiles/test/Dockerfile .
    - docker push $CI_REGISTRY_IMAGE:test
  tags:
    - docker_build
  environment: test

test_syntax:
  image: $CI_REGISTRY_IMAGE:test
  stage: test
  script:
    - flake8 --ignore=E501,E265,E402 .

UPDATE: Re-reading the question, the accepted answer is correct. In my example, the job test_syntax will fail to authenticate to the registry, unless the user logins manually from the runner machine. Although, it can work if the 2 runners are on the same host, but it's not the best solution anyway.

In gitlab-ci-multi-runner 1.8 there's an option to add the Registry credentials as a variable, so you only need to login once to get the encoded credentials. See documentation.

charli
  • 1,700
  • 1
  • 13
  • 21
  • What type of runner are you using to do this? If you're using a shell runner then GitLab CI isn't pulling the image from the registry but is instead using the image you just built on the host in the previous stage. – BrokenBinary Dec 20 '16 at 17:23
  • Actually I'm using 2 runners. One with shell executor, another with docker executor. The intended usage of the shell executor is only to build Docker images, that's why I'm using the tag `docker_build`. Note also the `image` directive inside the job `test_syntax` and the lack of it on `build_test`. – charli Dec 20 '16 at 21:23
6

No, this is currently not possible in any elegant way. GitLab should implement explicit credentials for the base images, it will be the most straight-forward and correct solution.

You need to docker login on the GitLab Runner machine. You can't use the gitlab-ci-token since they expire and also project-dependant, so you can't actually use one token for every project. Using your own login is pretty much the only solution available right now (happy to get corrected on this one).

Nikolai Prokoschenko
  • 8,465
  • 11
  • 58
  • 97
  • 1
    Thanks. You're right. It's not possible right now. Pointers I found: https://gitlab.com/gitlab-org/gitlab-ce/issues/19219 and https://gitlab.com/gitlab-org/gitlab-ce/issues/19275 – Martin Sadowski Jul 10 '16 at 10:35
  • To follow up on this, there are a couple gitlab tickets related to exposing this functionality in a more elegant way (https://gitlab.com/gitlab-org/gitlab-ce/issues/19275). However, this appears to sit in backlog right now. Hopefully, with more support, this capability will be something that the team identifies to be as important as the user community seems to. – user376327 Sep 08 '16 at 14:14
4

This is absolutely possible as of September 2018. I'll post my naive implementation here.

Context:

  • You'll need to leverage the docker:dind service, which lets you run the docker command inside of a docker container.
  • This will require you to use a valid docker login, which you can do using GitLab's builtin variables (gitlab-ci-token, $CI-JOB-TOKEN).
  • You should then be able to authenticate to your repo's registry (example $REGISTRY value: registry.gitlab.com/$USER/$REPO:$TAG), which will allow you to push or pull docker containers from inside the CI/CD context, as well as from any authenticated docker server.

Implementation:

Create this block at top level to ensure it runs before the following jobs:

before_script: 
        - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $REGISTRY

Job to build and save images to your registry:

build_container:
    image: docker:latest
    stage: build
    services:
        - docker:dind
    script:
        - docker build -t $REGISTRY .
        - docker push $REGISTRY

Job that uses the custom image:

build_app:
    image: $REGISTRY
    stage: deploy
    script:
        - npm run build

Regarding Cross-Repo Jobs:

I accomplish this by creating a "bot" GitLab user and assigning them access to repos/groups as appropriate. Then it's just a matter of replacing gitlab-ci-token and $CI_JOB_TOKEN with appropriate environment variables. This is only necessary if the base image is private.

Chris Vincent
  • 123
  • 12
  • 1
    before_script doesn't run "before" the job. It is simply concatenated with the script element, and run in the context of the image specified in the job. Given that, this doesn't look like it will work? – Michael Macnair Feb 23 '21 at 12:05
  • 1
    I'm usually using the `before_script` within an extended job so that it can be shared with multiple other docker jobs (one each for push to gitlab/dockerhub/etc., depending on tag/branch). It's intended to be run within the context of the image and leveraging the `dind` service, as the image needs to have access to docker commands for any of `login`, `build`, `push` to work. As long as the `login` comes first, this all works as intended. I use this strategy for multiple production applications; if you're having a specific problem I can try to help you out. – Chris Vincent Mar 01 '21 at 19:01
1

Its possible you first have to login to gitlab container registry of the image you want to use, kindly see below example. Notice the before_script: which basically auths you before using the image.

image: docker:latest
services:
  - docker:dind

stages:
  - build

variables:
  CONTAINER_RELEASE_IMAGE: registry.gitlab.com/obonyojimmy/node-mono-clr:latest

before_script:
  - docker login -u $CI_REGISTRY_USER -p $CI_BUILD_TOKEN registry.gitlab.com

build-app:
  stage: build
  image: $CONTAINER_RELEASE_IMAGE
  script:
    - npm run build
Skaronator
  • 33
  • 1
  • 9
Jimmy Obonyo Abor
  • 7,335
  • 10
  • 43
  • 71
0

I had a similar situation. My Java application uses Testcontainers lib in tests and this lib runs Docker container from private registry. I spent a lot of time trying to figure this out and I managed to handle this by creating a ~/.docker/config.json file in before_script section. I hope it'll help somebody:

image: openjdk:11-jdk-slim

stages:
  - build

before_script:
  - mkdir ~/".docker"
  - echo "{\"auths\":{\"$REGISTRY_HOST\":{\"auth\":\"$(printf "$REGISTRY_USER:$REGISTRY_PASSWORD" | openssl base64 -A)\"}}}" > ~/".docker/config.json"

build:
  stage: build
  services:
    - docker:dind
  script:
    - ./gradlew build