Перенос GitLab на новый сервер или восстановление из бекапа
После падения моего домашнего шлюза на 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 для нескольких целей, поэтому использовать будем его. То, что идёт в комплекте с 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