GitLab Backup and Restore Using Velero

This guide demonstrates how to implement GitLab backup and restore operations using Velero, an open-source cloud-native disaster recovery tool.

TOC

Applicability

This solution is applicable to GitLab instances running version 17.8 or later.

TIP

If your GitLab instance is already configured with object storage, we recommend prioritizing the official backup and restore solution.

How to determine if object storage is enabled?

GitLab data comprises three primary components: PostgreSQL database, Git repositories, and uploaded artifacts (including user avatars, comment attachments, etc.). This solution provides backup support for Git repositories and uploaded artifacts only. The PostgreSQL database requires separate backup procedures according to your database service provider's backup strategy.

DANGER

This solution does not support GitLab instances deployed using HostPath storage.

Terminology

TermDefinition
Source InstanceThe GitLab instance before backup
Target InstanceThe GitLab instance after restore
Source NamespaceThe namespace where the source instance is located
Target NamespaceThe namespace where the target instance is located
GitLab CR ResourceDescribes the deployment configuration of GitLab instance, used by the Operator to deploy GitLab instances

Prerequisites

  1. Deploy MinIO Object Storage: The current backup and restore solution relies on object storage to save backup data, requiring a pre-deployed MinIO instance. ACP provides MinIO Object Storage for .
  2. Deploy Velero: Velero is a tool for backup and restore. ACP provides Alauda Container Platform Data Backup for Velero, you can deploy it in the Administrator view, in the Marketplace -> Cluster Plugins page, search for Velero and deploy it.
  3. Install mc Command-Line Tool: mc is MinIO's command-line tool for managing MinIO instances. For installation instructions, refer to the MinIO official documentation.
  4. Install kubectl Command-Line Tool: kubectl is Kubernetes' command-line tool for managing Kubernetes clusters. For installation instructions, refer to the Kubernetes official documentation.

For convenience in subsequent operations, please set the environment variables first:

export MINIO_HOST=<MinIO instance access address> # Example: http://192.168.1.100:32008
export MINIO_ACCESS_KEY=<MinIO instance access key> # Example: minioadmin
export MINIO_SECRET_KEY=<MinIO instance secret key> # Example: minioadminpassword
export MINIO_ALIAS_NAME=<MinIO instance alias name> # Example: myminio

export VELERO_BACKUP_BUCKET=<Velero backup bucket name> # Example: backup
export VELERO_BACKUP_REPO_NAME=<Velero backup repo name> # Example: gitlab-backup-repo

export GITLAB_NAMESPACE=<namespace of the GitLab instance to be backed up>
export GITLAB_NAME=<name of the GitLab instance to be backed up>

Execute the following commands to configure the mc command-line tool and test the connection:

mc alias set ${MINIO_ALIAS_NAME} ${MINIO_HOST} ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY}
mc ping ${MINIO_ALIAS_NAME}

# Output:
#   1: http://192.168.131.56:32571:32571   min=98.86ms    max=98.86ms    average=98.86ms    errors=0   roundtrip=98.86ms
#   2: http://192.168.131.56:32571:32571   min=29.57ms    max=98.86ms    average=64.21ms    errors=0   roundtrip=29.57ms
#   3: http://192.168.131.56:32571:32571   min=29.57ms    max=98.86ms    average=52.77ms    errors=0   roundtrip=29.88ms

If you can successfully ping the MinIO instance, it indicates that mc is configured correctly.

Backup

Preparation

Backup preparation involves two steps:

  1. Create Bucket
  2. Configure Velero backup repository

Create Bucket

Execute the following commands to create a bucket to store backup data:

mc mb ${MINIO_ALIAS_NAME}/${VELERO_BACKUP_BUCKET}

# Output:
# Bucket created successfully `myminio/backup`.

Configure Velero Backup Repository

Execute the following commands to create the Velero backup repository which is used to store backup data:

gitlab_backup_repo_credentials_secret_name="gitlab-backup-repo-credentials"
minio_gitlab_backup_bucket="${VELERO_BACKUP_BUCKET:-backup}"
minio_gitlab_backup_bucket_directory="gitlab"

kubectl apply -f - <<EOF
apiVersion: v1
stringData:
  cloud: |
    [default]
    aws_access_key_id = ${MINIO_ACCESS_KEY}
    aws_secret_access_key = ${MINIO_SECRET_KEY}
kind: Secret
metadata:
  labels:
    component: velero
    cpaas.io/backup-storage-location-repo: ${VELERO_BACKUP_REPO_NAME}
  name: ${gitlab_backup_repo_credentials_secret_name}
  namespace: cpaas-system
type: Opaque
---
apiVersion: velero.io/v1
kind: BackupStorageLocation
metadata:
  name: ${VELERO_BACKUP_REPO_NAME}
  namespace: cpaas-system
spec:
  config:
    checksumAlgorithm: ""
    insecureSkipTLSVerify: "true"
    region: minio
    s3ForcePathStyle: "true"
    s3Url: ${MINIO_HOST}
  credential:
    key: cloud
    name: ${gitlab_backup_repo_credentials_secret_name}
  objectStorage:
    bucket: ${minio_gitlab_backup_bucket}
    prefix: ${minio_gitlab_backup_bucket_directory}
  provider: aws
EOF

# Output
# secret/gitlab-backup-repo-credentials created
# backupstoragelocationrepo.ait.velero.io/gitlab-backup-repo created

Execute Backup

Manual backup consists of six steps:

  1. Label resources for backup
  2. Stop GitLab services
  3. Create backup pod
  4. Create backup schedule
  5. Execute backup
  6. Restore GitLab services

Label Resources for Backup

Execute the following script:

if [ -z "${GITLAB_NAMESPACE}" ] || [ -z "${GITLAB_NAME}" ]; then
    cat <<EOF
    Please set the correct namespace and instance name:
    export GITLAB_NAME=<original GitLab instance name>
    export GITLAB_NAMESPACE=<original namespace name>
EOF
    return
fi

kubectl label gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} release=${GITLAB_NAME} --overwrite

secrets_to_label=()

root_password_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.initialRootPassword.secret}')
secrets_to_label+=(${root_password_secret_name})

rails_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.railsSecrets.secret}')
if [ -n "${rails_secret_name}" ]; then
    echo "Found rails secret: ${rails_secret_name}"
    secrets_to_label+=(${rails_secret_name})
fi

pg_connect_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.psql.password.secret}')
secrets_to_label+=(${pg_connect_secret_name})

ingress_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.ingress.tls.secretName}')
if [ -n "${ingress_secret_name}" ]; then
    echo "Found ingress secret: ${ingress_secret_name}"
    secrets_to_label+=(${ingress_secret_name})
fi

redis_connect_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.redis.auth.secret}')
if [ -n "${redis_connect_secret_name}" ]; then
    echo "Found redis auth secret: ${redis_connect_secret_name}"
    secrets_to_label+=(${redis_connect_secret_name})
fi

redis_sentinel_connect_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.redis.sentinelAuth.secret}')
if [ -n "${redis_sentinel_connect_secret_name}" ]; then
    echo "Found redis sentinel connect secret: ${redis_sentinel_connect_secret_name}"
    secrets_to_label+=(${redis_sentinel_connect_secret_name})
fi

object_store_secret_name=$(kubectl get gitlabofficial -n ${GITLAB_NAMESPACE} ${GITLAB_NAME} -o jsonpath='{.spec.helmValues.global.appConfig.object_store.connection.secret}')
if [ -n "${object_store_secret_name}" ]; then
    echo "Found object storage connect secret: ${object_store_secret_name}"
    kubectl label secret ${object_store_secret_name} -n ${GITLAB_NAMESPACE} release=${GITLAB_NAME}
fi

