Передача образов через registry
Локальный image можно запустить на текущем Engine, но для передачи другому разработчику нужен понятный способ доставки. В этом уроке опишем публикацию API и веб-клиента через registry и зафиксируем договор выпуска. Результат — точные имена двух образов, реестр фактических сведений и понимание того, что не переносится вместе с image.
Registry хранит images; он не превращает их в работающий сайт автоматически. Токен, repository, сборки и доступ к сети создаёт читатель в своём окружении. При написании серии автор не выполнял login, push, pull или размещение. Команды ниже являются ожидаемым сценарием самостоятельного повторения, а не сообщением о состоявшейся публикации.
Подготовим передаваемые материалы
Для API нужен обычный Dockerfile, а для клиента — multi-stage Dockerfile из предыдущего урока. У frontend должен существовать настоящий package-lock.json, полученный читателем. Dev-image с watcher и подключением исходников не выбираем в качестве релиза статического клиента: его роль связана с рабочей папкой и инструментами разработки.
После собственной успешной сборки compose.prod.yaml локальные образы имеют имена professorweb-container-lab-api:release-01 и professorweb-container-lab-web:release-01. Сначала прочитайте их список и подтвердите, что они относятся к текущим исходникам. Если build не завершился, наличие старого такого же тега не доказывает наличие новой версии. Подготовка выпуска должна связывать исходное состояние и конкретное содержимое image.
Манифест, lockfile и digest базовых images относятся к воспроизводимости. Пока выбраны изменяемые node:24-bookworm-slim и nginx:stable-alpine, повторная сборка позднее может получить обновлённую основу. Это не повод отказаться от обновлений, но их нужно различать с намеренным изменением собственного кода. Не записываем придуманный digest ради красивого реестра.
Выберем namespace и repository
В публичном registry имя обычно включает namespace владельца и repository. Для двух сервисов полезно использовать разные repositories: catalog-api и catalog-web могут обновляться вместе по договору релиза, но остаются разными images. Пользователь registry должен иметь право записи в выбранное место; совпадение текста namespace с чьим-то аккаунтом не даёт такого права.
В командах ниже замените YOUR_NAMESPACE собственным действительным namespace. Переменная содержит имя, а не пароль. Не публикуйте значение токена в статье, исходниках или shell-истории как часть команды. Для Docker Hub можно выполнить login с явно выбранным именем и ввести подходящий токен по запросу. Поддерживаемые способы и хранение учётных данных описаны в официальном справочнике docker login.
PW_DOCKER_NAMESPACE='YOUR_NAMESPACE'
docker login --username "$PW_DOCKER_NAMESPACE"
docker image tag professorweb-container-lab-api:release-01 "$PW_DOCKER_NAMESPACE/professorweb-catalog-api:release-01"
docker image tag professorweb-container-lab-web:release-01 "$PW_DOCKER_NAMESPACE/professorweb-catalog-web:release-01"
Tag даёт существующему image подходящее имя для registry. Он не собирает новый клиент и не меняет файлы API. Если namespace, image или версия перепутаны, исправлять нужно эти сведения до push. Успешный login также не доказывает право записи в произвольный repository; авторизация и адрес назначения являются разными условиями.
| Сведение | Что фиксирует | Где получить действительное значение |
|---|---|---|
| Namespace/repository | Адрес передаваемого image | Из собственного выбранного registry |
| Релизный tag | Человеческое имя версии | Из принятой политики проекта |
| Digest | Конкретное содержимое | Из фактической публикации или полученного image |
| Platform | Совместимую архитектуру | Из результата своей сборки и inspect |
| Backup каталога | Отдельные пользовательские данные | Из отдельной процедуры хранения |
Выполним отдельную операцию push
Когда читатель намеренно готов опубликовать выбранные материалы, выполняются две отдельные операции. Их последствия зависят от доступности repository, его публичности и правил registry.
docker image push "$PW_DOCKER_NAMESPACE/professorweb-catalog-api:release-01"
docker image push "$PW_DOCKER_NAMESPACE/professorweb-catalog-web:release-01"
Ожидается загрузка нужных слоёв и фактическая ссылка на результат. Возможность повторного использования уже существующих слоёв не является гарантированным временем передачи. Не переносим цифры из другого проекта в прогноз нашего. Правила команды, включая выбор тегов, приведены в справочнике image push.
Перед публикацией нужно знать состав image. .dockerignore помог ограничить входы, но он не проверяет самостоятельно смысл каждого файла. Подготовленные JSON-данные содержат только публичные учебные записи. Настоящие секреты, приватная база и сохранённые документы не должны оказаться в публичном image под видом удобной начальной конфигурации.
Проверим передачу без удаления всего окружения
После самостоятельной публикации другой Engine с подходящей платформой может получить images через pull. Не требуется предварительно удалять все локальные контейнеры и volumes, чтобы доказать возможность передачи. Достаточно отдельного понятного окружения или чтения фактических references и результата получения.
docker image pull "$PW_DOCKER_NAMESPACE/professorweb-catalog-api:release-01"
docker image inspect "$PW_DOCKER_NAMESPACE/professorweb-catalog-api:release-01" --format '{{json .RepoDigests}}'
Содержимое RepoDigests читатель записывает только из своего результата. Тег release-01 при разрешённой перезаписи repository может позднее указать на другой image. Digest помогает назвать конкретное содержимое, однако не доказывает сам по себе безопасность программы или успешность HTTP-сценариев. Для релизов нужна понятная политика обновления тегов, проверки и происхождение сборки.
Процессорная архитектура также не исчезает. Image, собранный на ARM-компьютере, не следует без проверки обещать совместимым с любым сервером x86. Базовый официальный image может иметь несколько платформ, но собственная сборка и её manifest требуют отдельного решения. Возможность buildx и multi-platform выпуска можно изучать дальше; в этом курсе такой выпуск не выполнялся и не объявляется готовым.
Заполним реестр только наблюдениями
В корне проекта добавьте release-record.json. Это полный начальный редакционный файл. Null означает отсутствующее наблюдение, а не пустую успешно завершённую публикацию.
{
"execution": "not_run",
"api": {
"tag": null,
"digest": null,
"platform": null
},
"frontend": {
"tag": null,
"digest": null,
"platform": null
},
"catalog_backup": null,
"reader_created_lockfile": null,
"registry_publication": "not_run",
"real_deployment": "not_run"
}
После собственных действий читатель связывает actual tag, digest и platform с сохранённым исходником и lockfile. Отдельно отмечает получение клиента и API, их ожидаемые ответы и состояние данных. Один общий флаг «готово» скрывает слишком много разных условий: можно загрузить API и забыть frontend, либо получить оба image без volume с нужным каталогом.
Что нужно переносить отдельно
Изменённый catalog.json в named volume не входит автоматически в pushed image. Image содержит исходный fixture, а volume хранит текущее runtime-содержимое. Если второй разработчик запускает новый пустой volume, он получает начальные записи. Для действительных пользовательских данных требуется отдельная резервная копия, передача и проверка восстановления; registry такую процедуру не заменяет.
Environment, публикация портов, домен, HTTPS и права доступа также являются настройками размещения. Compose-файл помогает описать часть из них, но локальное имя проекта и loopback-порт не становятся внешним адресом сайта сами по себе. Для настоящего хоста понадобятся его условия и отдельный план выпуска с возможностью вернуться к прежнему состоянию.
Архив серии содержит только наши исходники, редакционные реестры и полные snapshots, без registry-токенов, настоящих образов и сохранённых volumes. Execution остаётся not_run. К концу курса можно объяснить каждую границу проекта: образ, экземпляр, context, публикацию порта, dev-mount, постоянные данные, статическую сборку и registry. Следующий самостоятельный шаг — подтвердить эти ожидаемые сценарии в выбранном окружении и лишь затем готовить настоящее размещение.