Understanding Docker Images, Repositories, Tags, & Hosting Your Own Docker Registry - A Deep Dive
For some reason, I’ve gone into my “host everything yourself” era.
I got a Raspberry Pi for a project and working with a Raspberry Pi 3 in 2026, I realized that the Pi is probably not the best place to be compiling/building your applications. It’s running on an SD card—from I don’t know which era—that I found lying around and has only 1 GB of RAM to run the whole thing.
So I decided to instead use docker and containerization to run my applications on the Pi.
Since I don’t even want to build the docker image on the Pi from source for reasons like: I don’t like waiting all day for something that should build in a few seconds. I needed to find a way to transfer these docker images from my Mac to the Pi.
Wait, but how is a Docker image even stored on your computer?
This is an interesting question that I thought of while doing this — at the end, everything in linux and most OS’s is a file right? So if a docker image is just a single file, it shouldn’t be that hard to just transfer the file itself to the Pi, then somehow tell docker to run that image as a container, right?
This is where things started to get a bit weird. A quick Google (yes, I still use Google in 2026) revealed the following:
On the host machine, Docker stores images in a specific root directory, and the exact location and format depend on the operating system and the configured storage driver.
But after digging into the ONE stackoverflow post on this (again, yes, I still use stackoverflow), it turns out that the differences between how Docker stores your images arises mainly due to your OS, because on Linux, Docker shares the kernel, while on Mac and Windows, Docker Desktop runs a lightweight virtual machine (VM) and containers share the kernel with that VM. Some pretty cool tech if I do say so myself.
Getting back to how Docker images are stored— It turns out an image is not a single file but is composed of multiple, stacked, read-only layers. Each instruction in a Dockerfile creates a new layer, which represents a set of filesystem changes (additions, deletions, or modifications). This layering system, made possible by a union filesystem, is crucial for efficiency: layers are shared between different images and containers, saving disk space and network bandwidth.
So on Linux, images are usually stored in the /var/lib/docker directory (also known as the Docker root directory) and the specific layers are found within a subdirectory corresponding to the storage driver in use (e.g., /var/lib/docker/overlay2 if you’re using the overlay2 driver which is the default storage driver for Docker in Linux).
For MacOS and Windows (with Docker Desktop), since Docker runs within a VM, the images are stored inside a single, large disk image file (e.g., .raw or .vhdx) managed by the VM, and not in the host's native filesystem directly.
Okay, so an image is composed of many files, with some metadata in another folder and since I’m on Mac, it’s on a file that I really have no idea how to open up. So it turns out, it would be quite complicated to transfer the actual image files from my Mac to the Pi.
Docker Hub, Artifactory, and other Registry Solutions Out There
Since working in corporate big tech companies, I got to know that transferring lots of docker images is a real problem and that it’s not just me (lol) and that there are multiple solutions out there that already do this.
These span across the spectrum — from providers like Docker’s Docker Hub, AWS’s Elastic Container Registry, GitHub’s Container Registry, GCP’s Artifact Registry; to open source and self host ones like Harbor, Quay, Docker’s own registry and JFrog Arifactory.
While it’s cool to see these products and the many features they provide, what I needed was a really simple and easy to use service that I can just spin up transfer my images and spin down, with no real hassle. This is why I decided to go with Docker’s registry.
Running Docker Registry
Running docker registry on my local machine was pretty straightforward — Just one docker run command, like below:
docker run -d -p 5000:5005 --name registry registry
Note: In macOS, port 5000 is used by the system's built-in AirPlay Receiver service. This often means that we devs map our containers and applications to other ports, which is why we’re using Port 5005 here.
The registry becomes accessible on http://localhost:5005 (fascinating that docker uses http(s) for pulling and pushing images). Ideally in a production scenario, you’ll have SSL/TLS certs setup so you can get it working with HTTPS, as you’ll see me encounter this later…
Pushing an Image to Our Docker Registry (and Understanding Why Docker Tags Exist)
Before we can push an image to a registry, we need to tag it with a fully qualified tag name.
This was initially a bit cryptic to me because I just didn’t understand why we needed these tags and why I couldn’t just do docker push my-epic-app:1.0 .
After looking this up in the official docker docs and ChatGPT, basically each docker registry (eg: Docker Hub at docker.io, or in this case, localhost:5005) contains multiple namespaces (you can think of these as users or organizations) which in turn contain multiple repositories (you can think of them as repos on GitHub, eg: my-epic-app). To differentiate between multiple versions of images, you use image tags (a tag in a tag? tag-ception!), eg: the 1.0 in my-epic-app:1.0.
So, to push this new my-epic-app:1.0 image at localhost:5005 in the my-epic-app repository, you’d need to tell Docker that you’d like this local my-epic-app:1.0 image to be pushed to localhost:5000/my-epic-app:1.0 . You do this by tagging the local image with this fully qualified tag name.
You’d notice that I haven’t specified a namespace here. Namespaces in the tag are optional, and if they are not specified, docker assumes it to be library.
So to push an image to our registry after building it, we need to:
Tag the image with a fully qualified tag name so that docker knows where to push it to:
# Assuming that `docker build . -t my-epic-app:1.0` was used to build the image. docker tag my-epic-app:1.0 localhost:5000/my-epic-app:1.0Push the image (using the new tag name):
docker push localhost:5000/my-epic-app:1.0
Note: Creating a tag doesn’t create a new image or duplicate an existing one. It’s simply a reference pointing to the same image ID and is meant to make it easier for users to reference their image. You can see here that after tagging, the same image ID is displayed for the local image and the tagged image.
Pulling the Image from our Registry on Another Machine
Okay! We’ve now pushed an image to the registry, let’s go into the other machine, in my case, the Raspberry Pi, which is on the same network and pull the image.
So the computer hosting the registry has an IP address on this network is 192.168.1.22
Which means I should be able to pull the image like so:
Oh no! Docker is reporting that we’re running our registry on HTTP and the docker pull client expected it to be HTTPS. What if we just specified the protocol in the tag, HTTP?
Nope, that didn’t work either 😛
After pasting the error message into Google, the AI overview block suggested that we need to configure your Docker daemon to recognize it as an "insecure registry". Also, you’re not supposed to type out http:// or https:// in the image name, welp.
Adding the registry's address to the insecure-registries list in the Docker daemon's configuration file and restarting Docker will do the trick. For Linux, this file is typically located at /etc/docker/daemon.json. I copied the following into it:
and then ran
sudo systemctl daemon-reload && sudo systemctl restart docker to restart docker.
I was able to pull the image after that. YAY! (again, this is not the best security practice but a good workaround for local testing)
Conclusion
I had a lot of fun on this journey and definitely learnt a lot about docker while doing this. I hope you enjoyed reading my take on this and that it helped you understand things a little better. Please let us know what you think! You can find me on my socials below!
Sources:
Peter McKee | How to Use Your Own Registry | Docker
Stackoverflow | Where are docker images stored?
Docker Documentation - Image Tags
Google & ChatGPT (as always)