GitLab CI/CD: Architecting, Deploying, and Optimizing Pipelines

Continuous Integration with GitLab

Publish Image to Gitlab Container Registry

In this guide, you’ll learn how to authenticate with GitLab’s integrated Container Registry and publish your Docker images—both manually and via GitLab CI/CD pipelines. The Container Registry is available for every GitLab project, offering a secure, private registry alongside your code.

Authentication Methods

GitLab supports several registry authentication methods:

  • Personal Access Tokens
  • Deploy Tokens
  • Project Access Tokens
  • Group Access Tokens

Refer to the official GitLab Container Registry guide for details on creating and managing tokens.

The image shows a GitLab documentation page about the container registry, detailing how to use and view the integrated container registry for GitLab projects. The sidebar includes navigation options related to package and container management.

Logging in with a Token

Locally, you can log in using any valid token:

TOKEN=<your_token>
docker login registry.example.com -u <username> --password-stdin <<< "$TOKEN"

Within a GitLab CI/CD job, leverage predefined variables for seamless authentication:

docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin <<< "$CI_REGISTRY_PASSWORD"
docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin <<< "$CI_JOB_TOKEN"
docker login $CI_REGISTRY -u $CI_DEPLOY_USER --password-stdin <<< "$CI_DEPLOY_PASSWORD"

Note

Always keep your tokens secure. GitLab’s predefined variables (e.g., CI_JOB_TOKEN) expire automatically, reducing exposure risk.

Building and Pushing Images Manually

If you prefer to build and push outside of CI/CD, follow these steps:

docker build -t registry.gitlab.com/<group>/<project>/<image-name> .
docker push registry.gitlab.com/<group>/<project>/<image-name>

Replace <group>, <project>, and <image-name> with your specific values.

GitLab CI/CD Job: publish_gitlab_container_registry

Below is an example publish_gitlab_container_registry job that:

  1. Loads a prebuilt image archive
  2. Authenticates to the registry
  3. Tags the image
  4. Pushes it upstream
publish_gitlab_container_registry:
  stage: containerization
  needs:
    - docker_build
    - docker_test
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  script:
    - docker load -i image/solar-system-image-$CI_PIPELINE_ID.tar
    - echo "Registry: $CI_REGISTRY | User: $CI_REGISTRY_USER | Repo: $CI_REGISTRY_IMAGE"
    - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
    - docker tag $DOCKER_USERNAME/solar-system:$IMAGE_VERSION $CI_REGISTRY_IMAGE/ss-image:$IMAGE_VERSION
    - docker images
    - docker push $CI_REGISTRY_IMAGE/ss-image:$IMAGE_VERSION

Predefined CI/CD Variables

The image shows a GitLab documentation page about predefined CI/CD variables, specifically focusing on registry-related variables like `CI_REGISTRY`, `CI_REGISTRY_IMAGE`, and `CI_REGISTRY_PASSWORD`. The sidebar lists various documentation sections.

VariableDescriptionExample
CI_REGISTRYHostname of the container registryregistry.gitlab.com
CI_REGISTRY_USERUsername for Docker login (typically a CI job token)$CI_REGISTRY_USER
CI_REGISTRY_PASSWORDPassword or token for authentication$CI_REGISTRY_PASSWORD
CI_REGISTRY_IMAGEFull path to the project’s image reporegistry.gitlab.com/group/project

Viewing the Registry Before and After Push

Before any push, the Container Registry is empty:

The image shows a GitLab interface for a project named "Solar System" with the Container Registry section open, indicating no container images are stored for the project. The sidebar includes options like Manage, Plan, Code, and Deploy.

After committing your .gitlab-ci.yml and running the pipeline, the publish_gitlab_container_registry job executes in parallel with other containerization steps:

The image shows a GitLab CI/CD pipeline interface for a project named "Solar System NodeJS Pipeline," displaying various stages and jobs such as code coverage, unit testing, docker build, and docker push.

Troubleshooting Login Errors

If you encounter a syntax error using --password-stdin, switch to the -p flag:

-script:
-  - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" --password-stdin <<< "$CI_REGISTRY_PASSWORD"
+script:
+  - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"

Warning

Passing passwords directly via -p can be insecure. Use --password-stdin where possible, and ensure your CI logs are protected.

Verifying a Successful Push

Once the job completes, your logs should look like this:

$ docker load -i image/solar-system-image-$CI_PIPELINE_ID.tar
$ echo "Registry: $CI_REGISTRY = $CI_REGISTRY_USER = $CI_REGISTRY_IMAGE"
$ docker login $CI_REGISTRY --username="$CI_REGISTRY_USER" --password="$CI_REGISTRY_PASSWORD"
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
$ docker tag $DOCKER_USERNAME/solar-system:$IMAGE_VERSION $CI_REGISTRY_IMAGE/ss-image:$IMAGE_VERSION
$ docker images
$ docker push $CI_REGISTRY_IMAGE/ss-image:$IMAGE_VERSION

Returning to the Container Registry now reveals the newly published image:

The image shows a GitLab container registry interface for a project named "Solar System," displaying details of an image called "ss-image," including its size, tag, and digests.

Here you can inspect tags, image sizes, and manifest digests. You’ve successfully published your Docker image to GitLab’s Container Registry!

Watch Video

Watch video content

Previous
Docker Push