for secret_name in "${secrets_to_label[@]}"; do
  echo "Add label to secret: ${secret_name}"
  kubectl label secret ${secret_name} -n ${GITLAB_NAMESPACE} release=${GITLAB_NAME} --overwrite
done

kubectl get pvc -n ${GITLAB_NAMESPACE} --no-headers | grep ${GITLAB_NAME} | awk '{print $1}' | xargs -I {} kubectl label pvc {} release=${GITLAB_NAME} -n ${GITLAB_NAMESPACE}

kubectl get secret -n ${GITLAB_NAMESPACE} --no-headers | grep ${GITLAB_NAME} | awk '{print $1}' | xargs -I {} kubectl label secret {} release=${GITLAB_NAME} -n ${GITLAB_NAMESPACE}

# Output:
# secret/sh.helm.release.v1.xxx-gitlab.v9 not labeled

If additional resources need to be backed up, refer to the Label Additional Resources for Backup section.

Stop GitLab Services

All GitLab components must be stopped during backup:

kubectl annotate statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync="true"
kubectl scale statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=0

kubectl annotate deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync="true"
kubectl scale deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=0

kubectl delete pod -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --ignore-not-found

# Output:
# statefulset.apps/xxxx-gitlab-gitaly annotated
# deployment.apps/xxxx-gitlab-webservice-default annotated
# deployment.apps/xxxx-gitlab-toolbox scaled
# deployment.apps/xxxx-gitlab-webservice-default scaled

Create Backup Pod

This step creates a pod that mounts GitLab's PVCs to enable Velero to complete PVC data backup.

image=''

if [ -z "${IMAGE}" ]; then
  image=$(kubectl get deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME},app=gitlab-shell -o jsonpath='{range .items[0].spec.template.spec.containers[]}{.image}{"\n"}{end}' | head -n1)
fi

PVC_NAMES=($(kubectl get pvc -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} -o jsonpath='{range .items[*]}{.metadata.name}{" "}{end}'))

VOLUME_MOUNTS=""
VOLUMES=""
INDEX=0
for pvc in ${PVC_NAMES[@]}; do
  VOLUME_MOUNTS="${VOLUME_MOUNTS}
        - name: data-${INDEX}
          mountPath: /mnt/data-${INDEX}"
  VOLUMES="${VOLUMES}
    - name: data-${INDEX}
      persistentVolumeClaim:
        claimName: ${pvc}"
  INDEX=$((INDEX+1))
done

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: ${GITLAB_NAME}-backup-pod
  namespace: ${GITLAB_NAMESPACE}
  labels:
    release: ${GITLAB_NAME}
spec:
  containers:
    - name: backup
      image: ${image}
      command: ["/bin/sh", "-c", "sleep 86400"]
      resources:
        limits:
          cpu: 1
          memory: 1Gi
      volumeMounts:${VOLUME_MOUNTS}
  volumes:${VOLUMES}
  restartPolicy: Never
EOF

kubectl wait --for=condition=ready pod -n ${GITLAB_NAMESPACE} ${GITLAB_NAME}-backup-pod

# Output
# pod/xxxx-gitlab-backup-pod created
# pod/xxxx-gitlab-backup-pod condition met

Create Backup Volume Policy

Volume policy is used to specify the backup method for PVCs. The default policy is to backup PVCs using the fs-backup method.

export BACKUP_POLICY_NAME=${BACKUP_POLICY_NAME:-gitlab-backup}
export VELERO_BACKUP_REPO_NAME=${VELERO_BACKUP_REPO_NAME:-backup}

kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: ${BACKUP_POLICY_NAME}-volume-policy
  namespace: cpaas-system
data:
  resourcepolicies: |
    version: v1
    volumePolicies:
      - conditions:
          csi: {}
        action:
          type: fs-backup
      - conditions:
          csi: {}
        action:
          type: fs-backup
EOF

# Output
# configmap/gitlab-backup-volume-policy created

