Загрузка Docker-образа в реестр - это три последовательных шага: аутентификация, тегирование и пуш. Без любого из них образ не окажется в целевом репозитории. Эта инструкция проведёт вас через каждый этап для публичных и частных реестров, покажет типичные ошибки и способы их устранения, а также даст проверенный метод валидации загруженного образа через сравнение digest.
Материал построен на практическом опыте работы с Docker Hub, Harbor, AWS ECR и GitLab Container Registry. Все команды проверены на актуальных версиях Docker Engine 26+ и containerd. Если вы уже сталкивались с ошибками denied: requested access to the resource is denied или repository does not exist - сразу переходите к разделу типичных ошибок, там дан чёткий алгоритм исправления.
Подготовка к загрузке: аутентификация в реестре
Docker не примет пуш без предварительного входа в реестр. Исключение - локальный демон, сконфигурированный для работы с insecure-реестром без авторизации, но такой сценарий допустим только в изолированных dev-средах. Во всех остальных случаях первое действие - docker login.
Учётные данные передаются через stdin, файл или внешний credentials store. Прямая передача пароля в командной строке через --password небезопасна: пароль остаётся в истории shell и виден в списке процессов. Используйте --password-stdin:
echo "$DOCKER_PASSWORD" | docker login -u username --password-stdin
Docker хранит учётные данные в зашифрованном виде в ~/.docker/config.json. Для продакшен-сред настройте внешний credentials store - docker-credential-secretservice на Linux или связку с pass. Это исключает хранение секретов в открытом виде даже в зашифрованной базе Docker.
Вход в публичный реестр Docker Hub
Docker Hub - реестр по умолчанию. Если не указан адрес реестра, Docker направляет запрос именно туда. Команда входа:
docker login
Система запросит username и password. Вместо пароля от учётной записи Docker Hub настоятельно рекомендую создать персональный access token: Hub → Account Settings → Security → New Access Token. Токен можно отозвать в любой момент, не меняя основной пароль, и ограничить его права (Read, Write, Delete). Для пуша нужен минимум уровень Write.
Аутентификация в частном реестре
Для частного реестра укажите его адрес. Синтаксис:
docker login registry.example.com
Если реестр использует самоподписанный SSL-сертификат, Docker откажется подключаться. Варианта два. Первый - поместить корневой сертификат вашего CA в /etc/docker/certs.d/registry.example.com/ca.crt и перезапустить демон. Второй - добавить реестр в список небезопасных в /etc/docker/daemon.json:
{
"insecure-registries": ["registry.example.com:5000"]
}
Этот метод подходит только для тестовых сред. В production всегда настраивайте HTTPS через Let's Encrypt или корпоративный PKI. Подробнее о развёртывании приватного реестра с нуля читайте в руководстве Docker Hub и локальный реестр: работа с образами в 2026 году.
Правильное тегирование образа перед пушем
Тег - это указатель на конкретную версию образа. Docker не примет пуш, если образ не помечен тегом, который соответствует целевому репозиторию. Формат тега: [registry/]username/repository:tag. Если registry опущен, используется Docker Hub.
Команда docker tag создаёт новый указатель на существующий образ, не копируя данные слоёв:
docker tag my-app:latest username/my-app:1.0.0
После этого один и тот же образ имеет два тега: my-app:latest и username/my-app:1.0.0. При пуше Docker отправит слои один раз, но зарегистрирует оба тега в реестре, если запушить оба.
Стратегия версионирования: избегайте плавающих тегов
Полагаться только на latest опасно. Этот тег не несёт информации о версии, и при каждом новом пуше он перезаписывается. Восстановить, какой именно код был в latest неделю назад, невозможно. Рекомендую трёхуровневую стратегию:
- Семантическое версионирование:
1.2.3,1.2,1. Основной тег для production-развёртываний. - Git commit hash:
sha-a1b2c3d. Обеспечивает трассировку до конкретного коммита в репозитории исходного кода. - Метка сборки:
1.2.3-20260804или1.2.3-alpine. Уточняет дату или базовый образ.
Пример полного цикла тегирования для CI/CD:
VERSION=1.2.3
COMMIT_SHA=$(git rev-parse --short HEAD)
docker build -t app:latest .
docker tag app:latest registry.example.com/team/app:${VERSION}
docker tag app:latest registry.example.com/team/app:${VERSION}-${COMMIT_SHA}
docker tag app:latest registry.example.com/team/app:latest
Тег latest здесь используется осознанно - для dev-среды, где всегда нужен последний билд. Production-развёртывание ссылается на конкретную версию 1.2.3.
Загрузка образа в реестр: команда docker push
Синтаксис пуша повторяет формат тега:
docker push username/repository:tag
Docker выводит построчный прогресс загрузки каждого слоя. Слои, уже существующие в реестре, пропускаются - вы увидите сообщение Layer already exists. Это ключевое преимущество слоёной архитектуры: при повторных пушах передаются только изменившиеся слои.
Пример вывода успешного пуша:
The push refers to repository [docker.io/username/my-app]
5f70bf18a086: Pushed
6b5a2e39f1e2: Layer already exists
digest: sha256:a1b2c3d4e5f6... size: 528
Digest - это SHA256-хеш содержимого образа. Сохраните его. Он однозначно идентифицирует именно эту версию, независимо от тегов. Один образ может иметь несколько тегов, но digest у них будет общий.
Типичные ошибки при пуше и их решение
Ошибка: denied: requested access to the resource is denied. У вашей учётной записи нет прав на запись в репозиторий. Причины: неверный логин, протухший токен, репозиторий принадлежит другому пользователю или организации. Решение: проверьте docker logout и повторный docker login с корректными учётными данными. Убедитесь, что токен имеет права Write.
Ошибка: repository does not exist. Репозиторий не создан на стороне реестра. Docker Hub и некоторые частные реестры создают репозиторий автоматически при первом пуше, но многие (Harbor, AWS ECR, GitLab) требуют предварительного создания через UI или API. Решение: создайте репозиторий вручную и проверьте точное имя - username/repository должно совпадать с именем при тегировании, включая регистр.
Ошибка: unauthorized: authentication required. Вы не выполнили docker login для целевого реестра. Docker Hub и частные реестры требуют отдельных сессий входа. Решение: docker login registry.example.com перед пушем.
Ошибка: Get https://registry.example.com/v2/: dial tcp: i/o timeout. Сетевая недоступность реестра. Проверьте firewall, VPN, DNS-резолвинг и состояние самого сервиса реестра.
Проверка успешности загрузки и валидация образа
Пуш завершился без ошибок, но это не гарантирует целостность образа. Сбой сети на последнем слое, повреждение данных в хранилище реестра, ошибка дедупликации - редкие, но реальные сценарии. Проверьте образ одним из трёх методов.
Метод 1: повторный pull на чистом хосте. Удалите локальный образ и скачайте заново:
docker rmi username/repository:tag
docker pull username/repository:tag
Если pull проходит успешно и контейнер запускается - образ цел. Этот метод самый надёжный, но требует времени на скачивание.
Метод 2: сравнение digest локального и удалённого образа. Получите локальный digest:
docker images --digests | grep username/repository
Получите удалённый digest через манифест:
docker manifest inspect username/repository:tag | grep digest
Оба значения должны совпадать. Расхождение означает, что образ в реестре отличается от локального - либо пуш был неполным, либо тег перезаписан другой сборкой.
Использование digest для точной идентификации образа
Digest - это SHA256-хеш, вычисленный от манифеста образа. Манифест включает хеши всех слоёв, конфигурацию и метаданные. Изменение любого бита в любом слое меняет digest. Запуск контейнера по digest:
docker run username/repository@sha256:a1b2c3d4e5f6...
Этот метод исключает любую неоднозначность. Тег latest может указывать на разные образы в разное время, digest - никогда. В production-окружении всегда ссылайтесь на digest или immutable-тег (например, 1.2.3 с политикой запрета перезаписи в реестре).
Для продвинутого управления образами - удаления манифестов, настройки политик хранения и автоматической очистки - рекомендую руководство по очистке реестра образов. Оно поможет освободить гигабайты дискового пространства и навести порядок в репозиториях.
Особенности работы с частными реестрами
Частные реестры требуют явного указания адреса на каждом шаге: логин, тегирование, пуш. Опустили адрес - Docker уходит на Hub. Примеры для популярных решений:
Harbor. Поддерживает проекты, ролевую модель, сканирование уязвимостей. Адрес реестра - harbor.example.com, но тег включает имя проекта: harbor.example.com/project/repo:tag. Аутентификация через LDAP, OIDC или локальных пользователей.
AWS ECR. Аутентификация через aws ecr get-login-password. Токен живёт 12 часов, в CI/CD его получают на лету:
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
GitLab Container Registry. Привязан к проекту. Адрес - registry.gitlab.com, тег включает namespace: registry.gitlab.com/group/project/image:tag. Для аутентификации используйте GitLab CI/CD token или personal access token с правами write_registry.
Безопасность частного реестра - это HTTPS. Единственное исключение - изолированная dev-среда без доступа извне, где допустим insecure-режим. Во всех остальных случаях настройте TLS. Бесплатные сертификаты Let's Encrypt работают с любым реестром.
Автоматизация загрузки в CI/CD пайплайне
Ручной пуш годится для экспериментов. В production образы собирает и загружает CI/CD. Пример для GitLab CI:
build-and-push:
stage: deploy
image: docker:26
services:
- docker:26-dind
variables:
DOCKER_TLS_CERTDIR: ""
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
Ключевой момент - безопасность учётных данных. Никогда не хардкодьте пароли в .gitlab-ci.yml. Используйте CI/CD variables типа Variable (не File) с флагом Masked. В GitHub Actions аналогично - секреты хранятся в Settings → Secrets and variables → Actions.
Для продакшен-пайплайнов добавьте шаг сканирования уязвимостей перед пушем. Trivy, Grype или Docker Scout интегрируются в CI/CD и блокируют загрузку образа с критическими CVE. Готовые конфигурации для Jenkins, GitLab CI и GitHub Actions с проверкой лицензий и стратегиями тегирования собраны в статье Интеграция реестра образов с CI/CD пайплайнами.
Полный цикл работы с образами - от сборки и пуша до очистки устаревших версий - описан в практическом руководстве по управлению образами в реестре. Там же разобраны стратегии тегирования для крупных проектов и настройка высокодоступного реестра.