Podman - Local Container Registry

If you want to use containers, you need to pull images from a container registry. This is the place where container images live. But, how do you run your own registry? For your local network or development purposes, this is really useful!

Podman - Local Container Registry
Photo by Timelab Pro / Unsplash

If you want to use containers, you need to pull images from a container registry. This is the place where container images live. But, how do you run your own registry? For your local network or development purposes, this is really useful!

Container Registry

A container registry is the place, where images can be uploaded and downloaded. In fact, this is the most useful thing in the current container world.

You build your application, bundle it and upload the ready-to-use image somewhere. Others can download it and deploy it on their own machine. Today, there are many registry services available - Google, Amazon and Azure offer their own solution. Another registry is included in GitLab and GitHub, Pulp also offers one for self-hosting. Harbor is a dedicated registry server, and then there is also quay.io. But the most known is the Docker Registry.

Running such a registry on your own has many reasons and benefits. You may have security concerns or just don't want to upload something to a public registry. The easiest way is to use the official docker registry container.

So, let's have a look how you can run it with Podman on your server. If you work a lot with containers, this might also be a nice addition for the Fedora - Home Server.

Local Docker Registry

A friend of mine asked me about this topic and I also did a small poll over at LinkedIn to see, which registry you are using. It seems like the Docker Registry is still a thing, and therefore I decided to start with it. It is also the easiest one.

Without any further explanation, let's go.

💡
This guide is tested on Fedora 35/36 with Podman 3/4 installed.

Deployment

The easiest way to deploy the registry is by running the below command.

# Run the registry
$ podman container run -dt -p 5000:5000 --name registry docker.io/library/registry:2

# Check if it is running
$ podman container ls
CONTAINER ID  IMAGE                         COMMAND               CREATED        STATUS            PORTS                   NAMES
a8e77acc1c6e  docker.io/library/registry:2  /etc/docker/regis...  3 seconds ago  Up 3 seconds ago  0.0.0.0:5000->5000/tcp  registry

This is a very simple example and suitable for testing. We should add at least some persistent storage. This can be done either with a named volume or a desired path. So, let's add some persistent storage.

# Stop and Remove the running container
$ podman container rm -f registry

# Start again with a named volume
$ podman container run -dt -p 5000:5000 --name registry --volume registry:/var/lib/registry:Z docker.io/library/registry:2

This should do the trick, and you can check the volume with Podman.

# Check volumes
$ podman volume ls
DRIVER      VOLUME NAME
local       registry

# Inspect volume
$ podman volume inspect registry
[
     {
          "Name": "registry",
          "Driver": "local",
          "Mountpoint": "/home/dschier/.local/share/containers/storage/volumes/registry/_data",
          "CreatedAt": "2022-07-04T21:19:17.888305425+02:00",
          "Labels": {},
          "Scope": "local",
          "Options": {},
          "MountCount": 0,
          "NeedsCopyUp": true
     }
]

As you can, the data will be stored in my home directory and therefore, I can restart and even remove the container. If I start a new one and re-use the same volume, I can access already stored images.

Testing

To test the functionality, we can download an image and upload it to our local registry.

# Download an image
$ podman image pull docker.io/library/alpine

# Relable an image
$ podman image tag docker.io/library/alpine:latest localhost:5000/alpine:latest

# Upload to the local registry
$ podman image push localhost:5000/alpine:latest --tls-verify=false
Getting image source signatures
Copying blob 24302eb7d908 done  
Copying config e66264b987 done  
Writing manifest to image destination
Storing signatures

Since the test registry has no valid certificate, we need to add the --tls-verify=false option to our command. Afterwards, you can also search in the registry.

# Search all images in the local registry
$ podman image search localhost:5000/ --tls-verify=false
NAME                   DESCRIPTION
localhost:5000/alpine

Now, you can remove your local image and pull it again from your local registry, if you want.

# Remove local image
$ podman image rm localhost:5000/alpine docker.io/library/alpine

# Check images
$ podman image ls
REPOSITORY                                  TAG            IMAGE ID      CREATED       SIZE
docker.io/library/registry                  2              773dbf02e42e  5 weeks ago   24.6 MB

# Download the image from the local registry
$ podman image pull localhost:5000/alpine:latest --tls-verify=false

# Check images
$ podman image ls
REPOSITORY                                  TAG            IMAGE ID      CREATED       SIZE
docker.io/library/registry                  2              773dbf02e42e  5 weeks ago   24.6 MB
localhost:5000/alpine                       latest         e66264b98777  6 weeks ago   5.81 MB

This was easy enough, I assume.

Cleanup

If you are done with everything, it might be a good idea to clean up the images, volumes and containers.

# Remove container
$ podman container rm -f registry

# Remove volume
$ podman volume rm registry

# Remove image
$ podman image rm docker.io/library/registry:2

Production Setup

The above setup shows a nice example for a home server or development use case. For production, you should add authentication, a proper certificate and maybe tune the published ports.

This topic can be a bit annoying, but the Docker folks have documented it properly.

There are also hundreds of configuration options to make the registry work with cloud services, other storage options and much more.

Deploy a registry server
Explains how to deploy a registry
Configuring a registry
Explains how to configure a registry

Conclusion

This already sums it up today. I hope you will have some fun with your new registry. In some future article, I will demonstrate the same scenario with another registry server, and I am also looking into a comparison of different registries.

Which registry do you use? What do you prefer? Let me know if there is something special you want to know about.