If the PVC supports snapshot, you can use snapshot to backup pvc to speed up backup. You need to modify the volume policy configmap to specify that the storage class uses snapshot for backup. For example, if the ceph storage class supports snapshot backup, you need to add the following configuration (the added condition should be placed at the top to get higher priority):

How to determine if the PVC supports snapshot?

WARNING

If you use pvc snapshot backup, you cannot change the storage class when restoring. Please adjust the storage class according to the actual situation.

apiVersion: v1
kind: ConfigMap
metadata:
  name: ${BACKUP_POLICY_NAME}-volume-policy
  namespace: cpaas-system
data:
  resourcepolicies: |
    version: v1
    volumePolicies:
+      - conditions:
+          storageClass:
+            - ceph
+        action:
+          type: snapshot
      - conditions:
          csi: {}
        action:
          type: fs-backup
      - conditions:
          csi: {}
        action:
          type: fs-backup
WARNING

If the velero is not enabled CSI snapshot, you will get the following error when backup:

Skip action velero.io/csi-pvc-backupper for resource persistentvolumeclaims:xxx, because the CSI feature is not enabled.

To fix this, you need to add --features=EnableCSI parameter to the velero deployment.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: velero
spec:
  template:
    spec:
      containers:
      - args:
        - server
        - --uploader-type=restic
+        - --features=EnableCSI
        - --namespace=cpaas-system
        command:
        - /velero
        name: velero

Execute Backup

Execute the following command to create a backup schedule and trigger a backup job:

export BACKUP_POLICY_NAME=${BACKUP_POLICY_NAME:-gitlab-backup}
export VELERO_BACKUP_REPO_NAME=${VELERO_BACKUP_REPO_NAME:-backup}

kubectl apply -f - <<EOF
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: ${BACKUP_POLICY_NAME}
  namespace: cpaas-system
spec:
  schedule: '@every 876000h'
  template:
    defaultVolumesToFsBackup: true
    hooks: {}
    includedNamespaces:
    - ${GITLAB_NAMESPACE}
    includedResources:
    - '*'
    resourcePolicy:
      kind: configmap
      name: ${BACKUP_POLICY_NAME}-volume-policy
    orLabelSelectors:
    - matchLabels:
        release: ${GITLAB_NAME}
    storageLocation: ${VELERO_BACKUP_REPO_NAME}
    ttl: 720h0m0s
EOF

kubectl create -f - <<EOF
apiVersion: velero.io/v1
kind: Backup
metadata:
  labels:
    velero.io/schedule-name: ${BACKUP_POLICY_NAME}
    velero.io/storage-location: ${VELERO_BACKUP_REPO_NAME}
  generateName: ${BACKUP_POLICY_NAME}-
  namespace: cpaas-system
spec:
  csiSnapshotTimeout: 10m0s
  defaultVolumesToFsBackup: true
  includedNamespaces:
    - ${GITLAB_NAMESPACE}
  includedResources:
    - "*"
  itemOperationTimeout: 4h0m0s
  resourcePolicy:
    kind: configmap
    name: ${BACKUP_POLICY_NAME}-volume-policy
  orLabelSelectors:
    - matchLabels:
        release: ${GITLAB_NAME}
  snapshotMoveData: false
  storageLocation: ${VELERO_BACKUP_REPO_NAME}
  ttl: 720h0m0s
EOF

# Output
# schedule.velero.io/gitlab-backup created
# backup.velero.io/gitlab-backup-r6hht created

View backup logs:

kubectl logs -f -n cpaas-system -l app.kubernetes.io/instance=velero | grep gitlab-backup

# Output
# time="2025-07-01T07:29:54Z" level=info msg="PodVolumeBackup completed" controller=PodVolumeBackup logSource="pkg/controller/pod_volume_backup_controller.go:244" pvb=gitlab-backup-xxx-q7prc

Check task progress. If status is Completed, the backup was successful.

