GitLab - Using Docker private images
Use a private Docker image from Docker Hub in your GitLab CI/CD pipeline. Learn to create a read-only token and set up the necessary GitLab CI/CD variables for authentication.
This article is over a year old but was reviewed on July 30, 2026 — the content is still accurate.

To use a private Docker image from Docker Hub in a GitLab CI/CD pipeline, first generate a read-only personal access token from your Docker Hub settings. Then, in your GitLab project's CI/CD settings, create two protected and masked variables: DOCKER_HUB_USERNAME for your Docker username and DOCKER_HUB_TOKEN_RO for the access token. Finally, in your .gitlab-ci.yml, use docker login with these variables to authenticate before pulling the image.
In one of my GitLab CI, I came across the need to use a Docker image stored on hub.docker.com in a private repository.
I couldn't simply do a docker pull my_image because, first of all, I had to authenticate myself in the CI before I could retrieve the image (it's a private one).
This article is a how-to and explains how to do it.
Two sibling articles about the same CI: GitLab - Using an SSH key to connect to private repo for private git repositories, and GitLab - Running Docker-out-of-Docker in your CI if your job needs to run docker commands at all.
Here's the payoff once the token and variables are in place: the job authenticates and pulls the private image instead of failing with denied: requested access to the resource is denied.
Why It Works
- The Docker Hub token is scoped
Read-Only, so even if it leaked, it could only pull images — never push or modify anything on your account. - The username and token live as hidden, protected CI/CD variables, never in
.gitlab-ci.ymlitself — GitLab won't even echo them if you turn on full debug tracing.
Create a token
You'll need to create a token first. Please visit this page: https://app.docker.com/settings/personal-access-tokens. You'll need to sign in, of course.
Click on the Generate new token button and create a new one. Make sure to correctly specify the scope. To be able to access private images, you should select Read-Only and not Public Repo Read-Only (because the last one didn't give access to private images).
Once created, Docker will provide you a small help screen where you'll read that you can connect to Docker by using the token just as if it were your password.
Create two CI/CD variables in your repository page
In your GitLab CI/CD settings page, add two new variables:
- The first one will be called
DOCKER_HUB_USERNAME. The value to enter here is your Docker account name (likechristopheormy_companyif the image is stored in a business account) and - the second one will be called
DOCKER_HUB_TOKEN_RO. The value to enter here is the token you've received.
Make sure variables are hidden and protected. This will prevent GitLab from echoing the value in any output like when you initialize CI_DEBUG_TRACE=true (doc) for full debug.
Note
You can add the variables in your repository's CI/CD settings page or at a higher level like the group level or at the instance level (you should be an admin for this).
Your gitlab-ci.yml file
Once done, here is how to connect to Docker in your .gitlab-ci.yml file:
demo: image: docker:latest before_script: - | # Do a secure login echo "$DOCKER_HUB_TOKEN_RO" | docker login -u "$DOCKER_HUB_USERNAME" --password-stdin script: - | # Download the image docker pull your_private_image # - | # Use it # docker run [...] your_private_image [...]This YAML configuration defines a CI/CD job called 'demo' that uses a Docker image to run automated tasks. It first logs into Docker Hub securely using stored credentials, then pulls a private Docker image, with a commented-out section showing how you'd run that image afterward.
Conclusion
A read-only token and two protected, masked CI/CD variables are all it takes to pull a private Docker Hub image in your pipeline, without ever committing a credential to your repo. See GitLab - Using an SSH key to connect to private repo for the same problem applied to a private git repository instead of a private image.
Loading comments…

