Образы контейнеров
Каждый репозиторий Arkvory одновременно служит реестром контейнеров. Docker, Podman, Buildx, containerd, Helm и ORAS отправляют в него данные и забирают их по протоколу OCI Distribution. Слои образов и манифесты хранятся как обычные артефакты. Права на репозиторий, квоты, проверки SHA-256, резервные копии и зеркала действуют для них так же, как для любого другого файла.
Прежде чем начать
Вам понадобятся:
- Адрес сервера с HTTPS и доверенным сертификатом, например
arkvory.example. См. HTTPS. - Репозиторий, например
releases. - Ключ: персональный токен доступа или ключ сервиса. См. Учётные записи и ключи.
Реестр отвечает в корне хоста, по адресу /v2/. Он не может работать под префиксом пути, например https://example.com/arkvory/, потому что Docker такие префиксы не поддерживает. Обратный прокси-сервер должен передавать /v2/ без изменений и не должен буферизовать тела запросов. В nginx задайте client_max_body_size 0 и отключите буферизацию запросов.
Имена образов
Ссылка на образ имеет такой вид:
<хост>/<репозиторий>/<образ>:<тег>
<хост>/<репозиторий>/<образ>@sha256:<дайджест>Первый сегмент пути — это репозиторий Arkvory. Он служит границей доступа: ключ видит только те репозитории, к которым ему выдан доступ. Остальное — имя образа из одного или нескольких компонентов.
| Ссылка | Репозиторий | Образ | Часть ссылки |
|---|---|---|---|
arkvory.example/releases/web:1.4 | releases | web | тег 1.4 |
arkvory.example/releases/team/web:1.4 | releases | team/web | тег 1.4 |
arkvory.example/qa/tools/builder@sha256:… | qa | tools/builder | дайджест |
| Часть | Правило |
|---|---|
| Репозиторий | Строчные латинские буквы, цифры, _ и -. Начинается с буквы или цифры. До 64 символов. |
| Образ | Компоненты, разделённые /. Компонент состоит из строчных латинских букв и цифр, соединённых ., _, __ или дефисами. Всего до 200 символов. |
| Тег | Буквы, цифры, _, . и -. Начинается с буквы, цифры или _. До 128 символов. |
| Дайджест | sha256: и 64 строчные шестнадцатеричные цифры. Другие алгоритмы отклоняются. |
Ссылка без части с именем образа, например arkvory.example/web:1.4, отклоняется с ошибкой NAME_INVALID: web принимается за репозиторий, а имя образа остаётся пустым.
Вход
Реестр принимает ключ Arkvory как пароль при аутентификации HTTP Basic. Имя пользователя не проверяется: используйте любое имя, например название задания CI. Запрос может также передавать ключ как Authorization: Bearer <ключ>. Отдельная служба токенов не нужна.
docker login arkvory.example -u ci --password-stdin < ~/.arkvory/keyGet-Content C:\Private\arkvory.key | docker login arkvory.example -u ci --password-stdinОстальные клиенты входят так же:
podman login arkvory.example -u ci --password-stdin < ~/.arkvory/key
helm registry login arkvory.example -u ci --password-stdin < ~/.arkvory/key
oras login arkvory.example -u ci --password-stdin < ~/.arkvory/key| Ключ | Для чего |
|---|---|
Персональный токен доступа, область read | Скачивание (pull) на рабочей станции |
Персональный токен доступа, область read-write | Отправка (push) с рабочей станции |
| Ключ сервиса | CI/CD и агенты развёртывания. Единственный вид ключа, который может удалять образы. |
| Файловый ключ из файла ключей сервера | Владелец установки и прежние интеграции (read или write) |
Персональный токен истекает. После этого каждый запрос получает 401 UNAUTHORIZED: создайте новый токен и войдите снова. Docker сохраняет ключ в ~/.docker/config.json, если не настроен помощник учётных данных. Защитите этот файл или используйте хранилище учётных данных.
Push и pull
docker tag web:1.4 arkvory.example/releases/team/web:1.4
docker push arkvory.example/releases/team/web:1.4
docker pull arkvory.example/releases/team/web:1.4
docker pull arkvory.example/releases/team/web@sha256:<дайджест>Что делает реестр:
- Слой, который уже есть в репозитории, не сохраняется повторно, даже если его использует другой образ.
- Слои не используются совместно разными репозиториями. Запрос на подключение (mount) слоя из другого репозитория получает обычную сессию загрузки, поэтому клиент отправляет слой заново.
- Каждый слой и каждый манифест проверяется по дайджесту SHA-256. При несовпадении ничего не сохраняется, а в ответ приходит
DIGEST_INVALID. - Манифест принимается, только если всё, на что он ссылается, уже есть в репозитории: конфигурация и слои образа или платформенные манифесты индекса. Платформенные манифесты должны находиться в том же образе, что и их индекс. Иначе ответ —
MANIFEST_BLOB_UNKNOWN. - Скачивание слоёв поддерживает запросы
Range.
Реестр принимает такие типы манифестов:
| Тип носителя (media type) | Для чего |
|---|---|
application/vnd.oci.image.manifest.v1+json | Образы OCI, чарты Helm, артефакты ORAS |
application/vnd.oci.image.index.v1+json | Мультиплатформенные образы, кэш реестра BuildKit |
application/vnd.docker.distribution.manifest.v2+json | Образы Docker (schema 2) |
application/vnd.docker.distribution.manifest.list.v2+json | Мультиплатформенные образы Docker |
У манифеста schemaVersion: 2, и его размер не превышает 4 МиБ. Docker schema 1 не поддерживается. Тип берётся из заголовка Content-Type или из поля mediaType манифеста, и они должны совпадать. Pull возвращает манифест в точности таким, каким его отправили (push), с его собственным типом носителя. Реестр не преобразует форматы друг в друга.
Мультиплатформенные образы
docker buildx build --platform linux/amd64,linux/arm64 \
-t arkvory.example/releases/team/web:1.4 --push .Buildx отправляет каждый платформенный манифест по его дайджесту, затем индекс под тегом. Все они попадают в одно имя образа, как того требует реестр.
Кэш сборки
Сборщик BuildKit, который умеет экспортировать кэш, например сборщик docker buildx с драйвером docker-container, может хранить свой кэш реестра в Arkvory:
docker buildx build \
--cache-from type=registry,ref=arkvory.example/releases/team/web:cache \
--cache-to type=registry,ref=arkvory.example/releases/team/web:cache,mode=max \
-t arkvory.example/releases/team/web:1.4 --push .Индекс кэша перечисляет слои и конфигурацию кэша. Arkvory хранит их как блобы образа и защищает так же, как слои любого сохранённого манифеста.
Чарты Helm
Helm хранит чарты как артефакты OCI. После helm registry login:
helm push web-1.4.0.tgz oci://arkvory.example/releases/charts
helm pull oci://arkvory.example/releases/charts/web --version 1.4.0
helm install web oci://arkvory.example/releases/charts/web --version 1.4.0Чарт становится образом charts/web с тегом 1.4.0 в репозитории releases. Классического репозитория чартов с файлом index.yaml в Arkvory нет.
Артефакты ORAS
ORAS хранит любые файлы как слои манифеста OCI:
oras push arkvory.example/releases/tools/settings:1.0 ./settings.json:application/json
oras pull arkvory.example/releases/tools/settings:1.0Referrers API недоступен: /v2/<имя>/referrers/<дайджест> отвечает 404. Клиенты, которые следуют спецификации OCI, например ORAS, тогда хранят присоединённые артефакты под тегами, названными по дайджесту.
Теги и дайджесты
- Отправка манифеста под тегом перемещает тег. Манифест, на который тег указывал раньше, остаётся в реестре, и его по-прежнему можно скачать по дайджесту.
- Отправка по дайджесту (
PUT /v2/<имя>/manifests/sha256:…) сохраняет манифест без тега. Дайджест должен быть SHA-256 тела запроса. - Теги перечисляются в порядке байтов, поэтому прописные буквы идут перед строчными.
Получите список тегов образа:
curl -fsS -u "ci:$ARKVORY_KEY" https://arkvory.example/v2/releases/team/web/tags/listОтвет — {"name": "releases/team/web", "tags": [...]}. Параметр n задаёт размер страницы (по умолчанию 100, не более 1000), а last — последний тег предыдущей страницы. Если тегов больше, заголовок Link содержит адрес следующей страницы.
Узнайте дайджест тега:
curl -fsSI -u "ci:$ARKVORY_KEY" \
https://arkvory.example/v2/releases/team/web/manifests/1.4 | grep -i docker-content-digestКаталога всех образов (/v2/_catalog) нет. В консоли слои и манифесты видны среди артефактов репозитория с меткой oci и названы по своему дайджесту. Чтобы показать их, используйте Фильтр по метке в разделе Артефакты.
Удаление образов и освобождение места
Образы удаляются через API реестра. В командной строке Docker для этого нет команды: используйте curl, oras manifest delete или другой инструмент для работы с реестром.
| Запрос | Действие |
|---|---|
DELETE /v2/<имя>/manifests/<тег> | Удаляет только тег. Манифест остаётся, его можно скачать по дайджесту. |
DELETE /v2/<имя>/manifests/<дайджест> | Удаляет манифест и каждый тег, который на него указывает |
DELETE /v2/<имя>/blobs/<дайджест> | Отклоняется с кодом 405. Слои уходят вместе со своими манифестами. |
Для обоих видов удаления нужен ключ сервиса с действием artifact.delete в репозитории. Персональные токены, сессии консоли и файловые ключи удалять образы не могут. Удаление отвечает кодом 202.
curl -fsS -X DELETE -H "Authorization: Bearer $ARKVORY_CLEANUP_KEY" \
https://arkvory.example/v2/releases/team/web/manifests/sha256:<дайджест>Как освобождается место:
- Пока манифест хранится, с тегом или без него, Arkvory защищает его и каждый слой, на который он ссылается. Правила хранения пропускают их с причиной блокировки
reference. - Перемещение или удаление тега ничего не освобождает. Старые манифесты сохраняют свои слои, пока вы не удалите эти манифесты по дайджесту.
- После удаления манифеста по дайджесту его артефакт и слои, которые не использует ни один другой манифест, теряют эту защиту. Они остаются в хранилище, пока их не удалят правила хранения или пока кто-то не удалит их как артефакты. См. Хранение.
- Слой, отправленный без манифеста, например при неудачном push, не защищён.
- Если удалённый слой снова понадобится, реестр сообщит, что он неизвестен, и следующий push загрузит его заново.
Права
Персональные токены и файловые ключи получают доступ к репозиторию на чтение или на запись. Ключи сервисов получают точные действия.
| Операция | Действия ключа сервиса | Персональный токен или файловый ключ |
|---|---|---|
| Скачивание манифестов и слоёв (pull) | content.read | Доступ на чтение |
| Список тегов | artifact.list | Доступ на чтение |
| Отправка (push) | upload.create, upload.write, upload.complete | Доступ на запись; токену нужна область read-write |
| Удаление тега или манифеста | artifact.delete | Невозможно |
Ключ CI, который отправляет образы, обычно и скачивает их, например базовые образы или кэш сборки. Дайте ему также content.read и artifact.list. Репозиторий, к которому у ключа нет доступа, отвечает 403 DENIED.
Шлюзы чтения и зеркала
- Шлюз чтения обслуживает pull. Push получает
405. - Зеркало получает образы своего источника вместе с их тегами и удалениями. Клиенты скачивают образы с зеркала по его собственному адресу. Push получает
409 DENIEDс причинойmirror_read_only.
Ограничения
| Ограничение | Значение |
|---|---|
| Размер манифеста | 4 МиБ |
| Размер слоя | Наибольший объект установки, ARKVORY_MAX_OBJECT_BYTES (по умолчанию около 10 ТиБ) |
| Один запрос загрузки | Должен завершиться за 30 минут и не должен простаивать более 30 секунд (ARKVORY_UPLOAD_DEADLINE_MS, ARKVORY_UPLOAD_IDLE_TIMEOUT_MS). 30 минут — это также наибольшее допустимое значение. |
| Незавершённая загрузка | Удаляется вместе с байтами после 24 часов без активности |
| Временное место на диске | До удвоенного размера слоя во время загрузки |
| Одновременные загрузки | По умолчанию 1 на ключ и 2 на сервер (ARKVORY_MAX_UPLOADS_PER_PRINCIPAL, ARKVORY_MAX_UPLOADS). Ожидающий запрос сдаётся через 20 секунд (ARKVORY_TRANSFER_QUEUE_TIMEOUT_MS). |
| Одновременные скачивания | По умолчанию 4 на ключ и 16 на сервер |
| Тегов на странице | 1000 |
| Квота | Слои, манифесты и байты незавершённых загрузок учитываются в квоте репозитория и в ёмкости установки |
Docker отправляет каждый слой одним запросом. Поэтому слой должен прийти в пределах срока загрузки, а неудачная загрузка слоя начинается заново с первого байта. Для файлов размером во много гигабайт используйте вместо этого arkvoryctl: он загружает файл по частям и продолжает после сбоя. Переменные описаны в разделе Переменные окружения.
Что не поддерживается
- Referrers API. Он отвечает
404, и клиенты переходят на теги. - Каталог всех образов,
/v2/_catalog. - Подключение (mount) слоёв из другого репозитория. Клиент загружает слой заново.
- Служба токенов для токенов Bearer. Отправляйте сам ключ через Basic или Bearer.
- Кэш pull-through для Docker Hub и других реестров.
- Манифесты Docker schema 1 и дайджесты, отличные от
sha256. - Удаление отдельных слоёв.
- Раздел для образов в консоли.
Обычный HTTP для тестов
Docker отказывается работать с реестром без HTTPS. По умолчанию по обычному HTTP работают только адреса локального компьютера (localhost, 127.0.0.0/8). Для тестового сервера на другом хосте добавьте его в insecure-registries в конфигурации демона Docker (/etc/docker/daemon.json в Linux) и перезапустите Docker:
{
"insecure-registries": ["arkvory.test:8080"]
}В Podman для этого служит параметр --tls-verify=false. По обычному HTTP ключ передаётся открытым текстом. Используйте это только в тестовой сети.
Для сертификата от вашего собственного центра сертификации Docker в Linux читает сертификат центра из /etc/docker/certs.d/<хост>/ca.crt (с портом, если он не 443). Docker Desktop использует хранилище доверенных сертификатов системы.
Устранение неполадок
Docker выводит коды ошибок реестра строчными буквами и с пробелами, например denied или name invalid, а за ними — сообщение сервера. У каждой ошибки есть также ID запроса в detail.requestId. Передайте его администратору: по нему запрос находят в журнале сервера.
| Ошибка | Причина | Что делать |
|---|---|---|
UNAUTHORIZED (401) | Ключ отсутствует, неверен, истёк или отозван | Войдите снова с действующим ключом |
DENIED (403) | Ключ не может писать или не видит репозиторий. Токен с областью read получает «Read-only personal access token». | Используйте ключ с доступом на запись в этот репозиторий |
DENIED (409) | Репозиторий является зеркалом | Отправляйте образы на основной сервер |
DENIED (507) | Достигнута квота репозитория или ёмкость установки. Незавершённые загрузки тоже учитываются. | Освободите место или попросите увеличить квоту |
NAME_INVALID | В ссылке после репозитория нет части с именем образа или в ней есть прописные буквы | Используйте <хост>/<репозиторий>/<образ>:<тег> строчными буквами |
MANIFEST_UNKNOWN | Тега или дайджеста нет в этом образе | Проверьте имя через tags/list |
MANIFEST_BLOB_UNKNOWN | Манифест ссылается на слой или платформенный манифест, которых нет в этом репозитории | Отправьте образ целиком ещё раз, чтобы клиент загрузил недостающие части |
DIGEST_INVALID | Байты не совпадают с дайджестом | Повторите push. Если ошибка повторяется, проверьте прокси-сервер. |
TOOMANYREQUESTS (503 или 429) | Слишком много одновременных передач этого ключа или сервер занят | Подождите и повторите. Уменьшите число параллельных загрузок клиента, например "max-concurrent-uploads": 1 в конфигурации демона Docker, или попросите администратора поднять лимиты передач. |
http: server gave HTTP response to HTTPS client | На сервере нет HTTPS | Настройте HTTPS или используйте insecure-registries для тестового сервера |
x509: certificate signed by unknown authority | Docker не доверяет сертификату | Установите сертификат центра сертификации, как описано выше |
413 Request Entity Too Large | Обратный прокси-сервер ограничивает размер запроса | Задайте client_max_body_size 0 в nginx |
| Большой слой останавливается через 30 минут | Срок загрузки одного запроса | Используйте более быструю сеть или не кладите такие файлы в образы, а загружайте их через arkvoryctl |