Як push і pull images на Docker Hub?
Push і pull image на Docker Hub це базовий workflow для sharing'у image: тегуєш image зі своїм namespace, логінишся один раз, пушиш, потім тягнеш звідки завгодно.
Теорія
TL;DR
- Чотири команди покривають 99 відсотків кейсів:
docker login,docker tag,docker push,docker pull. - Формат імені image:
<namespace>/<repo>:<tag>, де<namespace>це твій Docker Hub username або організація. Без префіксу означає «офіційнийlibrarynamespace», туди ти запушити не можеш. - Автентифікація через personal access token (PAT), не пароль акаунту. PAT обмежують scope (read-only / read-write / read-write-delete) і чисто revoke'аються.
- Credentials лежать у
~/.docker/config.jsonпісляdocker login. На macOS / Windows за credential helper. - Публічні репо: необмежена кількість, безкоштовно. Приватні поза free tier потребують платний план. Анонімні pull rate-лімітовані (100 на 6 годин на IP); автентифіковані вищі.
Швидкий приклад
# 1. Збираємо локальний image
$ docker build -t myapp:1.0 .
# 2. Тегуємо зі своїм Docker Hub namespace
$ docker tag myapp:1.0 youruser/myapp:1.0
# 3. Автентифікуємось (один раз, до logout)
$ docker login -u youruser
Password: **** # сюди paste PAT, не пароль акаунту
Login Succeeded
# 4. Push
$ docker push youruser/myapp:1.0
The push refers to repository [docker.io/youruser/myapp]
adc4d6e8f1c2: Pushed
8a3f2d1c9b8e: Pushed
1.0: digest: sha256:9f8e7d6c... size: 1247
# З іншої машини
$ docker pull youruser/myapp:1.0Ось повний цикл. Build, tag, login, push, потім pull з будь-якого хоста, де встановлений Docker.
Іменування і тегування image
Повна форма для Docker Hub: [docker.io/]<namespace>/<repo>:<tag>.
docker.io/це неявний дефолтний registry. Майже ніколи не пишеш.<namespace>= твій Docker Hub username або організація, до якої ти належиш.<repo>= ім'я репозиторію. Створюється автоматично при першому push.<tag>= мітка цього білду (v1.0,2026-04-30,pr-1247,latest). Дефолтlatest, якщо не вказати.
Приклади:
youruser/myapp:1.0 # особистий namespace, version tag
mycompany/api:2026-04-30 # org namespace, date tag
mycompany/api # неявно :latest, уникай для проду
nginx:1.27 # офіційний library/nginx, library/ неявнийКоманда docker tag не рухає байти; вона лише додає ім'я, що вказує на той самий image ID. Один image може мати багато tag.
Автентифікація: PAT, не пароль
Docker Hub підтримує два способи логіну:
# Старий спосіб, пароль акаунту (працює, але погана практика)
$ docker login -u youruser
Password: <пароль акаунту>
# Сучасний спосіб, personal access token
$ docker login -u youruser
Password: <paste PAT з https://hub.docker.com/settings/security>PAT дають тобі:
- Scope токена (read-only / read-write / read-write-delete-public-repo).
- Revoke без зміни паролю акаунту.
- Використовувати кілька токенів на машину (CI runner, лептоп, сервер) і ротувати незалежно.
У CI токени тримають як repository secrets. Ніколи не комітимо токен у git, ніколи не вставляємо в Dockerfile.
Де лежать credentials
Після docker login credentials лягають у ~/.docker/config.json:
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "base64(username:PAT)"
}
}
}На macOS і Windows Docker використовує OS keychain (credsStore: osxkeychain, desktop), файл лише вказує на keychain, не на сирий токен. Linux без credential helper зберігає base64-токен прямо у файлі. chmod 600 ~/.docker/config.json, якщо так робиш.
Типові помилки
Push без префіксу namespace
# НЕПРАВИЛЬНО: намагається запушити в офіційний library/
$ docker push myapp:1.0
requested access to the resource is denied
# ПРАВИЛЬНО: включай свій namespace
$ docker tag myapp:1.0 youruser/myapp:1.0
$ docker push youruser/myapp:1.0Повідомлення про помилку безкорисне; причина завжди відсутній namespace.
Логін під паролем акаунту замість PAT
$ docker login -u youruser
Password: <пароль акаунту>
Login SucceededПрацює, але якщо твій пароль зливається, зловмисник отримує повний доступ до акаунту. PAT лімітує радіус ураження і revoke'ається окремо.
Запушити :latest і забути запушити версійний tag
# НЕПРАВИЛЬНО: тільки :latest нагорі
$ docker tag myapp:1.0 youruser/myapp:latest
$ docker push youruser/myapp:latest
# ПРАВИЛЬНО: push обидва, щоб люди могли пінитися на конкретну версію
$ docker tag myapp:1.0 youruser/myapp:1.0
$ docker tag myapp:1.0 youruser/myapp:latest
$ docker push youruser/myapp:1.0
$ docker push youruser/myapp:latest
# Або одним махом: docker push --all-tags youruser/myappЯкщо споживачі можуть тягти тільки :latest, вони не можуть пінитися на конкретну версію, і одного дня твій :latest їх здивує.
Натрапити на rate limit анонімного pull у CI
ERROR: toomanyrequests: You have reached your pull rate limit.
Docker Hub rate-лімітує анонімні IP до 100 pull на 6 годин, а спільний CI IP може спалити це швидко. Автентифікуй CI runner (docker login з токеном) або тягни через registry mirror (Google Artifact Registry, AWS ECR pull-through cache).
Реальне застосування
- GitHub Actions:
docker/login-action@v3читає username + PAT з secrets, потімdocker/build-push-action@v5будує і пушить в одному кроці. Стандартний патерн у тисячах репо. - Локальний лептоп → спільне dev-середовище: запушив свій бранч-image у приватне репо Docker Hub, твій колега робить
docker pullі запускає без rebuild. - Open-source дистрибуція: інструменти типу
tini,diveі багато CLI публікують свої офіційні image на Docker Hub під verified-publisher namespace. - CI/CD пайплайни у менших командах: PR-білди, тегнуті як
myapp:pr-1247, пушаться у приватне Docker Hub репо, staging-середовище їх тягне, інтеграційні тести бігають.
Питання для поглиблення
Q: Яка різниця між docker push і docker push --all-tags?
A: Звичайний docker push youruser/myapp:1.0 пушить один tag. docker push --all-tags youruser/myapp пушить кожен локальний tag того репозиторію. Корисно, коли ти позначив той самий image і версією, і latest.
Q: Як запушити приватний image?
A: Ті самі команди. Repo створюється при першому push; його visibility ставиш як private з web UI Docker Hub (або через API). Free акаунти Docker Hub включають одне приватне репо; більше потребує платного плану.
Q: Чи можна запушити image для кількох архітектур (amd64 + arm64)?
A: Так, через docker buildx. docker buildx build --platform linux/amd64,linux/arm64 -t youruser/myapp:1.0 --push . будує обидві архітектури і заливає їх як manifest list під одним tag. Споживачі автоматично тягнуть правильну для свого CPU.
Q: Як видалити image з Docker Hub?
A: Видалення tag з web UI або через curl проти Docker Hub API з PAT, що має delete scope. Немає docker delete-tag CLI. Видалення репозиторію теж тільки через web UI.
Q: (Senior) Як уникнути вшивання push-credentials у CI-логи і історію?
A: Використовуй офіційний login action (docker/login-action), що читає з masked secrets і ніколи їх не echo'їть. Для self-hosted CI передавай токен через --password-stdin: echo $DOCKER_TOKEN | docker login -u $DOCKER_USER --password-stdin. Ніколи не використовуй docker login -u user -p $TOKEN, це кладе токен у shell history і process listing (ps aux показав би його під час виклику).
Приклади
Push з GitHub Actions workflow
name: build-and-push
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: |
youruser/myapp:latest
youruser/myapp:${{ github.sha }}Кожен push у main дає image, тегнутий latest і commit SHA. Прод-деплої пінься на SHA-tag для відтворюваності.
Rate limit'и pull у CI, фікс
# Симптом: build job падає
ERROR: toomanyrequests: You have reached your pull rate limit.
# Фікс у твоєму CI: логінься перед будь-яким pull
- name: Docker login
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build
run: docker build -t myapp .Автентифіковані pull мають значно вищий ліміт. Сам login-крок безкоштовний.
Push того самого image у два registry
# Тегуємо раз, пушимо двічі, корисно для надлишковості або міграції
$ docker build -t myapp:1.0 .
$ docker tag myapp:1.0 youruser/myapp:1.0
$ docker tag myapp:1.0 ghcr.io/youruser/myapp:1.0
$ docker login docker.io
$ docker push youruser/myapp:1.0
$ docker login ghcr.io
$ docker push ghcr.io/youruser/myapp:1.0Ті самі байти image, два registry, два namespaces. Споживачі тягнуть звідки хочуть.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.