Перенос GitLab на новый сервер или восстановление из бекапа

Перенос GitLab на новый сервер или восстановление из бекапа
Photo by Pankaj Patel / Unsplash

После падения моего домашнего шлюза на Ubuntu 20.04 и установки на его место Ubuntu 24.04 нужно было как-то восстанавливать GitLab имея только копии файлов, этим и будем заниматься. Мануал использует официальную документацию по gitlab, необходимые для прочтения разделы: Migrate to a new server, Download and Install Gitlab, Restore Gitlab, Downgrade, но пишется больше для себя, поэтому не претендует на исчерпывающее руководство типа "How-To", в нём могут быть ошибки и не самые правильные команды, но как говорится as-is.

Подготовка виртуального хоста

Установка Nginx на Ubuntu 24.04.1
Установка Обновляем информацию о пакетах репозитория: sudo apt-get update Устанавливаем Nginx: sudo apt install nginx Обычно все устанавливается без вопросов, но бывает иное. Чтобы проверить, как работает сервис, выполняем: sudo systemctl status nginx В моем случае что-то пошло не по плану: × nginx.service - A high performance web server and

На сервере уже установлен Nginx для нескольких целей, поэтому использовать будем его. То, что идёт в комплекте с GitLab нам не интересно. Поэтому я сперва подготавливаю простейшую конфигурацию виртуального хоста для получения SSL сертификатов. Допустим, мой хост называется gitlab.example.com и вариант виртуального хоста следующий (хотя можно было и проще, скелет был готов ранее):

server {
        listen 80;
        server_name gitlab.example.com;

        access_log /var/www/logs/n.gitlab_example_com.access.log;
        error_log /var/www/logs/n.git_example_com.error.log;

        index index.php index.html index.htm;
        root /var/www/html;

        location / {
                proxy_pass http://127.0.0.1:8080;
                include proxy_params;
        }

        location @backend {
                proxy_pass http://127.0.0.1:8080;
                include proxy_params;
        }

        location ~* \.(html|htm|css|xml|rss|gif|jpeg|jpg|js|atom|mml|jad|wml|htc|png|tif|tiff|wbmp|ico|jng|bmp|jar|war|ear|hqx|doc|pdf|ps|eps|ai|rtf|xls|ppt|wmlc|xhtml|cco|jardiff|jnlp|run|>
                try_files $uri @backend;
                expires max;
                log_not_found off;
        }

        location ~ /\.ht {
                deny all;
        }
}

Активируем хост, перезапускаем nginx, проверяем состояние:

sudo ln -s /etc/nginx/sites-available/gitlab_example_com.conf /etc/nginx/sites-enabled/
sudo systemctl restart nginx
sudo systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Mon 2024-11-18 20:00:48 +07; 7s ago
       Docs: man:nginx(8)
    Process: 111368 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 111371 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 111372 (nginx)
      Tasks: 5 (limit: 9346)
     Memory: 5.2M (peak: 5.6M)
        CPU: 67ms
     CGroup: /system.slice/nginx.service
             ├─111372 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─111373 "nginx: worker process"
             ├─111374 "nginx: worker process"
             ├─111375 "nginx: worker process"
             └─111376 "nginx: worker process"

Генерируем сертификат хоста через certbot:

sudo certbot --nginx -d gitlab.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for gitlab.example.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/gitlab.example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/gitlab.example.com/privkey.pem
This certificate expires on 2025-02-16.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for gitlab.example.com to /etc/nginx/sites-enabled/gitlab.example.com.conf
Congratulations! You have successfully enabled HTTPS on https://gitlab.example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Отлично, сертификат создан. Виртуальный хост подготовлен.

Установка на новом сервере

