Docker Registry Operations, Garbage Collection, Retention, Search, Proxying, and Production Troubleshooting: Guided Hands-On Workflow and Core Operations
Run the smallest safe registry-operations workflow: create synthetic image references, prove shared-layer and digest relationships, retire selected tags through supported interfaces, observe logical deletion before physical reclamation, inspect a proxy request, and record every state transition.
Learning objectives
- Prepare a disposable Community-compatible Docker repository topology with explicit version/runtime/database/blob assumptions.
- Push or model several synthetic tags that reuse layers and record manifest digests before cleanup.
- Retire only selected disposable content through supported Nexus/Docker APIs or UI and verify what remains.
- Run only current supported Docker cleanup/reclamation tasks on disposable blob state and distinguish logical from physical changes.
- Inspect one proxy fetch/failure path and produce a causal before/after evidence packet.
HEAD requests do not refresh an asset's
lastDownloaded timestamp. An actively used image can
therefore look inactive. Do not use Last Downloaded–based Docker
cleanup policies on an affected instance until Sonatype publishes a
fixed version.
1. Lab baseline and preflight
Reference environment: Nexus Repository 3.95.2-01, Java 21, self-hosted Community Edition, single disposable node, H2 database, file blob store, and path-based Docker routing. H2 is acceptable for this small archive-style learning instance; do not generalize it into a production design, and do not use a containerized H2 Nexus deployment where current Sonatype support rules prohibit it.
Client options: Docker or Podman for the live path; Python 3 for the deterministic fallback. If your local Docker client requires insecure-registry configuration to reach HTTP Nexus, do not weaken a production/global daemon. Reuse the trusted local TLS/reverse-proxy fixture from Chapter 17, or use the deterministic fallback for the protocol/state exercises.
ch24-docker-hosted,
ch24-docker-proxy,
learner-example/ch24-demo, tags 1.0,
1.1, stable, and evidence folder
chapter24-evidence.
2. Create or verify the disposable repositories
Use Settings → Repositories on the disposable instance. Create a
Docker hosted repository named
ch24-docker-hosted backed by the disposable file blob
store and enable path-based routing. For the proxy extension, create
ch24-docker-proxy only if you have an approved harmless
upstream fixture or are allowed to proxy a small public image. Do
not use employer credentials or a private production registry.
Before publishing anything, record repository type, blob store, routing mode, write policy, online state, and current component count. Confirm the Docker Bearer Token Realm if Docker client authentication is required.
3. Build a tiny synthetic image set with shared layers
For a live Docker engine, create this harmless build context:
FROM scratch
COPY common.txt /common.txt
COPY version.txt /version.txt
LABEL org.example.course="chapter24"
mkdir -p ch24-image
cd ch24-image
printf 'shared-layer
' > common.txt
printf 'version=1.0
' > version.txt
# Build using your approved local Docker/Podman engine.
docker build -t ch24-demo:1.0 .
printf 'version=1.1
' > version.txt
docker build -t ch24-demo:1.1 .
The two images should share at least the layer corresponding to
common.txt; exact layer construction can vary with
builder implementation. The learning objective is to observe
digest/reference relationships, not to force a specific layer count.
4. Tag and publish to the hosted repository
With trusted TLS/path routing from Chapter 17, set:
export REGISTRY_HOST='repo.example.invalid'
export HOSTED_PATH='ch24-docker-hosted/learner-example/ch24-demo'
docker tag ch24-demo:1.0 "$REGISTRY_HOST/$HOSTED_PATH:1.0"
docker tag ch24-demo:1.1 "$REGISTRY_HOST/$HOSTED_PATH:1.1"
docker tag ch24-demo:1.1 "$REGISTRY_HOST/$HOSTED_PATH:stable"
docker push "$REGISTRY_HOST/$HOSTED_PATH:1.0"
docker push "$REGISTRY_HOST/$HOSTED_PATH:1.1"
docker push "$REGISTRY_HOST/$HOSTED_PATH:stable"
Use a disposable least-privilege publisher credential through
docker login or your client credential store. Do not
put credentials in the image URL or copy
~/.docker/config.json into the evidence bundle.
5. Deterministic no-Docker fallback: model the same graph
If a trusted Docker endpoint is unavailable, the following fixture still teaches the retention/reclamation graph without pretending to modify Nexus:
import hashlib, json
from pathlib import Path
root = Path('chapter24-evidence')
root.mkdir(exist_ok=True)
def h(text): return 'sha256:' + hashlib.sha256(text.encode()).hexdigest()
common = h('common-layer')
layer10 = h('version=1.0')
layer11 = h('version=1.1')
manifest10 = h('manifest:' + common + ':' + layer10)
manifest11 = h('manifest:' + common + ':' + layer11)
state = {
'tags': {'1.0': manifest10, '1.1': manifest11, 'stable': manifest11},
'manifests': {
manifest10: {'layers':[common, layer10]},
manifest11: {'layers':[common, layer11]}
},
'blobs': [common, layer10, layer11]
}
(root/'registry-before.json').write_text(json.dumps(state, indent=2)+'\n')
print(json.dumps(state, indent=2))
This fixture is a simulation only. It must be labeled as such in your evidence packet; it does not prove a particular Nexus task executed.
6. Capture before-state evidence
For the live path, capture tags and exact digests. The
docker image inspect result shows client-side
repository digests after pull/push, while Registry API/Nexus search
shows server-side metadata.
mkdir -p ../chapter24-evidence
curl -fsS "$NEXUS_URL/service/rest/v1/search?repository=ch24-docker-hosted&format=docker" > ../chapter24-evidence/search-before.json
# Through the Docker route; authentication may require a token-aware client.
curl -fsS "$REGISTRY/v2/learner-example/ch24-demo/tags/list" > ../chapter24-evidence/tags-before.json
docker pull "$REGISTRY_HOST/$HOSTED_PATH:1.1"
docker image inspect "$REGISTRY_HOST/$HOSTED_PATH:1.1" > ../chapter24-evidence/client-inspect-1.1.json
Record the digest of 1.1 and stable. They
should resolve to the same manifest if stable was
tagged from exactly the same image.
7. Predict before deleting anything
-
Removing tag/component
1.0should not make the common layer reclaimable because1.1/stablestill reference it. -
Removing
stableshould not delete the1.1manifest if the1.1tag still references that same digest. - Physical file-blob usage may not fall immediately after logical deletion; Docker GC and blob-store compaction are separate stages.
Write the predictions in
chapter24-evidence/predictions.md before proceeding.
8. Retire one disposable tag/component through a supported interface
Use Nexus Browse/Search or the documented Components API to locate
the exact disposable component associated with tag 1.0.
Verify repository name, image name, tag, and component ID twice.
Then delete only that component through supported Nexus UI/API. Do
not construct a filesystem path and delete blob files.
# Read first. Replace the synthetic ID only after verifying it belongs to ch24-docker-hosted.
curl -fsS "$NEXUS_URL/service/rest/v1/search?repository=ch24-docker-hosted&format=docker&docker.imageName=learner-example/ch24-demo&docker.imageTag=1.0"
# Destructive action: run only against the verified disposable component ID.
# curl -fsS -X DELETE "$NEXUS_URL/service/rest/v1/components/$COMPONENT_ID"
The destructive command is intentionally commented in the course. The learner must obtain and inspect the actual disposable component ID first. Current Nexus also supports Docker Registry API deletion semantics, but operational teams should standardize one supported deletion path and understand how it maps to tags/manifests.
9. Run Docker garbage collection only after inspecting scope
Go to Settings → System → Tasks and verify that the current task
type is
Docker - Delete unused manifests and images.
Confirm it targets only ch24-docker-hosted. Run it
during this isolated lab, then capture task history/log output.
The task removes Docker tags/manifests/layers no longer referenced by tags/manifests. Sonatype explicitly warns that digest-only content can be treated as unused. The lab does not create valuable digest-only content.
10. Reclaim physical blob space separately
Inspect file blob-store usage before and after logical deletion/GC.
Then, if the blob store is used only for the disposable lab or the
exact scope is otherwise safe, run the supported
Admin - Compact blob store task for that disposable
blob store. Record the Blobs Older Than setting and
expected effect.
# Filesystem-level measurement only; do not modify blob-store files.
df -h /path/to/disposable/blob-parent
# Or use the Nexus UI/metrics for blob-store size evidence.
If the disposable repository shares a blob store with valuable content, do not run compaction merely for the lab. Use the deterministic storage fixture instead and document why compaction was skipped.
11. Proxy one harmless image—or use a local upstream fixture
The safest pattern is an approved local upstream registry containing
a tiny synthetic image. Configure ch24-docker-proxy to
that upstream, pull once through Nexus, then capture Nexus
search/asset evidence and the resolved digest. If organizational
policy permits a public demonstration, use a small benign image and
record the exact upstream/digest; never stress-test or repeatedly
pull a public registry.
For an intentional proxy failure, block or stop the local upstream fixture rather than attacking a public registry. Pull the already-cached digest/tag and an uncached tag, then compare outcomes. This distinguishes cached availability from remote reachability.
12. Interpret a proxy rate-limit response rather than hiding it
If an upstream returns 429, record response headers,
Nexus proxy logs, and whether the requested manifest/layers were
already cached. Do not bypass Nexus, rotate random credentials, or
disable policy/TLS to make the pull succeed. Production fixes
include upstream authentication, approved mirrors, cache strategy,
pull-rate planning, and build design that pins/reuses known digests.
13. Verify after-state
-
1.0no longer appears in Nexus search/tag listing. -
1.1andstablestill resolve and, if expected, share the same manifest digest. -
The common layer remains referenced while
1.1remains. - Task history shows the Docker GC result for the disposable repository.
- Compaction, if safely run, is recorded separately from logical deletion.
- The proxy test records cached-versus-uncached behavior and remote status.
- No real credential appears in logs/evidence.
14. Challenge: choose the correct control
Your team wants to keep five rollback releases but remove old CI tags. Which control should you reach for first?
Answer in your evidence notes before revealing the explanation: start with a retention design that distinguishes release tags from ephemeral tags. Current Nexus retain-last-N is a Pro/PostgreSQL feature; Community environments can still implement deliberate supported deletion/task workflows, but must not simulate Pro entitlements as if present. The Docker GC task is not the retention policy—it only cleans data that has become unreferenced.
15. Knowledge check
You deleted tag 1.0 and disk usage did not change. Name three plausible reasons.
The underlying layer is still referenced by another manifest; content is only logically/soft deleted; Docker GC and/or compact blob-store reclamation has not run yet.
Why is the Docker GC task not a replacement for a retention policy?
GC finds unreferenced manifests/layers. It does not decide business lifecycle intent such as which release tags should be preserved for rollback.
What should happen to the shared common layer after tag 1.0 is retired but 1.1 still references it?
It must remain. A referenced layer is live content even if another image that shared it was removed.
What is the safe way to simulate an upstream outage in this lab?
Stop or block a local disposable upstream registry/fixture. Do not attack, overload, or intentionally interfere with a public registry.
Why is the component-delete command commented in the lesson?
The learner must first resolve and verify the exact disposable component ID/repository/tag. This prevents copy-paste deletion against the wrong Nexus content.
16. Summary and next step
You have now observed the essential registry lifecycle: publish/tag, resolve digests, inspect shared layers, retire only intended references, clean unreferenced Docker data, and reclaim physical blob space separately. Lesson 3 turns these mechanics into design choices for production retention, proxy freshness, trust zones, routing, and maintenance windows.
Official references and version notes
- Sonatype: Docker Registry — Docker repository routing, Registry API support, manifest lists, OCI image support, and current path-based routing guidance.
- Sonatype: Repository Manager Concepts — Docker component/tag/manifest/layer relationships and storage implications.
- Sonatype: Cleanup Policies — Docker cleanup sequence, policy criteria, soft deletion, Docker GC interaction, and blob-store compaction.
- Sonatype: Tasks — current Docker GC, incomplete-upload cleanup, repository cleanup, and compact blob-store task behavior.
- Sonatype: Searching Docker — Docker client search constraints and Nexus repository/group behavior.
- Sonatype: Searching for Components — current SQL-backed Nexus search and Docker-specific image/tag/layer criteria.
- Sonatype: Search API — supported paginated search endpoints and format-specific fields.
- Sonatype: Docker Authentication — Docker Bearer Token Realm and client authentication flow.
- Sonatype: Proxy Repository for Docker — Docker Hub/private ECR proxy behavior and current upstream-authentication options.
-
Sonatype: Nexus Repository 3.95.0–3.95.2 Release Notes
— dated release line and open Docker
HEAD/lastDownloadedcleanup issue. - Sonatype: Nexus Repository 3.91.x Release Notes — Docker manifest/tag integrity and garbage-collection correctness fixes relevant to modern behavior.
- Sonatype: OCI Repositories — native OCI hosted/proxy/group support introduced in the 3.94 line; separate it from the older Docker repository format.
- Sonatype nexus-public 3.95.2-01 release — dated patch baseline used in this chapter.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.