kubectl get backup -n cpaas-system -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.phase}{'\t'}{.status.startTimestamp}{'\n'}{end}"

# Output
# Completed

Restore GitLab Services

Delete the backup pod and restore all GitLab components.

kubectl delete pod -n ${GITLAB_NAMESPACE} ${GITLAB_NAME}-backup-pod

kubectl annotate statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync-
kubectl scale statefulset -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=1

kubectl annotate deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} skip-sync-
kubectl scale deployment -n ${GITLAB_NAMESPACE} -l release=${GITLAB_NAME} --replicas=1

After all components are restored, access the GitLab instance to ensure it is functioning normally.

Restore

Preparation

Restore preparation involves four steps:

  1. Restore PostgreSQL Database (Optional)
  2. Select a backup to restore
  3. Determine target namespace for restoration
  4. Uninstall Gitlab CE Operator

Restore PostgreSQL Database (Optional)

If the new instance will still use the same PostgreSQL instance and database, there's no need to restore the PostgreSQL database.

If the new instance will use a different PostgreSQL instance or database than the old instance, you need to restore the PostgreSQL database first. Refer to your PostgreSQL service provider's backup and restore documentation.

Select Backup Data to Restore

Execute the following command to view the list of successful backup records and select the desired backup based on start time.

kubectl get backup -n cpaas-system -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.phase}{'\t'}{.status.startTimestamp}{'\n'}{end}" | grep Completed

# Output:
# gitlab-backup-xxx     Completed       2025-07-01T07:29:19Z

Set the BACKUP_NAME environment variable:

export BACKUP_NAME=<selected backup record name>

Determine Target Namespace

We recommend restoring the instance to a new namespace. Set the following environment variables:

export NEW_GITLAB_NAMESPACE=<new namespace name>
kubectl create namespace ${NEW_GITLAB_NAMESPACE}

Uninstall Gitlab CE Operator

Execute the following command to uninstall the GitLab CE Operator:

kubectl get subscription --all-namespaces | grep gitlab-ce-operator | awk '{print "kubectl delete subscription "$2" -n "$1}' | sh

# Output:
# subscription.operators.coreos.com "gitlab-ce-operator" deleted
Why uninstall the GitLab operator?

During restoration, Velero needs to start backup pods to restore data in PVCs, which takes some time. If the operator is not uninstalled during restoration, the following issues may occur:

  1. The operator may recreate workload resources based on the GitLab CR, causing restored pods to restart or be recreated, ultimately leading to restoration interruption or failure.
  2. Some restored resources may conflict, such as ingress resources created by the operator based on the restored GitLab CR conflicting with the old instance's ingress resources.
Impact of Uninstalling Gitlab CE Operator

If the operator is uninstalled, modifications to the GitLab CR resource will not take effect, such as adjusting resources or storage size.

Uninstalling the operator will not cause existing instances to malfunction.

Restore Operations

Restore operations consist of five steps:

  1. Create restore configuration file
  2. Create restore task
  3. Clean up resources
  4. Modify GitLab CR resource
  5. Deploy Gitlab CE Operator

Create Restore Configuration File

Carefully read the comments in the YAML and make modifications according to your actual situation (such as changing storage class), then create the modified YAML.

# If you need to change storage class, set the following two environment variables
OLD_STORAGECLASS_NAME='' # Original storage class name
NEW_STORAGECLASS_NAME='' # New storage class name

