Install the GitLab Operator in a disconnected OpenShift cluster

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab Self-Managed

Install the GitLab Operator and GitLab on an OpenShift cluster that cannot reach public container registries by using the manifest or Helm installation method.

  1. Copy the container images to a registry inside your network.
  2. Configure the cluster to pull from that registry.

Installation with the Operator Lifecycle Manager (OLM) is experimental and is not covered by this page.

Before you begin

Before you install the GitLab Operator in a disconnected OpenShift cluster, you need:

  • An OpenShift cluster at a supported version.
  • A container registry that the cluster nodes can reach, referred to here as <mirror_registry>. The cluster must trust its TLS certificate.
  • A host with internet access and the oc, oc-mirror, and helm command-line tools. If the host cannot reach <mirror_registry>, you also need a host inside your network with the same tools. Use the oc-mirror plugin v2 to copy the container images to <mirror_registry>.
  • The other installation prerequisites, such as cert-manager. Their container images must be available to the cluster too. OpenShift Routes need no separate Ingress or Gateway API controller.
  • Credentials for <mirror_registry> in the global cluster pull secret, if the registry requires authentication.

To make the cluster trust the registry certificate, add the certificate authority (CA) to the cluster image configuration. Use the registry host name as the key. For a registry on a port other than 443, write the key as <host>..<port>. For more information, see configuring additional trust stores for image registry access.

shell
oc create configmap mirror-registry-ca \
  --namespace openshift-config \
  --from-file=<registry_host>=ca.crt

oc patch image.config.openshift.io/cluster --type merge \
  --patch '{"spec":{"additionalTrustedCA":{"name":"mirror-registry-ca"}}}'

Choose how to redirect container image pulls

The cluster must pull each container image from <mirror_registry> instead of its public registry. You can redirect pulls in two ways:

  • Use an ImageTagMirrorSet. The cluster nodes rewrite the container image names. You change nothing in the GitLab Operator or the GitLab custom resource (CR). This method is the same for the manifest and Helm installation methods.
  • Set the container image locations in values. You change the GitLab Operator container image, in the manifest or in the Helm values, and every container image value of the GitLab CR.

Mirror the container images

The GitLab Operator and the GitLab chart pull container images from registry.gitlab.com. The charts pull container images by tag, so an ImageDigestMirrorSet alone does not redirect them.

  1. Find the GitLab Operator version and the chart version. The chart version is spec.chart.version in your GitLab CR. It is one of the versions in the CHART_VERSIONS file of the GitLab Operator release. The GitLab Operator container image tag is the GitLab Operator version.

  2. List the container images the chart needs. Save the content of spec.chart.values from your GitLab CR in values.yaml, with the values from Install GitLab.

    Render the chart, as the custom images page describes:

    shell
    helm repo add gitlab https://charts.gitlab.io
    helm template gitlab gitlab/gitlab --version <chart_version> --values values.yaml \
      | grep 'image:' | tr -d '[:blank:]"' | sort --unique

    The list can include container images that the GitLab Operator does not deploy. The GitLab Operator does not use the chart’s cert-manager or Envoy Gateway. Leave out the quay.io/jetstack and docker.io/envoyproxy container images.

  3. Create an imageset-config.yaml file with the GitLab Operator container image and every container image from the previous step. Copy each tag from the helm template output. Some container images do not use the GitLab version as their tag.

    This example fits a CR with the container registry, GitLab Exporter, and the agent server for Kubernetes (KAS). It also uses the chart’s self-signed certificate. A CR that turns these off needs fewer container images:

    yaml
    kind: ImageSetConfiguration
    apiVersion: mirror.openshift.io/v2alpha1
    mirror:
      additionalImages:
      - name: registry.gitlab.com/gitlab-org/cloud-native/gitlab-operator:<operator_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/certificates:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/cfssl-self-sign:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitaly:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-base:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-container-registry:<registry_tag>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-exporter:<exporter_tag>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-kas:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-shell:<gitlab_shell_tag>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-sidekiq-ee:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-toolbox-ee:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-webservice-ee:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/gitlab-workhorse-ee:v<gitlab_version>
      - name: registry.gitlab.com/gitlab-org/build/cng/kubectl:v<gitlab_version>
  4. Copy the container images to your registry:

    shell
    oc-mirror --v2 --config imageset-config.yaml \
      --workspace file://<workspace_dir> docker://<mirror_registry>

    oc-mirror keeps the repository paths. For example, the GitLab Operator container image becomes <mirror_registry>/gitlab-org/cloud-native/gitlab-operator:<operator_version>. It also writes an ImageTagMirrorSet to <workspace_dir>/working-dir/cluster-resources/itms-oc-mirror.yaml.

    If no host can reach both the internet and <mirror_registry>, mirror through a disk instead. On the host with internet access, write the container images to a directory:

    shell
    oc-mirror --v2 --config imageset-config.yaml file://<archive_dir>

    Copy the directory to a host that can reach <mirror_registry>, and run:

    shell
    oc-mirror --v2 --config imageset-config.yaml \
      --from file://<archive_dir> docker://<mirror_registry>

    The ImageTagMirrorSet is then at <archive_dir>/working-dir/cluster-resources/itms-oc-mirror.yaml. For more information, see mirroring an image set in a fully disconnected environment.

