Docker Course
Docker Hub
Docker Hub is the world's largest container image registry — the place where millions of developers push their images and hundreds of thousands of official images live. You've been pulling from it since Lesson 1. This lesson shows you the other side: pushing your own images, managing repositories, and setting up the access controls that keep your private images actually private.
Knowing your way around Docker Hub professionally matters more than most developers realise. Your CI/CD pipeline authenticates to it. Your team's images live there. Your production servers pull from it. Getting the setup wrong means broken pipelines, exposed images, or rate-limited deployments at the worst possible time.
Docker Hub Repositories — Public vs Private
Everything on Docker Hub lives in a repository — a named collection of image versions identified by tags. A repository belongs to either a user account or an organisation. The full repository address is username/repository-name or orgname/repository-name.
Public repositories are free and unlimited. Anyone can pull from them without authentication. This is where open-source projects live — and where official images like nginx, postgres, and node are maintained.
Private repositories require authentication to pull. Free accounts get one private repository. Paid plans get unlimited. For teams building proprietary software, private repositories are the norm — your internal microservices should never be publicly pullable.
acmecorp/payment-api
Private · Last pushed 2 hours ago
Pulls (all time)
14,832
Stars
0
Tags
23
Tags
v2.3.1
167 MB · pushed 2h ago
v2.3.0
165 MB · pushed 3d ago
latest
167 MB · pushed 2h ago
Pushing Your First Image to Docker Hub
The scenario: You've just finished Dockerizing your order API. Your team is ready to share the image so other developers can pull it and the staging server can deploy it. You need to push it to Docker Hub under your organisation's namespace.
# Step 1 — Log in to Docker Hub
docker login
# Username: your-dockerhub-username
# Password: your-password OR access-token (recommended — see below)
# Login Succeeded
# Step 2 — Tag your local image with the full Docker Hub path
docker tag order-api:v1.0.0 acmecorp/order-api:v1.0.0
docker tag order-api:v1.0.0 acmecorp/order-api:latest
# Tag it twice — once with the version, once as latest
# The registry stores them as two tag pointers to the same image layers
# Step 3 — Push both tags
docker push acmecorp/order-api:v1.0.0
docker push acmecorp/order-api:latest
Login Succeeded The push refers to repository [docker.io/acmecorp/order-api] 3a7f2c9e1b4d: Pushed 8b1c4e7a9d2f: Pushed 5d3a1b9c7e4f: Pushed a3b7c9d1e5f2: Pushed v1.0.0: digest: sha256:7b9c3e1f5a... size: 1573 The push refers to repository [docker.io/acmecorp/order-api] 3a7f2c9e1b4d: Layer already exists 8b1c4e7a9d2f: Layer already exists 5d3a1b9c7e4f: Layer already exists a3b7c9d1e5f2: Layer already exists latest: digest: sha256:7b9c3e1f5a... size: 1573
What just happened?
The first push uploaded all four layers fresh. The second push — latest pointing to the exact same image — completed instantly because all layers already existed. Both tags have the identical digest, confirming they reference the same underlying layers. Your team can now pull acmecorp/order-api:v1.0.0 for a pinned version or acmecorp/order-api:latest for the most recent build.
Access Tokens — Never Use Your Password in CI
Using your Docker Hub password in a CI/CD pipeline is a security risk. If pipeline logs are ever exposed, your entire Docker Hub account is compromised. Access tokens are scoped, revocable credentials created specifically for automated systems — a compromised token only loses what that token was allowed to do, not your entire account.
# Generate at: hub.docker.com → Account Settings → Security → New Access Token
# Scope: "Read & Write" for CI that pushes, "Read Only" for servers that only pull
# Authenticate with a token instead of a password
echo "dckr_pat_abc123xyz..." | docker login --username acmecorp-ci --password-stdin
# --password-stdin reads the token from stdin — never pass as -p flag
# -p flags appear in shell history and process listings
# In GitHub Actions — inject from repository secrets
# echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login --username acmecorp-ci --password-stdin
Never Hardcode Credentials in Pipeline Config
Credentials hardcoded in a .github/workflows file, Jenkinsfile, or .gitlab-ci.yml are committed to source control — permanently. Even in a private repository, anyone with read access has your credentials in the git history forever. Always use CI secret management — GitHub Secrets, GitLab Variables, Jenkins Credentials — and inject at runtime.
Pulling a Private Image — Authentication Required
# Must authenticate before pulling private images
echo "dckr_pat_xyz..." | docker login --username acmecorp-deploy --password-stdin
docker pull acmecorp/order-api:v1.0.0
# In Compose — docker login on the host covers all services
docker compose pull # pulls all service images including private ones
# Unauthenticated attempt: Error response from daemon: pull access denied for acmecorp/order-api, repository does not exist or may require 'docker login' # After docker login: v1.0.0: Pulling from acmecorp/order-api 3a7f2c9e1b4d: Pull complete 8b1c4e7a9d2f: Pull complete 5d3a1b9c7e4f: Pull complete a3b7c9d1e5f2: Pull complete Status: Downloaded newer image for acmecorp/order-api:v1.0.0
What just happened?
The unauthenticated pull returned "pull access denied" — Docker Hub intentionally gives the same error whether the repository doesn't exist or you simply lack access. This prevents enumeration of private repository names. After authenticating, the pull succeeded. The Daemon caches credentials from docker login in ~/.docker/config.json — subsequent pulls from the same registry don't re-authenticate until the token expires or is revoked.
Searching Docker Hub From the CLI
docker search postgres # search for postgres images
docker search --filter is-official=true node # official images only
docker search --limit 5 redis # limit results
NAME DESCRIPTION STARS OFFICIAL postgres The PostgreSQL object-relational database... 12841 [OK] bitnami/postgresql Bitnami container image for PostgreSQL 113 postgrest/postgrest A REST API for any Postgres database 64 ankane/pgvector Open-source vector similarity search... 41 edoburu/pgbadger Tool for creating reports from PostgreSQL... 39
What just happened?
Results are ranked by star count. The [OK] in the OFFICIAL column confirms postgres is maintained by Docker in partnership with the PostgreSQL team — security-scanned, regularly updated, and the safe default choice. The others are community images — bitnami/postgresql is reputable but community-maintained. Before trusting any community image in production, check the star count, official badge, and when it was last pushed on the Docker Hub web UI — the CLI search doesn't show vulnerability scan results.
Teacher's Note
Create a dedicated CI service account on Docker Hub — never use a personal account in pipelines. When a team member leaves and their account is deleted, every pipeline that authenticated with it breaks simultaneously. A service account belongs to the organisation, not the person.
Practice Questions
1. Instead of a Docker Hub password in CI/CD pipelines, you should generate a scoped and revocable credential called a what?
2. To search Docker Hub for images matching a keyword directly from the terminal, which command do you use?
3. To pass a Docker Hub token to docker login without it appearing in shell history, which flag do you use?
Quiz
1. A developer pulls a private image without authenticating and gets "repository does not exist or may require docker login" even though the image exists. Why does Docker Hub phrase the error this way?
2. A developer pushes order-api:v1.0.0 then immediately pushes order-api:latest pointing to the same image. The second push shows Layer already exists for every layer. The reason is:
3. A team uses a developer's personal Docker Hub account in all CI pipelines. The developer leaves and their account is deleted. The correct long-term fix is:
Up Next · Lesson 30
Private Docker Registry
Docker Hub isn't always the answer — sometimes you need your own registry. Let's spin one up, secure it with TLS, and understand when running your own is the right call.