Chapter 73: DevOps Projects Part 3: Docker Websites, APIs, Compose, Registry and ECR
73.9 Project 25: Run a private Docker registry
Friends, teams need a place to store images that is not a public hub. Today we run registry:2 on port 5000 with a volume, tag and push an nginx image, pull it back, and call the v2 catalog API.
मित्रांनो, teams ला public hub नसलेले image store हवे. आज registry:2 port 5000, volume, nginx tag-push-pull, v2 catalog API.
दोस्तों, teams को public hub के बिना image store चाहिए. आज registry:2 port 5000, volume, nginx tag-push-pull, v2 catalog API.
What you will build in this project
- registry:2 on :5000.
- Push and pull localhost:5000/shop-nginx.
- Catalog and tags API.
- Volume keeps blobs across restart.
1. Start from a real company story
At Freshworks in Chennai, developers pushed images to a shared laptop folder with scp. Digests never matched and one bad copy hit staging.
A rollback failed for 40 minutes. Rough cost: about ₹6 lakh in SLA credits.
Meera stood up a private registry with a volume and digest pins in Compose.
Today we run that registry lab on localhost:5000.
Ravindra Bagale's Tip
Many students run a registry with no volume and wonder where tags went after restart. Mount /var/lib/registry. Keep that habit.
खूप students volume नसलेला registry चालवतात आणि restart नंतर tags हरवतात. /var/lib/registry mount करा. सवय ठेवा.
बहुत students बिना volume registry चलाते हैं और restart के बाद tags खो देते हैं. /var/lib/registry mount करें. आदत रखिए.
2. Start and prepare
Step 1: Run registry container
Why: Need a place to store images. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: docker run registry:2. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 1: run
Type this:
docker rm -f local-registry >/dev/null 2>&1; docker volume create registry-data >/dev/null; docker run -d --name local-registry -p 5000:5000 -v registry-data:/var/lib/registry registry:2 && echo started
You will see:
started
What it means: Registry up.
Example 2: ps
Type this:
docker ps --filter name=local-registry --format '{{.Names}} {{.Ports}}'
You will see:
local-registry 0.0.0.0:5000->5000/tcp
What it means: Mapped.
Example 3: v2
Type this:
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/v2/
You will see:
200
What it means: API.
Step 2: Tag local image
Why: Tag includes registry host. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: docker tag. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 4: need image
Type this:
docker images nginx:1.27-alpine -q | head -1 || docker pull nginx:1.27-alpine
You will see:
sha...
What it means: Base image.
Example 5: tag
Type this:
docker tag nginx:1.27-alpine localhost:5000/shop-nginx:1.0 && docker images localhost:5000/shop-nginx --format '{{.Repository}}:{{.Tag}}'
You will see:
localhost:5000/shop-nginx:1.0
What it means: Tagged.
Example 6: why host
Type this:
echo 'The first path segment before / is the registry host:port'
You will see:
The first path segment before / is the registry host:port
What it means: Rule.
Step 3: Push to localhost
Why: Push uploads layers. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: docker push. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 7: push
Type this:
docker push localhost:5000/shop-nginx:1.0
You will see:
Pushed ... digest: sha256:...
What it means: Pushed.
Example 8: ok
Type this:
echo push_ok
You will see:
push_ok
What it means: OK.
Example 9: note
Type this:
echo 'If push fails with HTTP, check insecure-registries only for lab hosts'
You will see:
If push fails with HTTP, check insecure-registries only for lab hosts
What it means: Lab tip.
3. Build the main pieces
Step 4: Pull from registry
Why: Pull proves registry. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: docker pull. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 10: rmi local tag optional
Type this:
docker rmi localhost:5000/shop-nginx:1.0 >/dev/null 2>&1; echo cleared_local_tag
You will see:
cleared_local_tag
What it means: Force pull.
Example 11: pull
Type this:
docker pull localhost:5000/shop-nginx:1.0
You will see:
Pulled ...
What it means: Pulled.
Example 12: images
Type this:
docker images localhost:5000/shop-nginx:1.0 --format '{{.Repository}}:{{.Tag}}'
You will see:
localhost:5000/shop-nginx:1.0
What it means: Listed.
Step 5: List catalog
Why: Catalog lists repos. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: curl _catalog. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 13: catalog
Type this:
curl -s http://127.0.0.1:5000/v2/_catalog
You will see:
{"repositories":["shop-nginx"]}
What it means: Catalog.
Example 14: tags
Type this:
curl -s http://127.0.0.1:5000/v2/shop-nginx/tags/list
You will see:
{"name":"shop-nginx","tags":["1.0"]}
What it means: Tags.
Example 15: code
Type this:
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/v2/_catalog
You will see:
200
What it means: OK.
Step 6: Verify digest
Why: Digest pins content. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: inspect RepoDigests. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 16: digest
Type this:
docker image inspect localhost:5000/shop-nginx:1.0 --format '{{index .RepoDigests 0}}'
You will see:
localhost:5000/shop-nginx@sha256:...
What it means: Digest.
Example 17: pin tip
Type this:
echo 'Prefer digest pins in production compose and k8s'
You will see:
Prefer digest pins in production compose and k8s
What it means: Habit.
Example 18: id
Type this:
docker images localhost:5000/shop-nginx:1.0 --format '{{.ID}}'
You will see:
sha256:...
What it means: ID.
4. Automate and verify
Step 7: Restart registry volume
Why: Volume keeps blobs. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: volume mount. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 19: restart
Type this:
docker restart local-registry && sleep 2 && curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/v2/
You will see:
200
What it means: Still up.
Example 20: catalog2
Type this:
curl -s http://127.0.0.1:5000/v2/_catalog
You will see:
{"repositories":["shop-nginx"]}
What it means: Data kept.
Example 21: vol
Type this:
docker volume inspect registry-data --format '{{.Name}}'
You will see:
registry-data
What it means: Volume.
Step 8: Push again
Why: Second push is faster. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: push again. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 22: retag
Type this:
docker tag localhost:5000/shop-nginx:1.0 localhost:5000/shop-nginx:1.1 && docker push localhost:5000/shop-nginx:1.1
You will see:
Pushed
What it means: Second tag.
Example 23: tags2
Type this:
curl -s http://127.0.0.1:5000/v2/shop-nginx/tags/list
You will see:
...1.0...1.1...
What it means: Two tags.
Example 24: layers
Type this:
echo 'Second push reuses layers; output shows Mounted from'
You will see:
Second push reuses layers; output shows Mounted from
What it means: Cache.
Step 9: Pull on clean name
Why: Retag pull. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: rmi then pull. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 25: rmi
Type this:
docker rmi localhost:5000/shop-nginx:1.1 >/dev/null 2>&1; docker pull localhost:5000/shop-nginx:1.1
You will see:
Pulled
What it means: Clean pull.
Example 26: run
Type this:
docker rm -f reg-test >/dev/null 2>&1; docker run -d --name reg-test -p 8089:80 localhost:5000/shop-nginx:1.1 && curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8089/
You will see:
200
What it means: Runs.
Example 27: stop
Type this:
docker rm -f reg-test >/dev/null; echo cleaned
You will see:
cleaned
What it means: Clean.
5. Harden and accept
Step 10: curl v2 API
Why: HTTP API check. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: /v2/. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 28: v2
Type this:
curl -s http://127.0.0.1:5000/v2/
You will see:
{}
What it means: Empty JSON OK.
Example 29: headers
Type this:
curl -sI http://127.0.0.1:5000/v2/ | head -3
You will see:
HTTP/1.1 200 OK
What it means: Headers.
Example 30: catalog
Type this:
curl -s http://127.0.0.1:5000/v2/_catalog
You will see:
{"repositories":["shop-nginx"]}
What it means: Still.
Step 11: Auth note
Why: Real registries need TLS+auth. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: htpasswd note. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 31: auth
Type this:
echo 'Production: put TLS and htpasswd or SSO in front of the registry'
You will see:
Production: put TLS and htpasswd or SSO in front of the registry
What it means: Real life.
Example 32: insecure
Type this:
echo 'Do not leave insecure-registries on company laptops'
You will see:
Do not leave insecure-registries on company laptops
What it means: Safety.
Example 33: cleanup tip
Type this:
echo 'Lab: docker rm -f local-registry; keep volume if you want blobs'
You will see:
Lab: docker rm -f local-registry; keep volume if you want blobs
What it means: Cleanup.
Step 12: Acceptance checklist
Why: Meera signs off when push and pull work. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the stack is healthy today.
What: All green. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn Compose and registries.
Example 34: push ok
Type this:
curl -s http://127.0.0.1:5000/v2/shop-nginx/tags/list | grep 1.0
You will see:
1.0
What it means: Tag.
Example 35: pull ok
Type this:
docker images localhost:5000/shop-nginx --format '{{.Tag}}' | head
You will see:
1.0
What it means: Local.
Example 36: Sign-off
Type this:
echo 'Meera: PASS'
You will see:
Meera: PASS
What it means: Done.
Check yourself
Q1. Who fixed Freshworks image chaos?
Meera
Q2. Registry image?
registry:2
Q3. Host port?
5000
Q4. Catalog path?
/v2/_catalog
Q5. Volume path in container?
/var/lib/registry
Q6. Why digest pins?
Immutable content
Friends, you pushed and pulled through a private registry. Did you understand? Let us try it once more. Add a second tag and pin a service by digest in a tiny compose file.
मित्रांनो, तुम्ही private registry वर push-pull केले. दुसरा tag टाका आणि compose मध्ये digest pin करा.
दोस्तों, आपने private registry पर push-pull किया. दूसरा tag डालें और compose में digest pin करें.
Lab: try at home
- Run registry:2 with a volume.
- Tag nginx to localhost:5000.
- Push and pull.
- curl the catalog.
- Restart and confirm tags remain.
Recap
- Tag must include registry host.
- Volume keeps blobs.
- Digests pin immutable content.
- Lab HTTP is not production TLS.
- Catalog API lists repositories.