How to Push Image to Registry

How to Push Image to Registry Pushing a Docker image to a registry is a foundational skill in modern software development, DevOps, and cloud-native infrastructure. Whether you're deploying microservices, automating CI/CD pipelines, or managing containerized applications across environments, the ability to securely and efficiently push images to a registry ensures consistency, scalability, and repr

Nov 6, 2025 - 10:08
Nov 6, 2025 - 10:08
 0

How to Push Image to Registry

Pushing a Docker image to a registry is a foundational skill in modern software development, DevOps, and cloud-native infrastructure. Whether you're deploying microservices, automating CI/CD pipelines, or managing containerized applications across environments, the ability to securely and efficiently push images to a registry ensures consistency, scalability, and reproducibility. This guide provides a comprehensive, step-by-step walkthrough of how to push an image to a registrycovering public platforms like Docker Hub, private registries like Harbor or Amazon ECR, and enterprise solutions like Google Container Registry (GCR) or Azure Container Registry (ACR). Youll learn not only the mechanics of the push command, but also the underlying concepts, security considerations, and industry best practices that separate novice users from seasoned practitioners.

By the end of this tutorial, you will understand how to authenticate, tag, and upload container images to any major registry, troubleshoot common errors, and implement automated workflows that integrate seamlessly into your development lifecycle. This knowledge is essential for engineers working with Kubernetes, Jenkins, GitHub Actions, GitLab CI, or any modern orchestration platform that relies on container images as its deployment unit.

Step-by-Step Guide

Prerequisites

Before you begin pushing images to a registry, ensure you have the following components installed and configured:

  • Docker Engine installed on your local machine or build server. Verify installation by running docker --version.
  • A container image built locally. If you dont have one, create a simple image using a Dockerfile.
  • Access to a container registrypublic (e.g., Docker Hub) or private (e.g., AWS ECR, Google GCR, Azure ACR, Harbor).
  • Authentication credentials for the registry. This may include a username/password, access token, or IAM role.
  • Network connectivity to the registry endpoint. Some registries require specific ports or proxy configurations.

Step 1: Build Your Container Image

Before pushing, you must have a valid Docker image. Create a simple Dockerfile to illustrate the process:

FROM alpine:latest

RUN apk add --no-cache curl

COPY . /app

WORKDIR /app

CMD ["echo", "Hello from containerized app"]

Save this as Dockerfile in your project directory. Then, build the image using the docker build command:

docker build -t my-app:v1 .

The -t flag assigns a tag to the image. The format is repository-name:tag. In this case, my-app is the repository name and v1 is the version tag. The dot (.) at the end tells Docker to use the current directory as the build context.

To verify the image was built successfully, run:

docker images

You should see your image listed with the repository name, tag, image ID, creation time, and size.

Step 2: Log In to Your Registry

Most registries require authentication before you can push images. The login process varies depending on the registry provider.

Logging into Docker Hub

If youre using Docker Hub, the default public registry, authenticate with:

docker login

Youll be prompted to enter your Docker Hub username and password (or personal access token, which is recommended for security). After successful authentication, Docker stores your credentials in ~/.docker/config.json.

Logging into Amazon ECR

Amazon Elastic Container Registry (ECR) requires a temporary authentication token generated via AWS CLI. First, ensure you have the AWS CLI installed and configured with valid credentials:

aws configure

Then, retrieve the login command for your region (e.g., us-east-1):

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com

Replace 123456789012 with your AWS account ID and us-east-1 with your target region. This command retrieves a temporary password and passes it to Docker for authentication.

Logging into Google Container Registry (GCR)

For Google Cloud, use the gcloud CLI:

gcloud auth configure-docker gcr.io

This configures Docker to use your Google Cloud credentials for authentication with GCR. If you're using Artifact Registry instead of GCR, replace gcr.io with your region-specific endpoint (e.g., us-central1-docker.pkg.dev).

Logging into Azure Container Registry (ACR)

Azure requires you to enable admin access or use service principal credentials. First, ensure youre logged into the Azure CLI:

az login

Then, retrieve the login server and credentials for your registry:

az acr login --name myregistry

Replace myregistry with your ACR name. This command authenticates Docker using the registrys admin credentials or a service principal.

Logging into Harbor or Other Private Registries

For self-hosted registries like Harbor, use:

docker login your-harbor-domain.com

Enter your Harbor username and password (or API token if two-factor authentication is enabled). Ensure the registrys SSL certificate is trusted by your system or add it to your Docker daemons trusted certificate store.

