Зеркала и вторая площадка
Зеркало — это репозиторий одной установки Arkvory, который служит копией другого репозитория (источника) на другой установке, доступной только для чтения. Установка с зеркалом забирает изменения из источника по HTTPS. У неё своя база данных, своё хранилище файлов, свои учётные записи и свои ключи.
Зеркало нужно, чтобы отдавать скачивания из второго места и держать вторую площадку, которая может заменить источник, если он потерян. Зеркало не заменяет резервную копию источника и не даёт автоматической высокой доступности. Переключение вы выполняете сами. Другие способы защиты описаны в разделах Резервные копии и Шлюзы чтения.
Что такое зеркало
Для зеркалируемого репозитория установка-зеркало копирует:
- Опубликованные файлы: их байты и те же идентификаторы артефактов, что и на источнике.
- Метки, метаданные и коллекции.
- Регистрацию UPack, стадии и текущие пути к файлам.
- Образы контейнеров, объекты Git LFS и пакеты npm репозитория.
- Удаления. Файл, удалённый на источнике, удаляется и на зеркале.
Скачивания по ID, по пакету (версия, диапазон, стадия) и по пути к файлу на зеркале отвечают так же, как отвечал источник при последней синхронизации. Они продолжают работать, когда источник недоступен.
Зеркало не копирует:
- Учётные записи, группы, ключи и права доступа. У зеркала свои, и они независимы: отзыв ключа на источнике не влияет на зеркало.
- Ссылки, которые защищают файлы от очистки, вложения сборок, журналы аудита и политики хранения.
- Историю путей к файлам до первой синхронизации. Номера версий меток и путей на зеркале собственные.
Клиенты не могут писать в зеркалируемый репозиторий. Загрузки, изменения меток, пути к файлам, стадии, удаление и продвижение в него возвращают HTTP 409 с причиной mirror_read_only. Другие репозитории установки-зеркала работают как обычно. Политики хранения в зеркалируемом репозитории не выполняются, а удаляет там только синхронизация.
Настройте зеркало
Вам понадобятся ключ на источнике и одна команда на зеркале.
Создайте ключ на источнике
Зеркалу нужен ключ, который может только читать репозиторий источника. Ключ с правом записи не нужен.
- На источнике откройте Сервисный доступ с ключом восстановления или ключом оператора.
- Нажмите Создать сервисный аккаунт и в Права на репозитории добавьте репозиторий. Нажмите Набор для чтения, чтобы заполнить права, которые нужны зеркалу. Среди них
artifact.list,artifact.read,content.read,annotation.read,asset.readиpackage.read. - Нажмите Выпустить ключ, скопируйте секрет, подтвердите Секрет сохранён и нажмите Активировать ключ. Ключ, который не активирован, истекает через 15 минут.
- Сохраните секрет в файле на сервере-зеркале. В файле только ключ, одной строкой, от 16 до 4000 печатаемых символов. Читать файл могут только root или группа «Администраторы».
Источник должен быть выпуском с потоком изменений. Команда на следующем шаге это проверяет.
Подключите репозиторий на зеркале
Используйте для зеркала новое пустое имя репозитория. Синхронизация делает репозиторий равным источнику, но никогда не удаляет то, чего на источнике никогда не было.
sudo arkvory configure --root /opt/proanima-arkvory \
--mirror releases \
--mirror-upstream https://arkvory.example \
--mirror-token-file /root/mirror-releases.key$root = 'C:\ProgramData\ProAnima\Arkvory'
& 'C:\Program Files\ProAnima\Arkvory\arkvory.ps1' configure --root $root `
--mirror releases --mirror-upstream https://arkvory.example `
--mirror-token-file C:\secure\mirror-releases.key| Параметр | Значение |
|---|---|
--mirror NAME | Репозиторий на этой установке. От 1 до 64 символов: строчные буквы, цифры, _ и -, первый символ — буква или цифра |
--mirror-upstream URL | Origin источника: https://host без пути, учётных данных и запроса. Обычный http:// принимается только для localhost, 127.0.0.1 и [::1] |
--mirror-token-file FILE | Абсолютный путь к файлу ключа |
--mirror-source NAME | Репозиторий на источнике. По умолчанию — то же имя, что в --mirror |
--mirror-ca-file FILE | Файл PEM с центром сертификации источника. См. HTTPS со своим центром сертификации |
Передавайте одной команде один репозиторий. Нельзя объединять изменение зеркала с изменением HTTPS, хранилища копий или обновлений в одном вызове.
- Команда проверяет источник с ключом, прежде чем что-либо изменить. Источник должен сообщать о потоке изменений для зеркал, а поток изменений репозитория источника должен отвечать.
- Она сохраняет ключ в
config/mirrors/NAME.token, записываетconfig/mirrors/mirrors.jsonи задаётARKVORY_MIRRORS_FILEвconfig/runtime.json. - Она перезапускает API и обработчик и ждёт, пока они будут готовы. Если что-то не получилось, она возвращает прежние файлы и перезапускает службы снова.
В Docker Compose команда дополнительно записывает config/compose.mirrors.yml, который подключает файлы зеркал к контейнерам API и обработчика. Добавляйте его в команды Compose, которые вы запускаете сами.
Чтобы заменить ключ репозитория, повторите команду только с --mirror и новым --mirror-token-file. Источник, стадии и центры сертификации остаются прежними, а зеркало никогда не превращается в импорт от повторной команды. Команда перезапускает API и обработчик. Кроме того, обработчик заново читает файл ключа после каждого сбоя, поэтому файл ключа, заменённый вручную, работает без перезапуска.
sudo arkvory configure --root /opt/proanima-arkvory \
--mirror releases --mirror-token-file /root/new-mirror-releases.keyЕсли источник отклоняет ключ, команда останавливается, ничего не изменив, и сообщает причину: ключ не принят (401), ему нельзя читать репозиторий (403) или репозитория нет на источнике (404). Репозиторий, который уже зеркалирует один источник, отклоняет другой источник с сообщением NAME mirrors another source; detach it first.
На установке-зеркале дайте людям и инструментам доступ к репозиторию. Репозиторий появляется, как только его имя указано в выданном доступе или в политике сервисной учётной записи. Для людей используйте Доступ к репозиториям в разделе Пользователи и доступ, для инструментов — политику сервисной учётной записи. Права источника не переносятся.
HTTPS со своим центром сертификации
Если источник использует сертификат корпоративного или самоподписанного центра сертификации, добавьте --mirror-ca-file /path/ca.pem в команду --mirror. Команда проверяет, что каждый сертификат читается и не просрочен, и сохраняет от 1 до 64 сертификатов в config/mirrors/ca.pem (размер файла не должен превышать 1 МиБ). После этого обработчик доверяет им в дополнение к стандартным.
- Файл обслуживает все зеркала установки. Новый
--mirror-ca-fileдополняет его, а уже имеющийся сертификат хранится один раз. Отключение последнего зеркала удаляет файл. - Обработчик доверяет всему набору для всех своих соединений, а не только для одного зеркала.
- Проверка сертификатов никогда не отключается.
Что копируется и как часто
Синхронизацию выполняет обработчик установки-зеркала. Отдельной службы нет. Для каждого зеркалируемого репозитория он выполняет такие шаги:
- Первичное заполнение. Обработчик запоминает текущую позицию в потоке изменений источника. Затем он постранично читает список артефактов, пакетов и путей к файлам и делает зеркало равным источнику.
- Отслеживание. Обработчик читает поток изменений источника. Когда он догнал источник, он проверяет поток заново каждые 10 секунд. Позицию он сохраняет после каждого применённого изменения.
- Копирование файлов. Файл копируется по частям. Обработчик проверяет SHA-256 каждой части и всего файла. После прерывания он продолжает с первой недостающей части. Часть ждёт в
mirror-stagingвнутри каталога хранилища файлов зеркала. - После ошибки. Обработчик повторяет шаг после паузы, которая начинается с 2 секунд и удваивается до 5 минут. Один зеркалируемый репозиторий с ошибкой не останавливает остальные.
В установке может быть до 64 зеркалируемых репозиториев. Копии учитываются в пределе ёмкости и на диске зеркала, поэтому планируйте столько же места, сколько нужно репозиторию-источнику. См. Хранение.
Если ключ источника отозван или источник недоступен, зеркало продолжает отдавать то, что у него уже есть, и показывает ошибку в своём состоянии.
Проверьте состояние синхронизации
В консоли
Зеркала в меню перечисляет все зеркала и импорты, репозитории которых вам можно читать, с источником, состоянием, последней синхронизацией и тем, что скопировано. Администраторы видят страницу всегда; пока зеркал нет, она объясняет, как его настроить. Страница сама обновляется каждые 20 секунд.
| Состояние | Значение |
|---|---|
| Синхронизировано | Зеркало догнало источник |
| Догоняет | Копирует изменения, которые источник внёс после последней проверки |
| Запускается | Настроено, но обработчик до него ещё не добрался |
| Первое копирование | Первичное заполнение или новое заполнение после восстановления источника |
| Ошибка синхронизации | Последняя попытка не удалась. Скачивания продолжают работать, а обработчик сам повторяет попытки |
Когда синхронизация остановилась, страница говорит, почему, и что делать дальше, и показывает команду, которая это исправляет, если такая есть, например новый ключ после того, как источник отклонил старый. Тексты соответствуют кодам ошибок.
Если консоль подключена к зеркалируемому репозиторию, она также показывает значок над каталогом: Зеркало, Зеркало · синхронизация или Зеркало · ошибка синхронизации. Пока синхронизация остановлена, под ним видны причина и следующий шаг, а значок следит за сервером без перезагрузки страницы. Откройте справку значка (Об этом зеркале), чтобы увидеть источник и время последней синхронизации. В зеркалируемом репозитории консоль скрывает кнопки загрузки и изменения.
В API
getRepositoryMirror возвращает состояние репозитория. Для него нужно право читать репозиторий. Для обычного репозитория ответ — 404.
| Поле | Значение |
|---|---|
mode | mirror или import |
phase | pending (обработчик не начал), seeding (первичное заполнение) или following |
caughtUp | true, если сохранённая позиция равна самой новой позиции источника. null до конца первичного заполнения |
checkedAt, syncedAt | Когда обработчик последний раз читал поток изменений и когда он последний раз догнал источник |
copiedArtifacts, copiedBytes | Итоги копирования на сейчас (copiedBytes — десятичная строка) |
conflicts | Отложенные записи источника: count, oldestAt и до 10 записей в sample. См. Отложенные записи |
errorCode, errorAt | Последний сбой шага или null |
Коды ошибок
errorCode | Значение и что делать |
|---|---|
mirror_mismatch | У одного и того же ID артефакта на источнике другое содержимое. Зеркало оставляет свой файл. Изучите артефакт; не удаляйте ни одну из копий, пока не узнаете причину |
mirror_source_changed | В репозитории уже есть копия другого источника. Отключите его или зеркалируйте новый источник в новый репозиторий |
mirror_source_behind | Источник восстановлен или установлен заново: изменение на позиции зеркала не то, которое оно там применило. Зеркало читает источник заново, и код сбрасывается, когда оно догонит. Файлы, которых нет на восстановленном источнике, остаются на зеркале |
mirror_delete_blocked | Источник удалил файл, который зеркало удалить не может, потому что здесь его ещё что-то использует, например ссылка или история пути к файлу |
mirror_detached | Репозиторий был отключён и содержит собственные изменения. Он больше никогда не синхронизируется. Зеркалируйте источник в новый репозиторий |
mirror_package_conflict | Версия источника содержит версию пакета, которую этот репозиторий хранит с другими байтами. Запись откладывается, а синхронизация продолжается: см. Отложенные записи. Прежние выпуски здесь останавливались |
mirror_id_taken | Артефакт источника хранится в другом репозитории этой установки. Запись откладывается, см. Отложенные записи; в изменении тегов образов, объектов Git LFS или пакетов npm синхронизация останавливается. Один репозиторий источника может заполнять здесь только один репозиторий |
mirror_unreachable | Источник недоступен: соединение отклонено или прервано по тайм-ауту либо имя не разрешается. Обработчик сам повторяет попытки. Проверьте сеть, межсетевой экран и что источник работает |
mirror_certificate | Сертификат источника не доверенный, просрочен или не соответствует его имени. Добавьте его центр сертификации через --mirror-ca-file (см. HTTPS со своим центром сертификации) |
mirror_failed | Сбой без более точного кода. Прочитайте журнал обработчика |
| другие коды | Код неудавшегося запроса: unauthorized, когда источник больше не принимает ключ (выдайте зеркалу новый), forbidden, когда ключу нельзя читать репозиторий, not_found, когда репозитория на источнике больше нет, capacity_exceeded, когда зеркало заполнено |
В журнале обработчика (component равен mirror) бывают строки mirror.started, mirror.step_failed с errorCode и attempts, mirror.recovered и mirror.stopped.
Отложенные записи
Некоторые изменения источника нельзя применить здесь, не сломав то, что здесь уже есть. Обработчик откладывает такую запись и продолжает остальные изменения, поэтому одна версия не задерживает все последующие. Ничего не пропускается молча: каждая отложенная запись видна, пока её не разрешат.
| Код | Что это значит | Что делать |
|---|---|---|
mirror_package_conflict | У версии есть версия пакета (группа, имя и версия), которую этот репозиторий хранит с другими байтами. Клиенты по-прежнему получают версию, которая есть здесь; скопированный файл остаётся без регистрации пакета | Снимите стадию или удалите версию на источнике либо опубликуйте её под другой версией. При импорте можно также удалить версию здесь |
mirror_id_taken | ID артефакта хранит другой репозиторий этой установки | Один репозиторий источника заполняет здесь один репозиторий. Отсоедините другое зеркало или импорт либо удалите другую копию |
- Обработчик повторяет каждую запись через 10 минут после последней попытки, не больше 8 записей каждый раз, когда догнал источник. Запись удаляется, когда применилась или когда её больше нет на источнике: версию там удалили или, для импорта, сняли её стадию.
- В состоянии есть
conflicts: сколько записей отложено, когда отложена самая старая, и до 10 записей с ID артефакта, изменением (actionиdetail), кодом, первой и последней попыткой и числом попыток. - Консоль показывает их число на странице Зеркала и под значком репозитория. Состояние не меняется: остальное продолжает синхронизироваться.
- В журнале обработчика —
mirror.conflict_set_aside(warning, сartifactId,action,errorCodeиattempts) при каждой неудачной попытке иmirror.conflict_resolved, когда запись удалена. - Метрика
arkvory_mirror_conflictsсчитает их, правилоArkvoryMirrorConflictsпредупреждает, если они есть 30 минут.
Изменения тегов и манифестов образов, объектов Git LFS и пакетов npm никогда не откладываются: важен их порядок, и применённое позже изменение могло бы отменить более новое. Конфликт в них останавливает синхронизацию со своим кодом, пока его не разрешат.
Мониторинг зеркал
API установки-зеркала предоставляет четыре метрики для каждого зеркалируемого репозитория с метками repository и mode:
arkvory_mirror_last_sync_timestamp_seconds: время, когда зеркало последний раз догнало источник.arkvory_mirror_last_check_timestamp_seconds: время, когда оно последний раз читало поток изменений.arkvory_mirror_failing: 1, пока последняя попытка не удалась; но не пока зеркало заново читает восстановленный источник (mirror_source_behind).arkvory_mirror_conflicts: число отложенных записей.
Готовые правила Prometheus — ArkvoryMirrorStale (зеркало не догоняло источник больше часа, в течение 15 минут) и ArkvoryMirrorFailing (сбой длится 15 минут). См. Мониторинг. У зеркала, до которого обработчик ещё не добрался, времени синхронизации нет, поэтому правило устаревания не срабатывает до первой синхронизации. ArkvoryMirrorConflicts предупреждает, когда записи остаются отложенными 30 минут.
Импорт по стадии
С параметром --mirror-stages репозиторий на второй установке не зеркало. Это обычный репозиторий с правом записи, который принимает версии, имеющие на источнике одну из указанных стадий. Так можно переносить сборки с сервера разработки на рабочий сервер.
sudo arkvory configure --root /opt/proanima-arkvory \
--mirror releases --mirror-upstream https://dev.example \
--mirror-token-file /root/dev.key --mirror-stages release- Укажите от 1 до 16 разных имён стадий через запятую.
- Версия копируется один раз, с тем же ID, теми же байтами, метками и регистрацией UPack и с соответствующими стадиями.
- После этого она принадлежит этой установке. Изменения, снятие стадий и удаление на источнике до неё не доходят. Версия, которую вы удалили здесь, больше не импортируется. Стадия, которую вы сняли здесь, остаётся снятой. Если источник позже назначит версии другую настроенную стадию, добавляется только эта стадия.
- Загрузки и политика хранения репозитория работают как обычно.
- Данные реестров образов контейнеров, Git LFS и npm не переносятся.
- Изменение стадий запускает новое первичное заполнение. Оно приносит только версии, которых здесь ещё нет, а имеющиеся оставляет как есть.
- Версия источника, версию пакета которой этот репозиторий уже хранит с другими байтами, откладывается с
mirror_package_conflict, а импорт продолжается со следующими версиями. Клиенты продолжают получать версию, которая есть здесь. См. Отложенные записи.
Две установки могут импортировать друг из друга. Например, рабочая установка берёт release с тестовой, а тестовая берёт hotfix с рабочей. Версия сохраняет свой ID на обеих сторонах, поэтому ничего не копируется дважды и не ходит по кругу:
- Версия, созданная на тестовой установке и вернувшаяся с рабочей, получает только новую стадию.
- Версия, удалённая на одной стороне, больше никогда не импортируется с другой, даже если другая сторона позже назначит ей стадию.
- Удаление никогда не передаётся: другая сторона хранит свою копию, пока вы не удалите её и там.
Используйте разные стадии для двух направлений. Если в обоих направлениях одна и та же стадия, стадия, которую вы сняли на одной стороне, вернётся, когда другая сторона снова назначит её этой версии.
Консоль показывает значок Импорт или Импорт · ошибка синхронизации, если последняя попытка не удалась. Ключу на источнике нужны те же права только на чтение, что и для зеркала.
Переключение на зеркало при потере источника
Это ручное переключение для двух независимых установок на двух площадках. Автоматического переключения нет. Изменения, которые зеркало ещё не забрало, теряются.
Подготовьтесь заранее
- Установите вторую площадку, по возможности того же выпуска, что и источник, со своим PostgreSQL и своим диском. У двух площадок нет общих ресурсов.
- Создайте на источнике ключ только для чтения и подключите каждый репозиторий как зеркало. Репозиторий, созданный на источнике позже, сам на зеркале не появится, поэтому подключите его так же.
- На зеркале выпустите ключи, которые будут использовать ваши потребители, в том числе ключи с правом записи на случай переключения. Права источника не переносятся, поэтому скомпрометированный источник не даёт доступа к зеркалу.
- Настройте потребителей (CI, агенты развёртывания) так, чтобы адрес зеркала был у них запасным для скачивания. Это заодно снимает нагрузку с канала к источнику.
- Делайте резервные копии источника в хранилище копий вне его площадки. См. Резервные копии. Зеркало их не заменяет.
- Следите за зеркалом по правилам выше.
Переключение
Убедитесь, что источник действительно недоступен для клиентов и сам не вернётся. Две площадки, обе принимающие запись в один логический репозиторий, потом нельзя слить. Если источник доступен частично, остановите его службы или закройте его порт.
На зеркале прочитайте
syncedAtкаждого репозитория. Изменений на источнике после этого времени на зеркале нет.Отключите каждый зеркалируемый репозиторий на зеркале. Он станет обычным репозиторием с правом записи, с теми же ID артефактов и всеми данными.
bashsudo arkvory configure --root /opt/proanima-arkvory --mirror-detach releases,prodПеречислите несколько репозиториев через запятую или укажите
allдля всех зеркал и импортов. Команда один раз перезапускает API и обработчик, поэтому ожидайте короткого перерыва.Направьте клиентов, которые пишут, на зеркало через DNS или настройки вашего CI.
Загрузите на зеркало контрольный файл и скачайте его.
Что видят клиенты:
- До переключения скачивания с зеркала работают, а запись возвращает 409
mirror_read_only. - После отключения запись работает. Значок исчезает.
- Ключи и пароли источника на зеркале не действуют, если вы не создали там те же учётные записи.
Пути назад нет. Отключённый репозиторий нельзя снова подключить как зеркало: его синхронизация останавливается с mirror_detached. Чтобы вернуть старый источник, очистите его или установите заново и подключите репозитории нового основного сервера как зеркала. Никогда не запускайте старый источник и новый основной сервер одновременно с включённой записью.
Репетиция
Репетируйте переключение каждый квартал и после обновлений. Отключите один репозиторий на запасной копии, проверьте syncedAt, скачивание и загрузку и запишите дату и результат. Восстановление резервной копии источника в пустую установку проверяйте отдельно. См. Регулярно проверяйте восстановление.
Ограничения
- Зеркало доступно только для чтения, пока вы его не отключите. Отключённый репозиторий нельзя снова сделать зеркалом.
- Зеркало — не резервная копия. У него нет копии учётных записей, ключей и прав доступа, и оно не копирует ссылки, вложения, журналы аудита и политики хранения.
- Режим импорта не копирует образы контейнеров и данные Git LFS и npm.
- Новое первичное заполнение только добавляет и обновляет: после восстановления источника файлы, которые источник потерял, остаются на зеркале.
- Один репозиторий источника заполняет один репозиторий установки: ID артефактов на обеих сторонах одинаковы, поэтому второе зеркало или импорт из него отклоняется при настройке. По той же причине две установки, которые импортируют друг из друга, должны использовать одно и то же имя репозитория на обеих сторонах: версию, пришедшую с другой стороны, нельзя взять здесь в другой репозиторий, и она откладывается с
mirror_id_taken. - Версия, версия пакета которой здесь уже хранится с другими байтами, копируется, после чего откладывается с
mirror_package_conflict. Копия остаётся в репозитории без регистрации пакета, пока вы её не удалите. - Отложенной записи здесь нет, пока её не разрешат. Конфликт в изменении тегов образов, объектов Git LFS или пакетов npm по-прежнему останавливает синхронизацию.
- После восстановления установки зеркала из резервной копии версии, которые были импортированы и удалены после создания этой копии, могут быть импортированы снова.
- Обе установки обновляются независимо друг от друга. Источник должен поддерживать поток изменений для зеркал.
- Набор доверенных центров сертификации источника действует для всего обработчика.
- Нет автоматического переключения, изоляции старого источника и обратной синхронизации.