← назад к разделу

Вы собрали образ у себя на ноутбуке — теперь нужно, чтобы он оказался на сервере. Реестр образов — это именно то место, через которое образ переезжает с одной машины на другую, и откуда CI берёт и кладёт образы автоматически.

Что такое реестр образов

Реестр образов (registry) — это хранилище Docker-образов, доступное по сети. Принцип тот же, что у репозитория git: вы отправляете (push) образ в реестр, а потом скачиваете (pull) его на любой машине — локально, на сервере, в Kubernetes.

Самые распространённые реестры:

  • Docker Hub (hub.docker.com) — публичный реестр по умолчанию. Бесплатный для публичных образов; приватные — ограничены на бесплатном тарифе. Когда вы пишете docker pull nginx, Docker идёт именно туда.
  • GitHub Container Registry (ghcr.io) — реестр от GitHub, удобен, если код уже там. Права управляются через токены GitHub.
  • Приватные реестры — можно поднять собственный (например, через registry:2 или Harbor) или использовать реестр облачного провайдера (Amazon ECR, Google Artifact Registry, Yandex Container Registry).

Все они работают по единому протоколу — OCI Distribution Spec, поэтому команды docker push / docker pull одинаковы вне зависимости от реестра.

Именование образов и теги

Полное имя образа выглядит так:

<реестр>/<пространство-имён>/<имя>:<тег>

Несколько примеров:

nginx:1.27                         # Docker Hub, официальный образ
myuser/myapp:latest                # Docker Hub, пользовательский образ
ghcr.io/myorg/backend:v1.4.2      # GitHub Container Registry
registry.company.ru/team/api:sha-abc1234  # приватный реестр

Если реестр не указан — Docker Hub. Если тег не указан — latest.

Тег — это просто метка на конкретный слой образа. Теги изменяемы: latest сегодня и latest через неделю могут указывать на разные образы. Поэтому latest удобен для разработки, но опасен в продакшне.

Стратегия тегов

Хаотичное именование — источник головной боли: непонятно, что задеплоено, сложно откатиться, трудно проследить, из какого коммита образ собран.

Три устойчивые стратегии:

1. Семантическое версионирование (semver)

myapp:1.4.2
myapp:1.4
myapp:1

Понятно людям, поддерживает «плавающие» теги (1.4 → всегда последний патч-релиз). Подходит для библиотек и публичных образов.

2. Git SHA коммита

myapp:sha-abc1234f

Однозначно привязывает образ к исходному коду. Невозможно перезаписать случайно. Рекомендуется как основной тег в CI — всегда знаете, из какого коммита собрано.

3. Комбинированный

myapp:1.4.2          # для релизного тега
myapp:sha-abc1234f   # для точного отслеживания

Можно ставить оба тега на один образ.

Короткая формула: в продакшне никогда не используйте latest — только версионированный или sha-тег.

docker tag, push и pull

Прежде чем отправить образ в реестр — войдите в него:

docker login ghcr.io -u USERNAME --password-stdin <<< "$GITHUB_TOKEN"

Образ тегируется командой docker tag:

# сначала собираем
docker build -t backend:local .

# добавляем «адрес» для реестра
docker tag backend:local ghcr.io/myorg/backend:sha-abc1234f
docker tag backend:local ghcr.io/myorg/backend:v1.4.2

Отправляем:

docker push ghcr.io/myorg/backend:sha-abc1234f
docker push ghcr.io/myorg/backend:v1.4.2

Скачиваем на другой машине:

docker pull ghcr.io/myorg/backend:sha-abc1234f

Один образ (один набор слоёв) может иметь сколько угодно тегов — это дёшево: теги — просто указатели, данные не дублируются.

Сборка и публикация в CI

Ручная сборка и push — это хорошо для экспериментов. В реальном проекте образ собирается автоматически при каждом пуше в основную ветку или при создании тега релиза.

Общая схема конвейера:

Код → git push → CI запускается → docker build → docker tag → docker push → (развёртывание)

Пример конфигурации для GitHub Actions (.github/workflows/build.yml):

name: Сборка и публикация образа

on:
  push:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write          # нужно для публикации в ghcr.io

    steps:
      - uses: actions/checkout@v4

      - name: Войти в GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Собрать образ и опубликовать
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

Что здесь происходит:

  1. При пуше в main запускается задание.
  2. CI входит в реестр с помощью автоматического токена GITHUB_TOKEN.
  3. Образ собирается из Dockerfile в корне репозитория.
  4. Присваиваются два тега: sha коммита (стабильный) и latest (для удобства при разработке).
  5. Образ отправляется в реестр.

В реальном проекте рядом обычно идёт следующий шаг — обновление манифеста Kubernetes или вызов kubectl rollout restart, но это уже выходит за пределы Docker как инструмента сборки.

Немного про многоэтапную сборку и размер образа

Если вы используете многоэтапную сборку (multi-stage build), CI ничего особенного делать не должен — docker build сам разберётся. Для Spring Boot это выглядит так: в первом этапе компилируете jar, во втором — копируете только его поверх базового eclipse-temurin:21-jre. В реестр попадает только финальный, лёгкий образ.

# --- этап сборки ---
FROM eclipse-temurin:21-jdk AS build
WORKDIR /app
COPY . .
RUN ./gradlew bootJar -x test

# --- финальный образ ---
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /app/build/libs/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

Такой образ занимает 200–300 МБ вместо 600+ МБ с полным JDK — и именно он уйдёт в реестр.

Коротко

  • Реестр образов — хранилище, через которое образ переезжает между машинами; самые популярные: Docker Hub, GitHub Container Registry, приватные реестры облачных провайдеров.
  • Полное имя образа: <реестр>/<пространство-имён>/<имя>:<тег>; без реестра — Docker Hub, без тега — latest.
  • В продакшне используйте конкретный тег (semver или sha коммита), а не latest — иначе непонятно, что именно задеплоено.
  • docker tag добавляет новый указатель на уже собранный образ; данные не копируются.
  • Конвейер CI: build → tag → push; следующий шаг — развёртывание (Kubernetes, systemd, Compose на сервере).
  • В GitHub Actions GITHUB_TOKEN достаточно для публикации в ghcr.io — дополнительные секреты не нужны.

Что почитать дальше

  • Многоэтапная сборка и слои образа — как устроены слои, почему порядок инструкций влияет на размер и скорость сборки.
  • Лучшие практики образов — безопасность, минимальный базовый образ, непривилегированный пользователь.
  • Запуск Spring Boot в Docker — полный пример: Dockerfile, конфигурация JVM, профили Spring.