Мне необходимо было не просто установить, а потом и восстановить gitlab со всем кодом, что там был закопан. Поэтому для начала определяем, какая версия у нас стояла на предыдущем сервере. Для этого в архивах старого сервера находим файл version-manifest.txt, в нём описаны все версии установленных ранее компонентов и самого gitlab. В моем случае утраченная версия была gitlab-ce 17.4.2, однако не торопимся, ищем в резервной копии файл настроек gitlab.rb, в нём ищем строку gitlab_rails['backup_path'], если у вас она сконфигурирована, то следуем данному пути, если нет - идем по умолчанию в /var/opt/gitlab/backups и проверяем для какой версии у вас есть бэкап данных, в моем случае оказалось, что бекап есть только для версии 17.4.1. Из этого следует, что восстанавливать будем именно версию 17.4.1.

Выполняем частично рекомендации по установке gitlab:

sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates tzdata perl

Скачиваем и запускаем скрипт установки репозитория gitlab, для ce-версии команда следующая:

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  6865  100  6865    0     0  13174      0 --:--:-- --:--:-- --:--:-- 13176
Detected operating system as Ubuntu/noble.
Checking for curl...
Detected curl...
Checking for gpg...
Detected gpg...
Running apt-get update... done.
Installing apt-transport-https... done.
Installing /etc/apt/sources.list.d/gitlab_gitlab-ce.list...done.
Importing packagecloud gpg key... done.
Running apt-get update... done.

Отлично, репозиторий установлен. Теперь ищем пакет необходимой нам версии. Для этого выполняем:

sudo apt-cache madison gitlab-ce

Команда выдаст нам список доступных для установки пакетов, листинг не малый, поэтому строка с моей версией выглядит так:

gitlab-ce | 17.4.1-ce.0 | https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu noble/main amd64 Packages

Точно записываем версию пакета 17.4.1-ce.0 и подготавливаем с её помощью команду установки:

sudo apt-get install gitlab-ce=17.4.1-ce.0

Если вы последовали рекомендациям мануала и выполнили установку с указанием EXTERNAL_URL, то вероятнее всего GitLab у вас не установится и свалится с ошибкой генерации сертификата домена:

[2024-11-18T20:27:28+07:00] FATAL: Stacktrace dumped to /opt/gitlab/embedded/cookbooks/cache/cinc-stacktrace.out
[2024-11-18T20:27:28+07:00] FATAL: ---------------------------------------------------------------------------------------
[2024-11-18T20:27:28+07:00] FATAL: PLEASE PROVIDE THE CONTENTS OF THE stacktrace.out FILE (above) IF YOU FILE A BUG REPORT
[2024-11-18T20:27:28+07:00] FATAL: ---------------------------------------------------------------------------------------
[2024-11-18T20:27:28+07:00] FATAL: RuntimeError: letsencrypt_certificate[gitlab.example.com] (letsencrypt::http_authorization line 6) had an error: RuntimeError: acme_certificate[staging] (letsencrypt::http_authorization line 43) had an error: RuntimeError: ruby_block[create certificate for gitlab.example.com] (letsencrypt::http_authorization line 110) had an error: RuntimeError: [gitlab.example.com] Validation failed, unable to request certificate, Errors: [{url: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/14970648823/yG2trA, status: invalid, error: {"type"=>"urn:ietf:params:acme:error:unauthorized", "detail"=>"xx.xx.xx.xx: Invalid response from https://gitlab.example.com/.well-known/acme-challenge/NtuyKssxWtr6h0c9TsrsA4WassVPzQkBf6sS6ssJa7k: 404", "status"=>403}} ]

Не страшно, дальнейший порядок действий отличаться не должен.

Донастраиваем виртуальный хост

Редактируем конфигурацию виртуального хоста после изменений certbot'ом для работы с gitlab. Мой вариант конфигурации получился следующим:

upstream gitlab-workhorse {
  # On GitLab versions before 13.5, the location is
  # `/var/opt/gitlab/gitlab-workhorse/socket`. Change the following line
  # accordingly.
  server unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket fail_timeout=0;
}

server {
    server_name gitlab.example.com;

    access_log /var/www/logs/n.gitlab_example_com.access.log;
    error_log /var/www/logs/n.gitlab_example_com.error.log;

    server_tokens off; ## Don't show the nginx version number, a security best practice
    root /opt/gitlab/embedded/service/gitlab-rails/public;

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/gitlab.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/gitlab.example.com/privkey.pem; # managed by Certbot
    ssl_session_cache shared:SSL:10m;
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    ssl_protocols TLSv1 TLSv1.1;
    ssl_session_cache shared:SSL:10m;

    location / {
        client_max_body_size 0;
        gzip off;

        ## https://github.com/gitlabhq/gitlabhq/issues/694
        ## Some requests take more than 30 seconds.
        proxy_read_timeout      300;
        proxy_connect_timeout   300;
        proxy_redirect          off;

        proxy_http_version 1.1;

        proxy_set_header    Host                $http_host;
        proxy_set_header    X-Real-IP           $remote_addr;
        proxy_set_header    X-Forwarded-Ssl     on;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Proto   $scheme;
        proxy_pass http://gitlab-workhorse;
    }
}
server {
    server_tokens off; ## Don't show the nginx version number, a security best practice

    if ($host = gitlab.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name gitlab.example.com;
    return 404; # managed by Certbot
}

Конфигурация рассчитана на то, что в gitlab.rb установлены следующие директивы:

gitlab_workhorse['listen_network'] = "unix"
gitlab_workhorse['listen_addr'] = "/var/opt/gitlab/gitlab-workhorse/sockets/socket"

Перезапускаем nginx, проверяем всё ли ок:

sudo systemctl restart nginx
sudo systemctl status nginx

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Mon 2024-11-18 21:05:43 +07; 1s ago
       Docs: man:nginx(8)
    Process: 138488 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 138491 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 138492 (nginx)
      Tasks: 5 (limit: 9346)
     Memory: 4.9M (peak: 5.2M)
        CPU: 71ms
     CGroup: /system.slice/nginx.service
             ├─138492 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─138493 "nginx: worker process"
             ├─138494 "nginx: worker process"
             ├─138495 "nginx: worker process"
             └─138496 "nginx: worker process"

Всё ок, идём дальше.

Восстановление ключей и конфигурации

Необходимо из резервной копии файлов восстановить настройки gitlab и секретные ключи, которые находятся в файлах gitlab-secrets.json и gitlab.rb. Я просто переношу всё содержимое каталога /etc/gitlab/ из резервной копии на действующий сервер. После установки gitlab права на каталоги стояли 755, а вот на файлы 600, а после копирования из резервной копии они скорее всего слетят, поэтому восстановим:

sudo find /etc/gitlab/ -type d -exec chmod 755 {} \;
sudo find /etc/gitlab/ -type f -exec chmod 600 {} \;

Владелец тоже слетит, восстановим:

cd /etc/gitlab/
sudo chown -R root:root *

Запускаем реконфигурацию gitlab:

sudo gitlab-ctl reconfigure

Даже если при установке ваш gitlab упал с ошибкой описанной выше, сейчас этого уже произойти не должно, и вы должны увидеть заветное:

....
gitlab Reconfigured!

Запускаем gitlab:

sudo gitlab-ctl start

Наша задача на текущий момент получить рабочий инстанс GitLab, поэтому проверяем доступ по url. В моем случае я получил 502 Bad Gateway. Пошел разбираться и в логах nginx обнаружил множество ошибок формата:

[crit] 138495#138495: *2860 connect() to unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket failed (13: Permission denied) while connecting to upstream, client: xx.xx.xx.xx, server: gitlab.example.com, request: "GET /api/v4/internal/kubernetes/receptive_agents HTTP/2.0", upstream: "http://unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket:/api/v4/internal/kubernetes/receptive_agents", host: "gitlab.example.com"

Пошел проверять права на socket и директорию, его содержащую:

cd /var/opt/gitlab/gitlab-workhorse
ls -la
total 20
drwxr-x---  3 git  gitlab-www 4096 ноя 18 22:30 .
drwxr-xr-x 18 root root       4096 ноя 18 22:29 ..
-rw-r-----  1 root git         140 ноя 18 20:25 config.toml
drwxr-x---  2 git  gitlab-www 4096 ноя 18 22:24 sockets
-rw-r--r--  1 root root         45 ноя 18 20:25 VERSION

Ожидаемо видим, что директория sockets имеет права 750, что не позволяет её читать пользователю nginx. Для доступа к сокету добавим пользователя www-data в группу gitlab-www командой:

sudo usermod -aG gitlab-www www-data

и перезапускаем nginx:

sudo systemctl restart nginx

Этого обычно хватает, главная страница должна открыться:

Отлично, у нас есть рабочий инстанс gitlab c необходимой конфигурацией и секретными ключами.

Восстановление данных

Переходим к самому важному - восстановлению данных. Мы должны точно понимать, что последнее выполнение команды sudo gitlab-ctl reconfigure было успешным и наш инстанс запущен и работает, если нет запускаем его командой sudo gitlab-ctl start.

Останавливаем redis:

sudo gitlab-ctl stop redis

Переносим файл файл /var/opt/gitlab/redis/dump.rdb из архива аналогичную директорию сервера.

Открываем файл конфигурации gitlab.rb и ищем настройку gitlab_rails['backup_path'], в которой прописан путь к хранилищу резервных копий, по умолчанию это /var/opt/gitlab/backups. Загружаем наш бэкап в определенную директорию, устанавливаем владельцем пользователя git:

sudo chown git:git /var/opt/gitlab/backups/1728832281_2024_10_13_17.4.1_gitlab_backup.tar

Устанавливаем права на dump redis:

sudo chown gitlab-redis:gitlab-redis /var/opt/gitlab/redis/dump.rdb

Дополнительно, переносим из бэкапа директории:

  • /var/opt/gitlab/git-data - каталог, содержащий все данные Git;
  • /var/opt/gitlab/gitlab-rails/shared - каталог с объектами, например артефактами;
  • /var/opt/gitlab/postgresql/data - если используется PostgreSQL, установленный отдельно, переносим данные БД.
  • /var/opt/gitlab/gitlab-rails/uploads - аватарки, иконки - не забываем догрузить.

Устанавливаем права на перенесённые данные:

sudo chown -R git:git /var/opt/gitlab/git-data
sudo chown -R git:git /var/opt/gitlab/gitlab-rails/uploads

Запускаем redis:

sudo gitlab-ctl start redis

Останавливаем процессы работы с БД, остальное не трогаем:

sudo gitlab-ctl stop puma
sudo gitlab-ctl stop sidekiq
# проверяем
sudo gitlab-ctl status
run: gitaly: (pid 279253) 704s; run: log: (pid 279251) 704s
run: gitlab-kas: (pid 279267) 704s; run: log: (pid 279257) 704s
run: gitlab-workhorse: (pid 279262) 704s; run: log: (pid 279243) 704s
run: logrotate: (pid 279254) 704s; run: log: (pid 279245) 704s
run: postgresql: (pid 279255) 704s; run: log: (pid 279250) 704s
down: puma: 19s, normally up; run: log: (pid 279244) 704s
run: redis: (pid 279247) 704s; run: log: (pid 279246) 704s
down: sidekiq: 3s, normally up; run: log: (pid 279241) 704s

Исходя из имена фала резервной копии формируем команду на восстановление данных, хвост _gitlab_backup.tar отбрасывается, остальное используем и запускаем процесс восстановления:

sudo gitlab-backup restore BACKUP=1728832281_2024_10_13_17.4.1

Если версия файла резервной копии и версия установленного инстанса GitLab не совпадёт - вы получите соответствующее сообщение.

GitLab version mismatch:
  Your current GitLab version (17.4.2-ce) differs from the GitLab version in the backup!
  Please switch to the following version and try again:
  version: 17.4.1-ce

Для понижения версии GitLab читаем ниже главу Downgrade. Если версии совпали, процесс начнёт восстановление данных. Хвост лога восстановления должен быть примерно следующий:

2024-11-23 04:39:57 UTC -- [DONE]
2024-11-23 04:39:57 UTC -- Source backup for the database ci doesn't exist. Skipping the task
2024-11-23 04:39:57 UTC -- Restoring database ... done
2024-11-23 04:39:57 UTC -- Restoring external diffs ...
2024-11-23 04:39:57 UTC -- Restoring external diffs ... done
This task will now rebuild the authorized_keys file.
You will lose any data stored in the authorized_keys file.
Do you want to continue (yes/no)? yes

2024-11-23 04:42:43 UTC -- Deleting tar staging files ...
2024-11-23 04:42:43 UTC -- Cleaning up /var/opt/gitlab/backups/backup_information.yml
2024-11-23 04:42:43 UTC -- Cleaning up /var/opt/gitlab/backups/db
2024-11-23 04:42:43 UTC -- Cleaning up /var/opt/gitlab/backups/external_diffs.tar.gz
2024-11-23 04:42:43 UTC -- Deleting tar staging files ... done
2024-11-23 04:42:43 UTC -- Deleting backups/tmp ...
2024-11-23 04:42:43 UTC -- Deleting backups/tmp ... done
2024-11-23 04:42:43 UTC -- Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data
and are not included in this backup. You will need to restore these files manually.
2024-11-23 04:42:43 UTC -- Restore task is done.
2024-11-23 04:42:43 UTC -- Deleting backup and restore PID file at [/opt/gitlab/embedded/service/gitlab-rails/tmp/backup_restore.pid] ... done

Следующим шагом, перезапускаем и проверяем gitlab:

sudo gitlab-ctl restart
sudo gitlab-rake gitlab:check SANITIZE=true

Проверяем, что значения БД можно расшифровать ключами из восстановленного файла /etc/gitlab/gitlab-secrets.json:

sudo gitlab-rake gitlab:doctor:secrets

Выполняем проверку целостности загруженных файлов:

sudo gitlab-rake gitlab:artifacts:check
sudo gitlab-rake gitlab:lfs:check
sudo gitlab-rake gitlab:uploads:check

Если на данном этапе получаем что-то такое:

Checking integrity of Uploads
- 1..52: Failures: 39
Done!

перезапускаем команду с дополнительным флагом:

sudo gitlab-rake gitlab:uploads:check VERBOSE=1

По логам мы понимаем, каких файлов не хватает. В моем случае проблема оказалась в директории upload:

  - Upload: 1: #<Errno::ENOENT: No such file or directory @ rb_sysopen - /opt/gitlab/embedded/service/gitlab-rails/public/uploads/-/system/user/avatar/2/avatar.png>
...
- Upload: 52: #<Errno::ENOENT: No such file or directory @ rb_sysopen - /opt/gitlab/embedded/service/gitlab-rails/public/uploads/-/system/project/avatar/36/2327336-1567663181.jpg>

Догружаем потерянные файлы из архива в необходимые каталоги (по текущему примеру указанный в логе каталог и фактический, в который надо догрузить файлы - отличаются, это надо учитывать). Добиваемся результата, когда проверка не дает ошибок:

Checking integrity of Uploads
- 1..52: Failures: 0
Done!

Последним этапом является создание статистики БД для ускорения работы:

sudo gitlab-rails dbconsole --database main
SET STATEMENT_TIMEOUT=0 ; ANALYZE VERBOSE;
exit;

Downgrade

Бонусный раздел, для тех кто обнаружил, что версия бэкапа всё-таким меньше, чем установленная версия gitlab, т.е. для меня.

Останавливаем сервисы и удаляем текущую версию пакета:

sudo gitlab-ctl stop puma
sudo gitlab-ctl stop sidekiq
sudo dpkg -r gitlab-ce

Проводим идентификацию версии для установки:

sudo apt-cache madison gitlab-ce

Устанавливаем необходимую версию:

sudo apt install gitlab-ce=17.4.1-ce.0

Запускаем реконфигурацию:

sudo gitlab-ctl reconfigure