Add the container images of other prerequisites, such as cert-manager or an object storage server, to the same image set.

Redirect pulls with an ImageTagMirrorSet

The ImageTagMirrorSet that oc-mirror generates maps each public repository to its mirror:

yaml
apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
  name: itms-generic-0
spec:
  imageTagMirrors:
  - mirrors:
    - <mirror_registry>/gitlab-org/build/cng
    source: registry.gitlab.com/gitlab-org/build/cng
  - mirrors:
    - <mirror_registry>/gitlab-org/cloud-native
    source: registry.gitlab.com/gitlab-org/cloud-native

For more information, see image registry repository mirroring.

  1. Apply the ImageTagMirrorSet. If you mirrored directly, use the file in <workspace_dir>:

    shell
    oc apply -f <workspace_dir>/working-dir/cluster-resources/itms-oc-mirror.yaml

    If you mirrored through a disk, use the file in <archive_dir>:

    shell
    oc apply -f <archive_dir>/working-dir/cluster-resources/itms-oc-mirror.yaml
  2. Wait for the MachineConfigPool resources to finish updating. The UPDATED column must read True.

    shell
    oc get machineconfigpool

    OpenShift drains each node to apply the ImageTagMirrorSet, and can reboot it. Plan for the pods on each node to be evicted and rescheduled.

Then install the GitLab Operator and GitLab.

An ImageDigestMirrorSet redirects only pulls that name a digest. It does not redirect pulls that name a tag. Add one only for container images that you reference by digest. For example, add one when you install the GitLab Operator Helm chart with --set image.digest=<digest>.

Install the GitLab Operator

  1. On the host with internet access, download the release manifest. Copy it to a host that can reach the cluster:

    shell
    curl --fail --location --remote-name \
      https://gitlab.com/api/v4/projects/18899486/packages/generic/gitlab-operator/<operator_version>/gitlab-operator-openshift-<operator_version>.yaml
  2. Create the namespace, and apply the manifest:

    shell
    oc create namespace gitlab-system
    oc apply -f gitlab-operator-openshift-<operator_version>.yaml
  1. On the host with internet access, download the chart. Copy it to a host that can reach the cluster:

    shell
    helm pull oci://registry.gitlab.com/charts/charts.gitlab.io/release/gitlab-operator \
      --version <operator_version>
  2. Install the chart from the file:

    shell
    helm install gitlab-operator ./gitlab-operator-<operator_version>.tgz \
      --create-namespace \
      --namespace gitlab-system

Confirm that the GitLab Operator is running:

shell
oc --namespace gitlab-system rollout status deployment/gitlab-controller-manager

Install GitLab

Create the GitLab CR as described in Installing GitLab. The ImageTagMirrorSet needs no setting in the CR.

The example CR requests certificates from Let’s Encrypt, which a disconnected cluster cannot reach. In GitLab 19.0 and later, the GitLab chart also uses Gateway API and creates no Ingress by default. To serve GitLab through OpenShift Routes with a self-signed certificate, set these values in the CR:

yaml
spec:
  chart:
    values:
      global:
        ingress:
          enabled: true
          class: none
          configureCertmanager: false
          annotations:
            route.openshift.io/termination: "edge"
        gatewayApi:
          enabled: false

OpenShift creates Routes from the Ingress objects that the chart renders. Set global.hosts.domain to the cluster apps domain, or to a domain that resolves to the OpenShift router. Routes do not support Git over SSH. For more information, see OpenShift Routes.