if [ -n "${OLD_STORAGECLASS_NAME}" ] && [ -n "${NEW_STORAGECLASS_NAME}" ] && [ ${NEW_STORAGECLASS_NAME} != ${OLD_STORAGECLASS_NAME} ]; then
kubectl apply -f - <<EOF
apiVersion: v1
data:
  resourcemodifier: |
    version: v1
    resourceModifierRules:
      - conditions:
          groupResource: persistentvolumeclaims
          resourceNameRegex: .*
          namespaces:
            - "*"
        patches: &a1
          - operation: test
            path: /spec/storageClassName
            value: ${OLD_STORAGECLASS_NAME}
          - operation: replace
            path: /spec/storageClassName
            value: ${NEW_STORAGECLASS_NAME}
      - conditions:
          groupResource: persistentvolume
          resourceNameRegex: .*
          namespaces:
            - "*"
        patches: *a1
      - conditions:
          groupResource: persistentvolumeclaims
          resourceNameRegex: .*
          namespaces:
            - "*"
        patches:
          - operation: test
            path: "/metadata/annotations/meta.helm.sh~1release-namespace"
            value: ${GITLAB_NAMESPACE}
          - operation: replace
            path: "/metadata/annotations/meta.helm.sh~1release-namespace"
            value: ${NEW_GITLAB_NAMESPACE}
kind: ConfigMap
metadata:
  labels:
    component: velero
  name: gitlab-restore-modifier
  namespace: cpaas-system
EOF

else

kubectl apply -f - <<EOF
apiVersion: v1
data:
  resourcemodifier: |
    version: v1
    resourceModifierRules:
      - conditions:
          groupResource: persistentvolumeclaims
          resourceNameRegex: .*
          namespaces:
            - "*"
        patches:
          - operation: test
            path: "/metadata/annotations/meta.helm.sh~1release-namespace"
            value: ${GITLAB_NAMESPACE}
          - operation: replace
            path: "/metadata/annotations/meta.helm.sh~1release-namespace"
            value: ${NEW_GITLAB_NAMESPACE}
kind: ConfigMap
metadata:
  labels:
    component: velero
  name: gitlab-restore-modifier
  namespace: cpaas-system
EOF
fi

Create Restore Task

Execute the following command to create the restore task:

kubectl create -f - <<EOF
apiVersion: velero.io/v1
kind: Restore
metadata:
  generateName: ${GITLAB_NAME}-restore-
  namespace: cpaas-system
spec:
  backupName: ${BACKUP_NAME}
  hooks: {}
  includedNamespaces:
    - ${GITLAB_NAMESPACE}
  includedResources:
    - persistentvolumeclaims
    - persistentvolumes
    - secrets
    - pods
    - gitlabofficials.operator.alaudadevops.io
    - volumesnapshots
    - volumesnapshotcontents
  itemOperationTimeout: 10h0m0s
  namespaceMapping:
    ${GITLAB_NAMESPACE}: ${NEW_GITLAB_NAMESPACE}
  resourceModifier:
    kind: configmap
    name: gitlab-restore-modifier
EOF

View restore logs:

kubectl logs -f -n cpaas-system -l app.kubernetes.io/instance=velero | grep gitlab-restore

# Output
# time="2025-07-01T08:01:41Z" level=info msg="Async fs restore data path completed" PVR=xxxx-gitlab-restore-mv6l5-sc4pk controller=PodVolumeRestore logSource="pkg/controller/pod_volume_restore_controller.go:275" pvr=xxxx-gitlab-restore-mv6l5-sc4pk
# time="2025-07-01T08:01:41Z" level=info msg="Restore completed" controller=PodVolumeRestore logSource="pkg/controller/pod_volume_restore_controller.go:327" pvr=xxxx-gitlab-restore-mv6l5-sc4pk

Check task progress. If status is Completed, the restore was successful.

kubectl get restore -n cpaas-system -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.phase}{'\t'}{.status.startTimestamp}{'\n'}{end}"


# Output
# xxx-gitlab-restore-xxx    InProgress      2025-07-01T10:18:17Z

Clean Up Resources

Ensure the restore operation is complete before proceeding!

Execute the following commands to complete resource cleanup.

kubectl get pod -n ${NEW_GITLAB_NAMESPACE} | grep ${GITLAB_NAME} | awk '{print $1}' | xargs kubectl delete pod -n ${NEW_GITLAB_NAMESPACE}

kubectl get secret -n ${NEW_GITLAB_NAMESPACE} | grep sh.helm.release.v1.${GITLAB_NAME} | awk '{print $1}' | xargs kubectl delete secret -n ${NEW_GITLAB_NAMESPACE}

Modify GitLab CR Resource

kubectl edit gitlabofficial ${GITLAB_NAME} -n ${NEW_GITLAB_NAMESPACE}

The new instance CR resource may need the following modifications. Please make changes according to your actual situation.

  1. Domain Name:
    • Applicable scenario: Original instance was deployed via domain name
    • Why modify: Identical domain names in ingress resources created by old and new instances will cause conflicts, leading to failure in creating the new instance's ingress resources
    • Modification recommendations:
      • (Recommended) Change the original instance's domain to a temporary domain, leave the new instance unchanged
      • Keep the original instance's domain unchanged, change the new instance's domain to a new one
    • How to modify: Please refer to Configure Instance Network Access to modify the instance access domain name.
  2. NodePort:
    • Applicable scenario: Original instance was deployed via NodePort
    • Why modify: Identical NodePorts in service resources created by old and new instances will cause conflicts, leading to failure in creating the new instance's service resources
    • Modification recommendations:
      • (Recommended) Change the original instance's NodePort to a temporary port, leave the new instance unchanged
      • Keep the original instance's NodePort unchanged, change the new instance's NodePort to a new port
    • How to modify: Please refer to Configure Instance Network Access to modify the instance access configuration.
  3. Storage Class:
    • Applicable scenario: Original instance was deployed with storage class and there's a change in storage class between old and new instances (e.g., original used NFS, new uses Ceph)
    • Why modify: If not modified, the operator will still use the old storage class to create PVCs, which will conflict with the restored PVCs
    • Modification recommendation: Change the storage class to the correct value
    • How to modify: Please refer to Configure Instance Storage to modify the instance storage configuration.
  4. PostgreSQL Connection Information:
    • Applicable scenario: New instance and old instance plans to use different PostgreSQL instances or databases
    • Why modify: If not modified, the new instance will still connect to the old PostgreSQL instance or database
    • Modification recommendation: Change the PostgreSQL connection information to the correct values
    • How to modify: Please refer to Configure PostgreSQL Access Credential Configuration to modify the PostgreSQL access credential configuration.

Deploy Gitlab CE Operator

Navigate to the Administrator view, go to Marketplace -> OperatorHub page and redeploy the Alauda Build of Gitlab operator.

After deploying the Operator, operator will deploy the new instance according to the GitLab CR. You can view the instance deployment progress in instance detail page.

After waiting for the instance status to return to normal, login to GitLab to check if the data has been restored successfully. Check items include but are not limited to:

  • Groups
  • Repositories
  • Users
  • Merge Requests

Q & A

Label Additional Resources for Backup

This step is optional. If you have other resources in the same namespace that you want to backup together, you can add a release label to the corresponding resources. The label value should be the original GitLab instance name, for example:

metadata:
  labels:
    release: gitlab-g6zd4

How to determine if the PVC supports snapshot?

To determine whether a PVC supports snapshot, you need to check if its underlying StorageClass supports snapshot functionality. A PVC supports snapshot if there is a VolumeSnapshotClass in the cluster whose driver matches the StorageClass's provisioner. If such a VolumeSnapshotClass exists, the StorageClass (and therefore the PVC) supports snapshot functionality.

Example Configuration:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ceph
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
  clusterID: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  fsName: cephfs
  pool: cephfs-data0
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-cephfs-snapshotclass
deletionPolicy: Delete
driver: rook-ceph.cephfs.csi.ceph.com
parameters:
  clusterID: rook-ceph
  csi.storage.k8s.io/snapshotter-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/snapshotter-secret-namespace: rook-ceph

Key Points:

  • StorageClass provisioner must exactly match VolumeSnapshotClass driver
  • Both resources must exist in the cluster
  • The CSI driver must support snapshot operations