Skip to content

GitLab CI/CD Integration

This page explains how to use the registry.isima.fr registry from your GitLab pipelines:

Ready-to-use example project

To get started quickly, take inspiration from the boilerplate repository maintained by the CRI: cri-public/gitlab-ci-registry-boilerplate. It provides an out-of-the-box .gitlab-ci.yml that builds an image and pushes it to registry.isima.fr. Fork it or copy its pipeline, then adapt the Harbor project name and your image name.

Configure Harbor Integration

Access to the registry from GitLab is done via the native Harbor integration. Once configured, GitLab automatically injects the registry credentials into all project pipelines, without having to manually create variables.

Prerequisite: a robot account

Never use your personal CLI secret. First create a dedicated robot account for the project, with strictly necessary permissions (Pull to retrieve, Pull + Push to publish).

  1. In your GitLab project, open Settings > Integrations
  2. Select Harbor
  3. Check Active and fill in:
    • Harbor URL: https://registry.isima.fr
    • Harbor project name: the name of your project (e.g. my-project)
    • Username: the identifier of a robot account (e.g. robot$my-project+gitlab-ci)
    • Password: the secret of the robot account
  4. Click Test settings and save changes

Harbor integration configuration in GitLab

The integration then automatically exposes the following CI/CD variables to your jobs:

Variable Content
$HARBOR_URL Full registry URL (https://registry.isima.fr)
$HARBOR_HOST Registry hostname (registry.isima.fr)
$HARBOR_PROJECT Configured Harbor project name
$HARBOR_USERNAME Identifier (the robot account)
$HARBOR_PASSWORD Associated secret
$HARBOR_OCI OCI URL (oci://registry.isima.fr), useful for Helm charts

Group-level configuration

The integration can be defined once at the group level to be inherited by all its projects. A project-level configuration takes precedence over the group one.

Use a robot account, not your personal account

The credentials entered in the integration are accessible to all project pipelines. Enter a robot account with limited permissions here, and ensure that a malicious .gitlab-ci.yml cannot exfiltrate $HARBOR_PASSWORD (unprotected variable visible in unprotected branches).

Robot permissions for integration

In general, the same robot account is used both for pull/push in the pipeline and to feed the Harbor Registry view (which queries the Harbor API to list the project content). Grant it the following permissions:

Resource → Action Role
Repository → Pull Retrieve images in the pipeline
Repository → Push Push images from the pipeline
Repository → List List repositories in the Harbor Registry view
Artifact → List + Read List and detail artifacts
Tag → List List artifact tags

List/ReadPull/Push

Read actions (List, Read) are distinct from image actions (Pull, Push): a robot capable of pushing images cannot list repositories/artifacts/tags unless the List/Read permissions are explicitly checked. Without them, the Harbor Registry view remains empty.

Scan results not available

The GitLab Harbor integration does not display vulnerability scan results. Therefore, there is no need to grant the robot Scan permissions for this use: these reports are viewed in the registry web interface.

Viewing artifacts from GitLab

Once the integration is active, a Harbor Registry menu (under Deploy / Operate) appears in your GitLab project. It lists the repositories and artifacts of the associated Harbor project, without leaving the GitLab interface.

Harbor Registry view in GitLab

Push an image from a pipeline

Complete example building an image with Docker-in-Docker (dind) and pushing it to the registry, tagged with the commit short SHA then latest. The $HARBOR_* variables come from the Harbor integration:

build-image:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  variables:
    IMAGE: $HARBOR_HOST/$HARBOR_PROJECT/my-app
  before_script:
    - echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin
  script:
    - docker build -t "$IMAGE:$CI_COMMIT_SHORT_SHA" -t "$IMAGE:latest" .
    - docker push "$IMAGE:$CI_COMMIT_SHORT_SHA"
    - docker push "$IMAGE:latest"

Ready-to-use complete pipeline

A working example of this pipeline is available in the cri-public/gitlab-ci-registry-boilerplate repository: fork it to start from a base that already builds and pushes an image to the registry.

Pull an image from a pipeline

In a job with a Docker client, authenticate then perform a pull:

deploy:
  stage: deploy
  image: docker:27
  services:
    - docker:27-dind
  before_script:
    - echo "$HARBOR_PASSWORD" | docker login "$HARBOR_HOST" -u "$HARBOR_USERNAME" --password-stdin
  script:
    - docker pull registry.isima.fr/my-project/my-app:latest
    - docker run --rm registry.isima.fr/my-project/my-app:latest --version

Use a registry image as a job image

GitLab can run a job inside an image from the registry (using the image: key). Prefer using a public image or one from the proxy cache here: no authentication is required, and the proxy cache speeds up download while avoiding rate limits from public registries.

test:
  image: registry.isima.fr/dh/library/node:20
  script:
    - npm ci
    - npm test

Image from a private project

The image used as image: for a job is pulled by the runner before the script runs: the Harbor integration variables are therefore not yet available at this point. To use an image from a private project, do not declare it as image: for the job but retrieve it in the script after authentication (see Pull an image from a pipeline).

Use a registry image as a service

Services (services:) are side containers started alongside the job — typically a database for tests. They can also come from the registry, especially from the proxy cache:

test-with-db:
  image: registry.isima.fr/dh/library/python:3.12
  services:
    - name: registry.isima.fr/dh/library/postgres:16
      alias: db
  variables:
    POSTGRES_DB: testdb
    POSTGRES_USER: runner
    POSTGRES_PASSWORD: secret
    # from the job's perspective, the database is reachable on host « db »
    DATABASE_URL: "postgresql://runner:secret@db:5432/testdb"
  script:
    - pip install -r requirements.txt
    - pytest
  • The alias key defines the hostname by which the job connects to the service (here db).
  • Prefer public service images or ones from the proxy cache: as with the job image, a service is pulled by the runner before the script runs.

Useful GitLab variables

GitLab exposes predefined variables useful for tagging your images:

Variable Description
$CI_COMMIT_SHORT_SHA Commit short SHA (ideal image tag)
$CI_COMMIT_REF_SLUG "Slugified" branch/tag name (usable in an image name)
$CI_COMMIT_TAG Git tag, when a pipeline is triggered by a tag
$CI_PIPELINE_IID Internal project pipeline number