Добавление Docker-образа в реестр: полное практическое руководство | AdminWiki

Добавление Docker-образа в реестр: полное практическое руководство

04 августа 2026 7 мин. чтения

Загрузка 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 пайплайнами.

Полный цикл работы с образами - от сборки и пуша до очистки устаревших версий - описан в практическом руководстве по управлению образами в реестре. Там же разобраны стратегии тегирования для крупных проектов и настройка высокодоступного реестра.

Поделиться:
Сохранить гайд? В закладки браузера