Docker Hub
Last Updated: February 25, 2026
Overview
Docker Hub is the world's largest container image registry and the default registry for the Docker CLI. It serves as a central repository for both public and private container images, hosting millions of images including official images from software vendors, verified publisher images, and community-contributed content.
Plans and Features
| Feature | Free | Pro | Team | Business |
|---|---|---|---|---|
| Price | $0 | $5/month | $9/user/month | $24/user/month |
| Private Repositories | 1 | Unlimited | Unlimited | Unlimited |
| Teams | - | - | Unlimited | Unlimited |
| Parallel Builds | 1 | 5 | 15 | Unlimited |
| Build Minutes | - | Included | Included | Included |
| Vulnerability Scanning | Limited | Yes | Yes | Yes |
| SSO/SAML | - | - | - | Yes |
| Audit Logs | - | - | - | Yes |
| Image Access Management | - | - | - | Yes |
Rate Limits
Docker Hub enforces pull rate limits to ensure fair usage:
| User Type | Rate Limit | Reset Period |
|---|---|---|
| Anonymous | 100 pulls | 6 hours |
| Authenticated (Free) | 200 pulls | 6 hours |
| Authenticated (Pro) | 5,000 pulls | 24 hours |
| Authenticated (Team) | 50,000 pulls | 24 hours |
| Authenticated (Business) | Unlimited | - |
Rate limits are based on your source IP address for anonymous pulls, or your Docker Hub account for authenticated pulls. In Kubernetes environments, all nodes sharing an IP (behind NAT) share the same rate limit quota.
Using Docker Hub with Kubernetes
Creating Image Pull Secrets
To pull private images from Docker Hub, create a Kubernetes Secret:
# Create docker-registry secret
kubectl create secret docker-registry dockerhub-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<your-username> \
--docker-password=<your-password-or-token> \
--docker-email=<your-email> \
-n <namespace>Using a Personal Access Token (recommended over password):
# Generate a Personal Access Token at https://hub.docker.com/settings/security
kubectl create secret docker-registry dockerhub-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=myuser \
--docker-password=dckr_pat_xxxxxxxxxxxx \
-n defaultUsing Secrets in Pods
Reference the secret in your Pod specification:
apiVersion: v1
kind: Pod
metadata:
name: private-app
spec:
containers:
- name: app
image: myusername/private-app:v1.0.0
imagePullSecrets:
- name: dockerhub-secretServiceAccount Integration
Attach image pull secrets to a ServiceAccount for automatic injection:
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: default
imagePullSecrets:
- name: dockerhub-secretNow any Pod using this ServiceAccount automatically uses the Docker Hub credentials:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
serviceAccountName: app-service-account
containers:
- name: app
image: myusername/private-app:v1.0.0Namespace-Wide Secret Distribution
For multi-namespace clusters, automate secret distribution:
# Using Kubernetes Replicator or similar controller
apiVersion: v1
kind: Secret
metadata:
name: dockerhub-secret
namespace: default
annotations:
replicator.v1.mittwald.de/replicate-to: "staging,production,dev-*"
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-config>Rate Limit Mitigation Strategies
Strategy 1: Pull-Through Cache with Harbor
Deploy Harbor as a proxy cache to reduce Docker Hub pulls:
# Harbor values.yaml excerpt
proxy:
httpProxy: ""
httpsProxy: ""
noProxy: 127.0.0.1,localhost,.local,.internal
# After Harbor deployment, configure a proxy cache project
# pointing to https://registry-1.docker.ioConfigure containerd to use Harbor as a mirror:
# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://harbor.internal.example.com/v2/dockerhub-cache/"]Strategy 2: Registry Mirror with Distribution
Deploy the CNCF Distribution registry as a pull-through cache:
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry-mirror
spec:
replicas: 1
selector:
matchLabels:
app: registry-mirror
template:
metadata:
labels:
app: registry-mirror
spec:
containers:
- name: registry
image: registry:2
ports:
- containerPort: 5000
env:
- name: REGISTRY_PROXY_REMOTEURL
value: "https://registry-1.docker.io"
- name: REGISTRY_PROXY_USERNAME
valueFrom:
secretKeyRef:
name: dockerhub-creds
key: username
- name: REGISTRY_PROXY_PASSWORD
valueFrom:
secretKeyRef:
name: dockerhub-creds
key: password
volumeMounts:
- name: cache-storage
mountPath: /var/lib/registry
volumes:
- name: cache-storage
persistentVolumeClaim:
claimName: registry-cache-pvc
---
apiVersion: v1
kind: Service
metadata:
name: registry-mirror
spec:
selector:
app: registry-mirror
ports:
- port: 5000
targetPort: 5000Strategy 3: Amazon ECR Pull-Through Cache
If running on AWS, use ECR's pull-through cache feature:
# Create pull-through cache rule for Docker Hub
aws ecr create-pull-through-cache-rule \
--ecr-repository-prefix docker-hub \
--upstream-registry-url registry-1.docker.io \
--credential-arn arn:aws:secretsmanager:us-east-1:123456789012:secret:dockerhub-creds
# Pull images through ECR
# Original: docker.io/library/nginx:latest
# Via ECR: 123456789012.dkr.ecr.us-east-1.amazonaws.com/docker-hub/library/nginx:latestStrategy 4: Pre-Pull Images to Nodes
For predictable workloads, pre-pull images using a DaemonSet:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: image-prepuller
spec:
selector:
matchLabels:
app: image-prepuller
template:
metadata:
labels:
app: image-prepuller
spec:
initContainers:
- name: prepull-nginx
image: nginx:1.25
command: ['sh', '-c', 'echo Image pulled']
- name: prepull-redis
image: redis:7
command: ['sh', '-c', 'echo Image pulled']
containers:
- name: pause
image: gcr.io/google-containers/pause:3.2
imagePullSecrets:
- name: dockerhub-secretAutomated Builds
Docker Hub can automatically build images when you push code to GitHub or GitLab.
Setting Up Automated Builds
- Link your GitHub/GitLab account in Docker Hub settings
- Create a repository and connect it to a source repository
- Configure build rules:
# Example build rules configuration
Source Type: Branch
Source: main
Docker Tag: latest
Dockerfile location: /Dockerfile
Build Context: /
Source Type: Tag
Source: /^v[0-9.]+$/
Docker Tag: {sourceref}
Dockerfile location: /Dockerfile
Build Context: /Build Hooks
Customize builds with hook scripts in your repository:
# hooks/build - Custom build script
#!/bin/bash
docker build \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VCS_REF=$(git rev-parse --short HEAD) \
-t $IMAGE_NAME .# hooks/post_push - Run after successful push
#!/bin/bash
# Tag with additional tags
docker tag $IMAGE_NAME $DOCKER_REPO:$SOURCE_COMMIT
docker push $DOCKER_REPO:$SOURCE_COMMITLimitations of Docker Hub Automated Builds
- Build minutes are limited based on plan
- No support for multi-architecture builds (use GitHub Actions instead)
- Build logs retained for limited time
- No caching between builds (slow builds)
- Cannot access private dependencies easily
Recommendation: For production CI/CD, use GitHub Actions or GitLab CI with docker/build-push-action instead of Docker Hub Automated Builds.
Public Image Security Considerations
Supply Chain Attack Vectors
Public images from Docker Hub can introduce security risks:
- Typosquatting: Malicious images with names similar to popular ones
- Compromised Maintainer Accounts: Legitimate images taken over by attackers
- Embedded Malware: Cryptominers, backdoors, or data exfiltration code
- Vulnerable Base Images: Outdated images with known CVEs
- Bloated Images: Unnecessary packages increasing attack surface
Identifying Trusted Images
| Image Type | Indicator | Trust Level |
|---|---|---|
| Docker Official Images | "Docker Official Image" badge | High |
| Verified Publisher | "Verified Publisher" badge, checkmark | High |
| Sponsored OSS | "Sponsored OSS" label | Medium-High |
| Community Images | No badge | Verify manually |
Docker Official Images
Official images are curated by Docker and maintained by dedicated teams:
# Official images use the library/ namespace (often omitted)
docker pull nginx # Same as docker.io/library/nginx
docker pull postgres:15 # Same as docker.io/library/postgres:15Characteristics of Official Images:
- Clear documentation and Dockerfile transparency
- Regular security updates
- Best practice Dockerfile patterns
- Multi-architecture support
- Minimal base images
Verified Publishers
Verified Publishers are organizations validated by Docker:
# Verified publisher images include the organization namespace
docker pull bitnami/postgresql:15
docker pull grafana/grafana:10.0.0
docker pull datadog/agent:7Security Scanning Best Practices
Always scan public images before deployment:
# Using Trivy (recommended)
trivy image nginx:latest
# Using Docker Scout (Docker Desktop)
docker scout cves nginx:latest
# Using Grype
grype nginx:latestImplement admission control to enforce scanning:
# Example Kyverno policy to require scanned images
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-image-scan
spec:
validationFailureAction: Enforce
rules:
- name: check-image-scan
match:
resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "*"
attestations:
- predicateType: https://cosign.sigstore.dev/attestation/vuln/v1
conditions:
- all:
- key: "{{ scanner }}"
operator: Equals
value: "trivy"Recommendations for Public Images
Pin to Specific Digests (not just tags):
yaml# Avoid image: nginx:latest # Better image: nginx:1.25.3 # Best (immutable) image: nginx@sha256:a484819eb60211f5299034ac80f...Mirror to Private Registry:
bash# Pull, scan, and push to your private registry docker pull nginx:1.25.3 trivy image nginx:1.25.3 --exit-code 1 docker tag nginx:1.25.3 myregistry.com/library/nginx:1.25.3 docker push myregistry.com/library/nginx:1.25.3Use Distroless or Minimal Base Images:
dockerfile# Instead of full OS base images FROM gcr.io/distroless/static-debian12 # or FROM cgr.dev/chainguard/static:latest
Docker Hub API Usage
Authentication
# Get authentication token
TOKEN=$(curl -s -H "Content-Type: application/json" \
-X POST -d '{"username": "'${DOCKER_USER}'", "password": "'${DOCKER_PASS}'"}' \
https://hub.docker.com/v2/users/login/ | jq -r .token)List Repositories
# List your repositories
curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://hub.docker.com/v2/repositories/${DOCKER_USER}/?page_size=100" | jq '.results[].name'List Tags
# List tags for a repository
curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://hub.docker.com/v2/repositories/${DOCKER_USER}/${REPO}/tags/?page_size=100" | jq '.results[] | {name: .name, size: .full_size, updated: .last_updated}'Delete Tags (Cleanup Script)
#!/bin/bash
# Delete old tags keeping the last N
DOCKER_USER="myuser"
REPO="myapp"
KEEP_COUNT=10
TOKEN=$(curl -s -H "Content-Type: application/json" \
-X POST -d '{"username": "'${DOCKER_USER}'", "password": "'${DOCKER_PASS}'"}' \
https://hub.docker.com/v2/users/login/ | jq -r .token)
# Get all tags sorted by date (oldest first)
TAGS=$(curl -s -H "Authorization: Bearer ${TOKEN}" \
"https://hub.docker.com/v2/repositories/${DOCKER_USER}/${REPO}/tags/?page_size=100&ordering=last_updated" \
| jq -r '.results[].name')
TAG_COUNT=$(echo "$TAGS" | wc -l)
DELETE_COUNT=$((TAG_COUNT - KEEP_COUNT))
if [ $DELETE_COUNT -gt 0 ]; then
echo "Deleting $DELETE_COUNT old tags..."
echo "$TAGS" | head -n $DELETE_COUNT | while read TAG; do
echo "Deleting tag: $TAG"
curl -s -X DELETE -H "Authorization: Bearer ${TOKEN}" \
"https://hub.docker.com/v2/repositories/${DOCKER_USER}/${REPO}/tags/${TAG}/"
done
fiCheck Rate Limit Status
# Check your current rate limit status
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
curl -s -I -H "Authorization: Bearer $TOKEN" \
https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest 2>&1 | grep -i ratelimit
# Example output:
# ratelimit-limit: 100;w=21600
# ratelimit-remaining: 95;w=21600Best Practices
1. Authentication and Access
- Use Personal Access Tokens instead of passwords
- Rotate tokens regularly (every 90 days recommended)
- Use read-only tokens for CI/CD pull operations
- Enable 2FA on Docker Hub accounts
- For teams, use organization-level access management
2. Image Management
- Use specific tags, never
latestin production - Implement a consistent tagging strategy (SemVer recommended)
- Regularly clean up old/unused tags
- Document image dependencies and update procedures
3. Security
- Scan all images before deployment
- Prefer Official Images and Verified Publishers
- Mirror critical images to your private registry
- Implement admission controllers to enforce policies
- Review Dockerfiles for security issues
4. Performance and Reliability
- Implement registry mirroring/caching for production clusters
- Monitor rate limit usage
- Use authenticated pulls even for public images (higher limits)
- Pre-pull images for predictable deployments
5. CI/CD Integration
- Use GitHub Actions or GitLab CI for builds (more features than Docker Hub Automated Builds)
- Implement multi-stage builds for smaller images
- Cache layers effectively to speed up builds
- Sign images for supply chain security
Summary
Docker Hub remains the most widely used container registry, especially for open-source and development use cases. While its rate limits and security considerations require attention, proper configuration of authentication, caching, and scanning can make it a reliable part of your Kubernetes infrastructure.
For production workloads requiring higher reliability or stricter security controls, consider:
- Amazon ECR for AWS-native environments
- Harbor for self-hosted, air-gap, or multi-cloud scenarios
- Docker Hub Business for enterprise features with the convenience of SaaS
Key takeaways:
- Always authenticate to increase rate limits
- Implement pull-through caching for production clusters
- Trust but verify: scan all public images
- Use Official Images and Verified Publishers when possible
- Consider hybrid approaches: Docker Hub for base images, private registry for your applications