The chart generates a self-signed wildcard certificate, which browsers and Git clients do not trust. To use a certificate from your own certificate authority, see use your own wildcard certificate. The GitLab Operator still creates a cert-manager Issuer for Let’s Encrypt. Its status stays False, and GitLab does not use it.

Apply the CR:

shell
oc --namespace gitlab-system apply -f mygitlab.yaml
oc --namespace gitlab-system get gitlab

When the status is Running, the instance is ready.

Redirect pulls with container image values

Use this method when you cannot create an ImageTagMirrorSet. Mirror the container images as described in Mirror the container images, and do not apply the ImageTagMirrorSet.

Set the GitLab Operator container image

  1. Download the release manifest as described in Install the GitLab Operator. The manifest names the GitLab Operator container image in its Deployment. Change the registry to <mirror_registry> before you apply the manifest:

    shell
    sed -i.bak \
      's|registry.gitlab.com/gitlab-org/cloud-native/gitlab-operator:|<mirror_registry>/gitlab-org/cloud-native/gitlab-operator:|' \
      gitlab-operator-openshift-<operator_version>.yaml
  2. Confirm that the manifest names one container image, and that it points to <mirror_registry>:

    shell
    grep 'image:' gitlab-operator-openshift-<operator_version>.yaml
  3. Create the namespace, and apply the manifest:

    shell
    oc create namespace gitlab-system
    oc apply -f gitlab-operator-openshift-<operator_version>.yaml

Download the GitLab Operator chart as described in Install the GitLab Operator. Install it, and set its container image registry to <mirror_registry>:

shell
helm install gitlab-operator ./gitlab-operator-<operator_version>.tgz \
  --create-namespace \
  --namespace gitlab-system \
  --set image.registry=<mirror_registry>

Confirm that the GitLab Operator is running, as described in Install the GitLab Operator.

Set the GitLab container image values

  1. In the GitLab CR, set the repository of every container image the chart renders. The global.image.registry value alone is not enough, because it applies only to the Mailroom chart. Pods that use other container images still pull from registry.gitlab.com.

    This example shows the pattern for the global container images, Gitaly, and Webservice:

    yaml
    spec:
      chart:
        values:
          global:
            kubectl:
              image:
                repository: <mirror_registry>/gitlab-org/build/cng/kubectl
            certificates:
              image:
                repository: <mirror_registry>/gitlab-org/build/cng/certificates
            gitlabBase:
              image:
                repository: <mirror_registry>/gitlab-org/build/cng/gitlab-base
          gitlab:
            gitaly:
              image:
                repository: <mirror_registry>/gitlab-org/build/cng/gitaly
              init:
                image:
                  repository: <mirror_registry>/gitlab-org/build/cng/gitlab-base
            webservice:
              image:
                repository: <mirror_registry>/gitlab-org/build/cng/gitlab-webservice-ee
              init:
                image:
                  repository: <mirror_registry>/gitlab-org/build/cng/gitlab-base
              workhorse:
                image: <mirror_registry>/gitlab-org/build/cng/gitlab-workhorse-ee

    Repeat the pattern for the other charts that render container images, such as gitlab-shell, migrations, and sidekiq. The example values file lists the keys. The self-signed certificate also needs shared-secrets.selfsign.image.repository.

  2. In the same CR, set the values from Install GitLab. Render the chart again, and confirm that no container image still points to registry.gitlab.com. Then apply the CR.

Check that the cluster pulls from the mirror

The pod specifications keep the original container image names when you use an ImageTagMirrorSet. To confirm the redirect, check the access log of your mirror registry for requests to the mirrored repositories.

To list the pulls the cluster has made, run:

shell
oc --namespace gitlab-system get events --field-selector reason=Pulled

Fix container image pull errors

A pod that cannot pull a container image shows ImagePullBackOff. The event names the container image and the registry that the node could not reach:

shell
oc --namespace gitlab-system get events --field-selector reason=Failed
Failed to pull image "registry.gitlab.com/gitlab-org/cloud-native/gitlab-operator:<operator_version>":
unable to pull image: initializing source docker://registry.gitlab.com/...: pinging container registry
registry.gitlab.com: ...

If the event names a public registry, the mirror lacks the container image or no mirror set covers it. Add the container image to the image set, run oc-mirror again, and check the ImageTagMirrorSet.