Skip to main content

Backup GitLab with IBC S6 and IonFS CLI

· 11 min read
Josh Fraser
info

Prerequisites - before you begin, please ensure:

Please also note:

  • This tutorial is based on a GitLab instance installed using the Omnibus deployment method, on Rocky Linux 8.6 - other deployment types may require additional steps.

Overview

The self-hosted version of GitLab is a popular tool for privacy-conscious developers, open-source projects, and organisations looking to keep full control of their source code (like us!).

As an organisation operating a GitLab instance internally, one of our key considerations is ensuring we store our GitLab backups in a secure manner. While GitLab provides a suite of functionality allowing backups to be stored on Cloud object storage, we were keen to protect backups of the underlying Ionburst Cloud source code with Ionburst Cloud, while also minimising our configuration overhead.

In this tutorial, we will be covering how to use IBC S6 secure object storage and IonFS CLI, to backup self-hosted GitLab instances.

Shared Responsibility Model Breakdown

Customer Responsibility

  • You, the customer, are responsible for the secure management of the Ionburst Cloud credentials used by ionfs.
  • You, the customer, are responsible for the security of ionfs metadata repositories and the metadata stored in them.
  • You, the customer, are responsible for the security of the GitLab application and underlying instance.

Ionburst Cloud Responsibility

  • We are responsible for the security of GitLab backup data stored in IBC S6 using ionfs.
  • We are responsible for the underlying security and availability of the Ionburst Cloud platform.

GitLab backups

When backing up a GitLab instance, there are two main data sources to consider:

  • the application data - database, repositories etc.
  • the configuration and secrets data - stored within /etc/gitlab

GitLab application backups are typically performed with the gitlab-backup tool. Assuming no additional backup options have been added to the GitLab configuration file, this tool creates a tar archive of all GitLab application data and saves it in a well-known directory: /var/opt/gitlab/backups/.

Depending on how the GitLab instance is used, this archive can end up extremely large (10s of GB), typically when CI/CD build artifacts and the container registry are included. The GitLab backup tool allows aspects of the GitLab application to be skipped when backing up, using the SKIP environment variable. To minimise the amount of data stored, this tutorial will skip the artifacts stage.

By default, the GitLab backup process automatically generates a filename for the backup archive using the current timestamp and version of GitLab installed. This generated filename allows GitLab to automatically manage backup archives stored locally.

However, as we will be transferring the backups to IBC S6, and to make the automation process easier, we will override this automatic name using the BACKUP environment variable.

Getting started

To begin, we need a user account setup on the underlying operating system of the GitLab instance, with sudo access - it is not recommended to use the root account.

IonFS CLI will also need to be installed on the GitLab instance, and configured with an IBC S6 data repository and Ionburst credentials file. For the purposes of this tutorial, we will use a local metadata repository stored in our user account's home directory.

Our sample ionfs configuration file:

{
"IonFS": {
"MaxSize": "50000000",
"Verbose": "false",
"DefaultClassification": "Restricted",
"Repositories": [
{
"Name": "gitlab-local",
"Usage": "Data",
"Class": "Ionburst.Apps.IonFS.Repo.LocalFS.MetadataLocalFS",
"Assembly": "Ionburst.Apps.IonFS.Repo.LocalFS",
"DataStore": "/home/josh/gitlab-local"
}
],
"DefaultRepository": "gitlab-local"
},
"Ionburst": {
"Profile": "gitlab",
"IonburstUri": "https://api.eu-west-1.ionburst.cloud/",
"TraceCredentialsFile": "OFF"
}
}

We can verify the IonFS configuration with:

ionfs repos

Which should return something similar to:

[josh@gitlab-example ~]$ ionfs repos
____ ___________
/ _/___ ____ / ____/ ___/
/ // __ \/ __ \/ /_ \__ \
_/ // /_/ / / / / __/ ___/ /
/___/\____/_/ /_/_/ /____/ v0.3.0
Available Repositories (*default):
* [d] ion://gitlab-local/ (Ionburst.Apps.IonFS.Repo.LocalFS.MetadataLocalFS)

Creating the GitLab backups

With ionfs successfully configured, we can now create our GitLab backups. For the application backup, we can use the following:

sudo gitlab-backup create BACKUP="ionfs-example" SKIP="artifacts"

This will look something like:

[josh@git ~]$ sudo gitlab-backup create BACKUP="ionfs-example" SKIP="artifacts"
2022-10-14 20:04:19 +0100 -- Dumping main_database ...
Dumping PostgreSQL database gitlabhq_production ... [DONE]
2022-10-14 20:04:24 +0100 -- Dumping main_database ... done
2022-10-14 20:04:24 +0100 -- Dumping ci_database ... [DISABLED]
2022-10-14 20:04:24 +0100 -- Dumping repositories ...
--- truncated ---
2022-10-14 20:04:28 +0100 -- Dumping repositories ... done
2022-10-14 20:04:28 +0100 -- Dumping uploads ...
2022-10-14 20:04:28 +0100 -- Dumping uploads ... done
2022-10-14 20:04:28 +0100 -- Dumping builds ...
2022-10-14 20:04:28 +0100 -- Dumping builds ... done
2022-10-14 20:04:28 +0100 -- Dumping artifacts ... [SKIPPED]
2022-10-14 20:04:28 +0100 -- Dumping pages ...
2022-10-14 20:04:28 +0100 -- Dumping pages ... done
2022-10-14 20:04:28 +0100 -- Dumping lfs objects ...
2022-10-14 20:04:28 +0100 -- Dumping lfs objects ... done
2022-10-14 20:04:28 +0100 -- Dumping terraform states ...
2022-10-14 20:04:28 +0100 -- Dumping terraform states ... done
2022-10-14 20:04:28 +0100 -- Dumping container registry images ... [DISABLED]
2022-10-14 20:04:28 +0100 -- Dumping packages ...
2022-10-14 20:04:28 +0100 -- Dumping packages ... done
2022-10-14 20:04:28 +0100 -- Creating backup archive: ionfs-example_gitlab_backup.tar ...
2022-10-14 20:04:29 +0100 -- Creating backup archive: ionfs-example_gitlab_backup.tar ... done
2022-10-14 20:04:29 +0100 -- Uploading backup archive to remote storage ... [SKIPPED]
2022-10-14 20:04:29 +0100 -- Deleting old backups ...
2022-10-14 20:04:29 +0100 -- Deleting old backups ... done. (0 removed)
2022-10-14 20:04:29 +0100 -- Deleting tar staging files ...
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/backup_information.yml
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/db
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/repositories
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/uploads.tar.gz
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/builds.tar.gz
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/pages.tar.gz
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/lfs.tar.gz
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/terraform_state.tar.gz
2022-10-14 20:04:29 +0100 -- Cleaning up /var/opt/gitlab/backups/packages.tar.gz
2022-10-14 20:04:29 +0100 -- Deleting tar staging files ... done
2022-10-14 20:04:29 +0100 -- Deleting backups/tmp ...
2022-10-14 20:04:29 +0100 -- Deleting backups/tmp ... done
2022-10-14 20:04:29 +0100 -- Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
and are not included in this backup. You will need these files to restore a backup.
Please back them up manually.
2022-10-14 20:04:29 +0100 -- Backup ionfs-example is done.

The filesystem location used by GitLab is locked down to the git user only, so before we can upload our backup to IBC S6, we need to move the archive to an accessible location and change the ownership to our user account:

sudo mv /var/opt/gitlab/backups/ionfs-example_gitlab_backup.tar /tmp/
sudo chown josh:josh /tmp/ionfs-example_gitlab_backup.tar
ls -lah /tmp/ionfs-example_gitlab_backup.tar

Example output:

[josh@git ~]$ sudo mv /var/opt/gitlab/backups/ionfs-example_gitlab_backup.tar /tmp/
[josh@git ~]$ ls -lah /tmp/ionfs-example_gitlab_backup.tar
-rw-------. 1 josh josh 244M Oct 14 20:04 /tmp/ionfs-example_gitlab_backup.tar

As noted in the application backup output, the GitLab configuration files have not been included in the backup. We can create a configuration backup with the following:

sudo tar -cf /tmp/gitlab-config.tar /etc/gitlab/
sudo chown josh:josh /tmp/gitlab-config.tar
ls -lah /tmp/gitlab-config.tar

Example output:

[josh@git ~]$ sudo tar -cf /tmp/gitlab-config.tar /etc/gitlab/
[josh@git ~]$ sudo chown josh:josh /tmp/gitlab-config.tar
[josh@git ~]$ ls -lah /tmp/gitlab-config.tar
-rw-r--r--. 1 josh josh 320K Oct 14 20:32 /tmp/gitlab-config.tar

Uploading the backups to IBC S6

Now that our GitLab application and configuration backups are ready, we can upload them to IBC S6 with ionfs.

First, we create a directory within the metadata repository:

ionfs mkdir ion://gitlab-backups

We can now upload each of our backups:

ionfs put /tmp/ionfs-example_gitlab_backup.tar ion://gitlab-backups/
ionfs put /tmp/gitlab-config.tar ion://gitlab-backups/

Finally, we can verify that the backups have uploaded successfully, and remove our local copies:

ionfs ls ion://gitlab-backups
rm -f /tmp/ionfs-example_gitlab_backup.tar
rm -f /tmp/gitlab-config.tar
[josh@git ~]$ ionfs mkdir ion://gitlab-backups
[josh@git ~]$ ionfs put /tmp/ionfs-example_gitlab_backup.tar ion://gitlab-backups/
[josh@git ~]$ ionfs put /tmp/gitlab-config.tar ion://gitlab-backups/
[josh@git ~]$ ionfs ls ion://gitlab-backups
____ ___________
/ _/___ ____ / ____/ ___/
/ // __ \/ __ \/ /_ \__ \
_/ // /_/ / / / / __/ ___/ /
/___/\____/_/ /_/_/ /____/ v0.3.0
Directory of ion://gitlab-local/gitlab-backups/
gitlab-backups/gitlab-config.tar 14/10/2022 20:40:17
gitlab-backups/ionfs-example_gitlab_backup.tar 14/10/2022 20:40:12
[josh@git ~]$ rm -f /tmp/ionfs-example_gitlab_backup.tar
[josh@git ~]$ rm -f /tmp/gitlab-config.tar

Building the backup script

Now that we've gone through the backup steps manually, we can have a look at wrapping the steps in a simple bash script that can then be used to automatically backup GitLab to IBC S6. We'll also add in some extra logic to add dates and other useful context to the backup filenames.

So let's take a look at the script:

#!/bin/bash
set -eou pipefail
## setup vars
date=$(date "+%Y%m%d-%H%M%S")
name="$date"_gitlab_backup.tar
data_path=/var/opt/gitlab/backups/
config_path=/etc/gitlab/
user=$(whoami)
## create backups
sudo gitlab-backup create BACKUP="$date" SKIP="artifacts"
sudo mv "$data_path/$name" /tmp/
sudo chown "$user:$user" /tmp/"$name"
sudo tar -cf "/tmp/$date"_gitlab_config.tar "$config_path"
sudo chown "$user:$user" "/tmp/$date"_gitlab_config.tar
## upload to IBC S6
ionfs put "/tmp/$name" ion://gitlab-backups/
ionfs put "/tmp/$date"_gitlab_config.tar ion://gitlab-backups/
## verify and delete local copies
ionfs ls ion://gitlab-backups/
rm -f "/tmp/$name"
rm -f "/tmp/$date"_gitlab_config.tar

Running through the script by section:

  • set -eou pipefail - this is used to ensure the script exits immediately in the event of any failures.
  • We're also setting up the following variables
    • $date is used to add a timestamp to our backup filenames, using the following format: 20221014-205835
    • name is the full filename of the application backup
    • $data_path is the filesystem location used by GitLab to store the application backup
    • $config_path is the location of the GitLab configuration files
    • $user is the current user, used to change the backup file ownership
  • We then create the backups, adding the variables to the manual steps above.
  • Once the backups are created, we upload them to IBC S6 using ionfs
  • Finally, we list the contents of the ionfs metadata repository, and remove the local copies of the backup files.

An example execution of the script would look like:

[josh@git ~]$ ./gitlab-backup.sh
[sudo] password for josh:
2022-10-14 20:59:07 +0100 -- Dumping main_database ...
Dumping PostgreSQL database gitlabhq_production ... [DONE]
2022-10-14 20:59:11 +0100 -- Dumping main_database ... done
2022-10-14 20:59:11 +0100 -- Dumping ci_database ... [DISABLED]
2022-10-14 20:59:11 +0100 -- Dumping repositories ...
--- truncated ---
2022-10-14 20:59:16 +0100 -- Dumping repositories ... done
2022-10-14 20:59:16 +0100 -- Dumping uploads ...
2022-10-14 20:59:16 +0100 -- Dumping uploads ... done
2022-10-14 20:59:16 +0100 -- Dumping builds ...
2022-10-14 20:59:16 +0100 -- Dumping builds ... done
2022-10-14 20:59:16 +0100 -- Dumping artifacts ... [SKIPPED]
2022-10-14 20:59:16 +0100 -- Dumping pages ...
2022-10-14 20:59:16 +0100 -- Dumping pages ... done
2022-10-14 20:59:16 +0100 -- Dumping lfs objects ...
2022-10-14 20:59:16 +0100 -- Dumping lfs objects ... done
2022-10-14 20:59:16 +0100 -- Dumping terraform states ...
2022-10-14 20:59:16 +0100 -- Dumping terraform states ... done
2022-10-14 20:59:16 +0100 -- Dumping container registry images ... [DISABLED]
2022-10-14 20:59:16 +0100 -- Dumping packages ...
2022-10-14 20:59:16 +0100 -- Dumping packages ... done
2022-10-14 20:59:16 +0100 -- Creating backup archive: 20221014-205835_gitlab_backup.tar ...
2022-10-14 20:59:16 +0100 -- Creating backup archive: 20221014-205835_gitlab_backup.tar ... done
2022-10-14 20:59:16 +0100 -- Uploading backup archive to remote storage ... [SKIPPED]
2022-10-14 20:59:16 +0100 -- Deleting old backups ...
2022-10-14 20:59:16 +0100 -- Deleting old backups ... done. (0 removed)
2022-10-14 20:59:16 +0100 -- Deleting tar staging files ...
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/backup_information.yml
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/db
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/repositories
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/uploads.tar.gz
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/builds.tar.gz
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/pages.tar.gz
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/lfs.tar.gz
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/terraform_state.tar.gz
2022-10-14 20:59:16 +0100 -- Cleaning up /var/opt/gitlab/backups/packages.tar.gz
2022-10-14 20:59:16 +0100 -- Deleting tar staging files ... done
2022-10-14 20:59:16 +0100 -- Deleting backups/tmp ...
2022-10-14 20:59:16 +0100 -- Deleting backups/tmp ... done
2022-10-14 20:59:16 +0100 -- Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
and are not included in this backup. You will need these files to restore a backup.
Please back them up manually.
2022-10-14 20:59:16 +0100 -- Backup 20221014-205835 is done.
tar: Removing leading `/' from member names
____ ___________
/ _/___ ____ / ____/ ___/
/ // __ \/ __ \/ /_ \__ \
_/ // /_/ / / / / __/ ___/ /
/___/\____/_/ /_/_/ /____/ v0.3.0
Directory of ion://gitlab-local/gitlab-backups/
gitlab-backups/20221014-205835_gitlab_backup.tar 14/10/2022 20:59:30
gitlab-backups/20221014-205835_gitlab_config.tar 14/10/2022 20:59:34
gitlab-backups/gitlab-config.tar 14/10/2022 20:40:17
gitlab-backups/ionfs-example_gitlab_backup.tar 14/10/2022 20:40:12

Wrapping up

In this tutorial we've covered some background on the self-hosted GitLab backups, how to create them, and how to upload them to IBC S6 with the IonFS CLI. Finally we wrapped the steps in a simple bash script to allow the process to be automated.

All the steps covered in this tutorial, and the backup script, are currently used by Ionburst Cloud to backup and protect our internal GitLab instance. To keep up with the latest developments on the backup script, please checkout out our examples repository on GitHub.