Step 3: Tag Your Image for the Registry

After logging in, you must tag your local image with the full registry path. Docker uses the image name to determine where to push it. The format is:

registry-domain.com/namespace/repository:tag

For example, to push to Docker Hub:

docker tag my-app:v1 username/my-app:v1

To push to Amazon ECR:

docker tag my-app:v1 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:v1

To push to Google Artifact Registry:

docker tag my-app:v1 us-central1-docker.pkg.dev/my-project/my-repo/my-app:v1

To push to Azure Container Registry:

docker tag my-app:v1 myregistry.azurecr.io/my-app:v1

To push to Harbor:

docker tag my-app:v1 your-harbor-domain.com/myproject/my-app:v1

Use docker images again to confirm the new tagged image appears in your list. Youll now see two entries: one with the short name and one with the full registry path.

Step 4: Push the Image to the Registry

Once tagged, push the image using the docker push command:

docker push username/my-app:v1

For ECR:

docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:v1

For GCR:

docker push us-central1-docker.pkg.dev/my-project/my-repo/my-app:v1

For ACR:

docker push myregistry.azurecr.io/my-app:v1

For Harbor:

docker push your-harbor-domain.com/myproject/my-app:v1

Docker will begin uploading layers of your image. Each layer is compressed and uploaded individually. If a layer already exists on the registry (due to previous pushes), Docker skips itthis makes subsequent pushes faster and more efficient.

Upon successful upload, youll see output similar to:

The push refers to repository [username/my-app]

f5a7b9d1c3e2: Pushed

a1b2c3d4e5f6: Pushed

v1: digest: sha256:abc123def456ghi789... size: 1234

The digest is a cryptographic hash of the image manifest. It uniquely identifies your image and is critical for reproducible deployments.

Step 5: Verify the Push

After pushing, verify the image exists in the registry:

  • Docker Hub: Visit https://hub.docker.com/repositories and navigate to your repository.
  • Amazon ECR: Go to the AWS Console > ECR > Repositories and locate your image.
  • Google Artifact Registry: Use the Google Cloud Console > Artifact Registry > Repositories.
  • Azure Container Registry: Navigate to your ACR in the Azure Portal > Repositories.
  • Harbor: Log in to your Harbor UI and browse the project repository.

Alternatively, use the registrys CLI tools:

For ECR:

aws ecr list-images --repository-name my-app --region us-east-1

For GCR:

gcloud container images list-tags us-central1-docker.pkg.dev/my-project/my-repo/my-app

For ACR:

az acr repository show-tags --name myregistry --repository my-app --output table

For Harbor (via API):

curl -u username:password https://your-harbor-domain.com/v2/myproject/my-app/tags/list

These commands confirm the image exists and show its tags and metadata.

Best Practices

Use Semantic Versioning for Tags

Never use the latest tag in production unless you have a strict rollback and audit policy. Instead, adopt semantic versioning (e.g., v1.2.3, 1.2.3-beta). This ensures reproducibility and enables rollbacks. Tools like GitLab CI, GitHub Actions, or Jenkins can automatically tag images using commit hashes or Git tags.

Minimize Image Size

Smaller images reduce push/pull times and improve security by reducing the attack surface. Use multi-stage builds, choose minimal base images (e.g., alpine, distroless), and remove unnecessary files during build. For example:

FROM golang:alpine AS builder

WORKDIR /app

COPY . .

RUN go build -o myapp .

FROM alpine:latest

RUN apk --no-cache add ca-certificates

COPY --from=builder /app/myapp /usr/local/bin/myapp

CMD ["myapp"]

This reduces the final image size from hundreds of MB to under 10 MB.

Sign Images with Cosign or Notary

Image signing ensures integrity and authenticity. Use Sigstores cosign to sign your images:

cosign sign --key cosign.key your-registry.com/myapp:v1

Verify signatures during deployment:

cosign verify --key cosign.pub your-registry.com/myapp:v1

Many orchestration platforms (e.g., Kubernetes with Kyverno or OPA) can enforce signed images as a policy.

Use Digests for Immutable Deployments

Instead of referencing myapp:v1, reference the digest: myapp@sha256:abc123.... Digests are immutableonce pushed, they cannot be changed. This prevents tag mutation attacks where a malicious actor re-tags a vulnerable image as v1.

To get the digest after pushing:

docker inspect --format='{{index .RepoDigests 0}}' your-registry.com/myapp:v1

