Як 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. Споживачі тягнуть звідки хочуть.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів