✦ For everyone, free.

Practical knowledge for real and everyday life

Home

19.1.4.1 Push Image Upload

A focused guide to Push Image Upload, connecting core concepts with practical Docker and container operations.

Push image upload covers the lower-level mechanics of how layers actually transfer to a registry, concurrent upload limits, compression applied before transmission, retry behavior for transient failures, and registry-imposed size limits, which together explain push performance and failure characteristics beyond what the basic push command's own flags reveal.

Daemon-level concurrent upload configuration

Mirroring the concurrent download limit covered for pulls, the daemon's max-concurrent-uploads setting controls how many layers upload simultaneously during a push:

{
  "max-concurrent-uploads": 5
}
systemctl restart docker

Increasing this on a host with ample upload bandwidth pushing many-layered images can improve overall push throughput, while a lower value is appropriate on a host where upload bandwidth is genuinely constrained or shared with other critical traffic that should not be starved by a large, simultaneous push.

Compression applied before transmission

Layers are compressed before being uploaded, which reduces the actual amount of data transmitted over the network at the cost of CPU time spent compressing on the way out, a trade-off generally favorable for any reasonably fast modern CPU and any network connection slower than extremely high local bandwidth:

docker push registry.example.com/my-api:1.4.2
8a1f3c9b: Pushing [=====>    ]  45MB/98MB

The progress figures shown during a push reflect the compressed transfer size, not the layer's uncompressed, on-disk size, which is worth knowing when the displayed progress numbers do not seem to match an image's locally reported, uncompressed size.

Retry behavior for transient network failures

A push experiencing a transient network interruption generally retries automatically for the specific layer that was interrupted, rather than requiring the entire push to restart from the very beginning:

docker push registry.example.com/my-api:1.4.2
8a1f3c9b: Retrying in 5 seconds

This automatic, per-layer retry behavior means a brief, transient network blip during a large push does not necessarily require manually restarting the entire operation, though a sufficiently persistent or severe connectivity issue will eventually exceed the retry budget and fail the push outright, requiring a genuine, manual retry at that point.

Registry-imposed layer and manifest size limits

Some registries impose explicit limits on individual layer size or total image size, and a push exceeding these limits fails with a registry-specific error rather than any generic, ambiguous failure:

blob upload invalid: blob upload invalid
manifest invalid: max manifest size exceeded

Checking the specific target registry's own documented limits directly, when a push fails in a way that does not point to an obvious authentication or network cause, identifies whether an oversized layer or an unusually large total manifest is the actual responsible factor, which is a meaningfully different problem than a connectivity issue and requires restructuring the image, splitting an overly large layer, for instance, rather than simply retrying.

Monitoring upload progress for very large images

For images large enough that a push takes a meaningful amount of time, watching per-layer progress directly, rather than only waiting for the overall command to eventually complete or fail, identifies specifically which layer, if any, is the actual bottleneck:

docker push registry.example.com/large-image:latest 2>&1 | tee push-log.txt

Capturing the full, verbose progress output this way provides a record useful both for monitoring an in-progress push and for later, post-hoc review if the push ultimately fails partway through, showing exactly how far it had progressed before the failure occurred.

Why pushing a previously pushed image with minor changes is fast

Because the registry checks for already-present layers before accepting an upload, pushing an updated image that shares most of its layers with a previously pushed version uploads only the genuinely new or changed layers, which is the upload-side mirror of the pull-side layer reuse behavior covered in dedicated content, explaining why a routine, small update to an already-published image typically pushes considerably faster than the image's full size might otherwise suggest.

docker push registry.example.com/my-api:1.4.3
3f29a8c1: Layer already exists
8a1f3c9b: Pushed

Common mistakes

  • Not adjusting the daemon's concurrent upload limit when push throughput genuinely needs tuning for the host's actual available bandwidth.
  • Interpreting push progress figures as reflecting uncompressed, on-disk layer size, when they actually reflect the compressed transfer size instead.
  • Manually restarting an entire push from scratch after a brief, transient network interruption, when the daemon's own automatic, per-layer retry would likely have resolved it without intervention.
  • Treating a registry size-limit failure as a generic, retryable network issue rather than recognizing it requires restructuring the image to address the specific oversized component.
  • Not capturing verbose push output for a very large, long-running push, losing the ability to review exactly how far it had progressed if it ultimately failed partway through.

Push image upload mechanics involve daemon-configurable concurrency, compression applied before transmission, automatic per-layer retry for transient failures, and registry-imposed size limits that require image restructuring rather than simple retrying, all of which together explain push performance and failure behavior beyond what the basic push command's own flags and default output alone make clear.