Use this digest in your Kubernetes manifests, Helm charts, or deployment scripts.

Limit Registry Access with RBAC

Never use admin credentials for automated pipelines. Create dedicated service accounts with least-privilege permissions. In ECR, use IAM policies. In ACR, use Azure RBAC roles. In Harbor, assign project-level roles (Developer, Maintainer, Guest). Rotate credentials regularly.

Scan Images for Vulnerabilities

Pushing vulnerable images defeats the purpose of containerization. Integrate image scanning into your pipeline:

  • Docker Hub: Automatic scanning for public images.
  • Trivy: Open-source scanner: trivy image your-registry.com/myapp:v1
  • Clair: Used by Harbor and GitLab.
  • Amazon Inspector: For ECR images.
  • Google Container Analysis: For GCR.

Fail builds if critical vulnerabilities are found.

Automate with CI/CD Pipelines

Manually pushing images is error-prone and unscalable. Automate with CI/CD:

GitHub Actions example:

name: Build and Push Image

on:

push:

branches: [ main ]

jobs:

build-and-push:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: docker/setup-buildx-action@v3

- uses: docker/login-action@v3

with:

registry: your-registry.com

username: ${{ secrets.REGISTRY_USERNAME }}

password: ${{ secrets.REGISTRY_PASSWORD }}

- uses: docker/build-push-action@v5

with:

context: .

file: ./Dockerfile

tags: your-registry.com/myapp:${{ github.sha }}

push: true

This pushes the image using the Git commit SHA as the tagensuring traceability and immutability.

Monitor Registry Usage and Quotas

Public registries like Docker Hub have rate limits. Private registries have storage quotas. Monitor usage with:

Set alerts for quota thresholds and implement image cleanup policies (e.g., delete images older than 30 days).

Tools and Resources

Core Tools

  • Docker CLI The standard tool for building, tagging, and pushing images.
  • Docker Buildx Enables multi-platform builds and caching. Essential for cross-architecture deployments (e.g., ARM64, AMD64).
  • Podman Docker-compatible alternative that doesnt require a daemon. Useful in rootless environments.
  • Skopeo Tool for copying images between registries without requiring Docker. Useful for air-gapped environments.
  • Oras OCI Artifact Registry client for pushing non-container artifacts (e.g., Helm charts, OPA policies).

Registry Platforms

  • Docker Hub Free tier available; best for open-source and small teams.
  • Amazon ECR Integrated with AWS services; pay-per-use pricing.
  • Google Artifact Registry Unified registry for containers, Helm, and npm; supports regional replication.
  • Azure Container Registry Deep integration with Azure Kubernetes Service (AKS).
  • Harbor Open-source, on-premises registry with vulnerability scanning, role-based access, and replication.
  • GitHub Container Registry (GHCR) Free private registry integrated with GitHub repositories.
  • GitLab Container Registry Built into GitLab CI; automatically tagged with pipeline metadata.

Security and Compliance Tools

  • Trivy Open-source vulnerability scanner with CI/CD integration.
  • Clair Static analysis tool for container images; used by Harbor and Quay.
  • Notary Legacy image signing tool (being replaced by Cosign).
  • Cosign Modern, Sigstore-based image signing and verification tool.
  • Kyverno Kubernetes policy engine that can enforce signed images and registry allowlists.
  • OPA/Gatekeeper Open Policy Agent for enforcing registry and image policies in Kubernetes.

Documentation and Learning Resources

Real Examples

Example 1: Pushing to Docker Hub from a CI Pipeline

Scenario: Youre building a Node.js microservice and want to push it to Docker Hub on every commit to the main branch.

Dockerfile:

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./

RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["node", "server.js"]

GitHub Actions Workflow:

name: Build and Push to Docker Hub

on:

push:

branches: [ main ]

jobs:

docker:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Set up Docker Buildx

uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub

uses: docker/login-action@v3

with:

username: ${{ secrets.DOCKERHUB_USERNAME }}

password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push

uses: docker/build-push-action@v5

with:

context: .

file: ./Dockerfile

tags: yourusername/my-node-app:${{ github.sha }}

push: true

After this runs, the image is pushed to yourusername/my-node-app with the Git commit SHA as the tag. You can now deploy this exact image to Kubernetes using:

image: yourusername/my-node-app:sha256:abc123...

Example 2: Pushing to ECR with AWS CodeBuild

Scenario: Youre using AWS CodeBuild to build and push images to ECR for deployment on ECS.

buildspec.yml:

version: 0.2

phases:

pre_build:

commands:

- echo Logging in to Amazon ECR...

- $(aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com)

build:

commands:

- echo Building the Docker image...

- docker build -t my-ecr-app .

post_build:

commands:

- echo Pushing the Docker image...

- docker tag my-ecr-app:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-ecr-app:latest

- docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-ecr-app:latest

- echo Push completed

This workflow integrates seamlessly with ECS task definitions and ensures your containers are always pulled from a trusted, private registry.

Example 3: Pushing to Harbor with Image Signing

Scenario: Your organization requires signed images for compliance. Youre using Harbor as your internal registry.

After building and tagging:

docker build -t harbor.company.com/project/myapp:v1 .

docker push harbor.company.com/project/myapp:v1

cosign sign --key cosign.key harbor.company.com/project/myapp:v1

Now, your Kubernetes cluster uses Kyverno to block any unsigned images:

apiVersion: kyverno.io/v1

kind: ClusterPolicy

metadata:

name: require-signed-images

spec:

rules:

- name: check-image-signature

match:

resources:

kinds:

- Pod

validate:

message: "Image must be signed with cosign"

deny:

conditions:

- key: "{{ request.object.spec.containers[].image }}"

operator: NotIn

value: ["cosign:verified"]

This ensures only signed, trusted images are deployed.

FAQs

What happens if I push an image with the same tag twice?

If you push an image with the same tag (e.g., myapp:v1) multiple times, the registry will overwrite the previous image. The digest will change, and any system referencing the old digest will no longer be able to pull it unless its retained by the registrys retention policy. Always use immutable tags (e.g., commit hashes) for production.

Can I push images without Docker installed?

Yes. Tools like buildah, podman, and skopeo can build and push images without requiring the Docker daemon. Skopeo can even copy images directly between registries (e.g., Docker Hub ? ECR) without downloading them locally.

Why is my push failing with unauthorized: authentication required?

This typically means:

  • Youre not logged in to the registry.
  • Your credentials expired (common with AWS ECR tokens).
  • Youre trying to push to a repository you dont have write access to.
  • Youre using the wrong registry URL (e.g., Docker Hub URL for ECR).

Run docker logout and re-login. Verify your registry URL and permissions.

How do I delete an image from a registry?

Most registries dont allow deletion via Docker CLI. Use the registrys native tools:

  • ECR: aws ecr delete-image --repository-name myapp --image-imageTag v1
  • ACR: az acr repository delete --name myregistry --image myapp:v1
  • Harbor: Use the UI or API to delete tags or repositories.

Be cautiousdeletion is often irreversible.

Whats the difference between a tag and a digest?

A tag is a human-readable label (e.g., v1.2.3) that can be changed or reassigned. A digest is a SHA-256 hash of the image manifest and is immutable. Use tags for development and digests for production deployments.

Can I push to multiple registries at once?

Yes. Use Docker Buildx to build and push to multiple registries in one command:

docker buildx build --push --platform linux/amd64,linux/arm64 \

-t username/myapp:v1 \

-t your-harbor-domain.com/project/myapp:v1 \

.

This builds a multi-platform image and pushes it to both Docker Hub and Harbor simultaneously.

How do I handle rate limits on Docker Hub?

Docker Hub imposes anonymous and authenticated pull limits. To avoid throttling:

  • Use a paid plan for higher limits.
  • Cache images locally or in your CI runner.
  • Use a private registry for internal images.
  • Use docker pull only when necessary in CI pipelines.

Conclusion

Pushing an image to a registry is more than a technical commandits a critical step in the modern software delivery pipeline. Mastering this process ensures your applications are deployed consistently, securely, and at scale. From choosing the right registry and tagging strategy to implementing image signing and automated pipelines, every decision impacts reliability and security.

This guide has provided a complete, practical roadmapfrom building your first image to pushing it to Docker Hub, ECR, or Harbor with best practices in mind. You now understand how to authenticate, tag, verify, and automate the push process, while avoiding common pitfalls like mutable tags, unsecured credentials, and unscanned vulnerabilities.

As container adoption continues to grow, the ability to manage images effectively will become even more essential. Whether youre a developer, DevOps engineer, or platform architect, the skills outlined here form the foundation of cloud-native operations. Implement these practices in your workflows today, and youll build systems that are not only functionalbut trustworthy, auditable, and resilient.