Ранее я писал о MinIO в качестве хранилища реестра контейнеров, но в случае VDS/VPS такой вариант экономически не выгоден: чуть ли не на порядок дешевле воспользоваться услугой аренды S3 у какого-нибудь облачного провайдера. Что я и решил сделать, ведь место на сервере стало очень быстро заканчиваться. Заодно мигрируем прокси зависимостей, LFS и всякое такое.

Коротко об аренде объектного хранилища

По моим ощущениям, рынок сейчас предлагает три основных подхода к тарификации. Самый сложный – с классами хранилища и оплатой не только за исходящий трафик и занятый объем, но еще и отдельно за запросы (PUT, GET и так далее). Этим грешат крупнейшие провайдеры типа Selectel с Яндексом, и на мой взгляд такое простым смертным вроде вашего покорного слуги не нужно. Хотя пойму, если репутация сыграет решающую роль при выборе.

Раздельная оплата за место и исходящий трафик встречается наиболее часто. Наконец, есть и самые простые варианты с оплатой только занимаемого пространства. Лично я предпочел как раз последний вариант на случай, если мои образы контейнеров станут востребованными. Если же нет, то тогда я буду терять примерно по 60 копеек за гигабайт. smile Иными словами, стоимость хранения гигабайта в последнем случае сейчас составляет где-то 2,1 рубля в месяц, а во втором – 1,5.

Итак, в моем случае после регистрации в личном кабинете потребовалось закинуть на счет 100 рублей. Затем я активировал хранилище S3, понасоздавал «вёдер» (мне не нравится калька с английского – можно было бы иносказательно перевести как «корзина» или чем-то подобным, но видимо «бакет» уже устоявшийся термин) и отдельный ключ доступа специально для GitLab.

Консолидированная настройка S3 в GitLab

Прежде чем приступать к настройке, на всякий случай согласуем версию песика – на момент написания статьи у меня работает 18.4.1 в Docker. И конечно же ни в коем случае нельзя забывать про бэкап архивирование!

docker exec -t gitlab gitlab-backup create

В gitlab.rb задаем общие настройки хранилища S3:

gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['proxy_download'] = false
gitlab_rails['object_store']['connection'] = {
  'provider' => 'AWS',
  'endpoint' => 'https://s3.example.ru',
  'aws_access_key_id' => '<ACCESS_KEY_ID>',
  'aws_secret_access_key' => '<SECRET_ACCESS_KEY>'
}
gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'artifacts'
gitlab_rails['object_store']['objects']['external_diffs']['enabled'] = false
gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'lfs'
gitlab_rails['object_store']['objects']['uploads']['enabled'] = false
gitlab_rails['object_store']['objects']['packages']['bucket'] = 'packages'
gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'dependency'
gitlab_rails['object_store']['objects']['terraform_state']['enabled'] = false
gitlab_rails['object_store']['objects']['ci_secure_files']['enabled'] = false
gitlab_rails['object_store']['objects']['pages']['enabled'] = false

Параметры подключения получаем в личном кабинете.

Я решил не переносить в S3 ряд объектов:

  • external_diffs – разностные файлы запросов на слияние (по умолчанию хранятся в БД и пусть так и остается);
  • uploads – пользовательские загрузки (для меня не особо актуально, так что поживут и в ФС);
  • terraform_state – перенос состояния Terraform пока что необратим, да и вероятность того, что я этой страстью воспользуюсь, крайне мала;
  • ci_secure_files – защищенные файлы для CI/CD;
  • pages – статические страницы, которые надо бы в принципе выключить, раз я ими не пользуюсь.

Что касается ci_secure_files – написано, что они хранятся отдельно от репозиториев и могут использоваться для передачи некоей «чувствительной» информации в задания. Мне кажется, пусть лучше такая информация будет в файловой системе. Впрочем я пока что CI/CD и не пользуюсь, так что посмотрим.

Для каждого типа объектов нужно создать отдельную ёмкость и прописать в настройках. В моем случае названия бакетов должны быть глобально уникальными (!?), поэтому пришлось изобретать всякие префиксы (лучше с дефисами, а не точками, чтобы работало подключение в стиле виртуальных хостов). Не могу сказать, насколько это нормальная ситуация – мне казалось, что достаточно быть уникальным в пределах аккаунта, а не всего облака.

Так или иначе, переконфигурирем GitLab. В общем случае это gitlab-ctl reconfigure, но под Docker мы можем перезапустить все приложение:

docker compose down
docker compose up -d

Когда все запустится (через несколько минут), поочередно переносим данные:

docker exec -t gitlab gitlab-rake gitlab:artifacts:migrate
docker exec -t gitlab gitlab-rake gitlab:lfs:migrate
docker exec -t gitlab gitlab-rake gitlab:packages:migrate
docker exec -t gitlab gitlab-rake gitlab:dependency_proxy:migrate

По мере необходимости аналогично мигрирует все остальное.

Миграция реестра

Хранилище реестра контейнеров настраивается отдельно, а перенос осуществляется вручную.

AWS CLI

В документации предлагается воспользоваться именно этим средством, хотя в теории подойдет и rclone (но к нему вроде как есть вопросы по части синхронизации метаданных).

Установим вручную (предполагается работа под root, иначе многие команды придется предварять sudo):

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
./aws/install

Настраиваем параметры доступа к облаку:

aws configure

Проверяем настройки – команда должна вывести список корзинок:

aws --endpoint-url https://s3.example.ru s3 ls

На этом шаге велика вероятность получить ошибку сертификата вида:

SSL validation failed for https://s3.example.ru/ [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1032)

В этом случае нужно прописать системный корневой сертификат в /root/.aws/config:

[default]
ca_bundle = /etc/ssl/certs/ca-certificates.crt
endpoint_url = https://s3.example.ru

Я заодно добавил endpoint_url, чтобы каждый раз не указывать ее в командах.

Перенос

В идеале сначала стоит перевести реестр в режим только чтения – в gitlab.rb прописать:

registry['storage'] = {
  'filesystem' => {
    'rootdirectory' => "/var/opt/gitlab/gitlab-rails/shared/registry"
  },
  'maintenance' => {
    'readonly' => {
      'enabled' => true
    }
  }
}

И переконфигурировать GitLab. Однако я позволил себе пропустить этот шаг, поскольку кроме меня туда никто ничего не отправляет. Поэтому сразу зарядил копирование:

cd /srv/gitlab/data/gitlab-rails/shared
aws s3 sync registry s3://registry

Где /srv/gitlab/data – директория, соответствующая /var/opt/gitlab в контейнере; первый registry в команде – директория, а второй – бадья (подставьте актуальное наименование).

Для контроля сравним количество файлов с объектами:

find registry -type f | wc -l
aws s3 ls s3://registry --recursive | wc -l

Перенастраиваем хранилище реестра:

registry['storage'] = {
  's3_v2' => {
    'accesskey' => '<ACCESS_KEY_ID>',
    'secretkey' => '<SECRET_ACCESS_KEY>',
    'bucket' => 'registry',
    'region' => 'us-east-1',
    'regionendpoint' => 'https://s3.example.ru'
  }
}

Особенность в том, что здесь надо обязательно указать какой-то регион (например us-east-1) даже если у провайдера никаких регионов нет. Последний раз на сегодня реконфигурируем GitLab в ознаменование окончания переезда. И только убедившись в безопасности маневра, удаляем директорию реестра.

На всякий случай уточню, что в случае больших реестров и нежелательности длительной блокировки, порядок работы немного отличается: сначала запускается синхронизация, потом включается режим только для чтения и досылаются изменения:

aws s3 sync registry s3://registry --delete

В этом случае количество объектов и файлов при сравнении в теории может отличаться на содержимое временных директорий загрузок (_upload).

Заключение

Вот таким относительно нехитрым и на первый взгляд не слишком затратным способом я освободил место на сервере. Пока что у меня, разумеется, нет какой-то статистики относительно стабильности работы хранилища. Скорость вроде бы нормальная, но как будто бы есть ощутимые первоначальные задержки на установку соединения.

В зависимости от того, насколько вы доверяете облачному провайдеру, резервировать само хранилище или не нужно вовсе, или это можно сделать тем же aws, поменяв местами пункты отправления и назначения, а потом еще и заполировать tar’ом. Мне кажется от греха подальше лучше все же настроить на своем компьютере или домашнем сервере aws или rclone и иногда таки хранилище выкачивать, особенно при безлимитном исходящем трафике (а потом загружать архив в другое облако biggrin scratch).

Напоследок позвольте напомнить о моем репозитории с образами PHP:

https://git.dmkos.ru/containers/php

В немалой степени он и послужил толчком к освоению реестра контейнеров, а теперь и хранилища S3.


Категория: Программирование, веб | Опубликовано 02.10.2025

Похожие материалы

Перенос GitLab на другой сервер в Docker

Примерно год я мучался с GitLab на сервере с двумя гигабайтами оперативки. Когда оплаченный период закончился, решил взять более мощный VDS по формуле 4/4/30. До этого сам GitLab был установлен непосредственно из репозитория, но для экспериментов с Pages и т.д. нужен Docker. А раз он и так есть, почему бы не завернуть GitLab в контейнер? Заодно на сервер можно будет установить что-нибудь еще.


Комментарии, обсуждение