A docker image registry is used to store docker images and maintain their versions. Container runtime engines such as Podman, Containerd, CRI-O, rkt, etc are typically used to the push and pull images using their respective commands. Most of these runtimes have a way to create and maintain a local registry for the machine on which they are installed. However when sharing images between different machines, we need a centralized repository where one can push and pull images. There are lot of PaaS registry services are available in the market already. However, sometimes you may want to have your own personal/private registry where you can control what images are available for your runtimes.
This article outlines the steps needed to implement a private registry as a container and store images in the same for internal use.
Install Container Engine and httpd-tools
The steps to install container engines will vary depending upon the engine you want to run, its version and the OS that you want to use. Please follow the instructions related to your engine. For the purpose of this blog post, we’ll install and use docker engine which uses containerd as runtime, on the CentOS 7.
To install httpd-tools, we can use below command:
# yum install -y httpd-tools
Create Directories for Registry
We’ll be creating the registry in /opt/registry/. For this, we’ll need to create three directories – auth, certs and data inside this path. For this, we can use below command:
# mkdir -p /opt/registry/{auth,certs,data}
Out of these directories, the auth directory is used to store the authentication information, certs directory is used to stores certificates and data is used to store the image data.
If you are looking for a portable registry, its better to use removable storage for creating registries.
Create Credentials for accessing Registry
For this, we can use the htpasswd
utility to generate a file containing the credentials for accessing the registry:
# htpasswd -bBc /opt/registry/auth/htpasswd registryuser registryuserpassword
In the above command, registryuser is the username and registryuserpassword is the associated password. This will create a Bcrypt Htpasswd file named htpasswd in the /opt/registry/auth/ directory.
Create Certificate to Secure Registry
To secure the registry with TLS, we need to use a certificate for it. You can either opt for a certificate provided by a trusted authority (internal or external) or by using a simple self-signed (not recommended) certificate. We can generate self-signed certificates using the OpenSSL utility, as below:
# openssl req -newkey rsa:4096 -nodes -sha256 -keyout /opt/registry/certs/domain.key -x509 -days 365 -out /opt/registry/certs/domain.crt

Where:
- req tells OpenSSL to generate and process certificate requests.
- -newkey tells OpenSSL to create a new private key and matching certificate request.
- rsa:4096 tells OpenSSL to generate an RSA key with 4096 bits.
- -nodes tells OpenSSL there is no password requirement for the private key. The private key will not be encrypted.
- -sha256 tells OpenSSL to use the sha256 to sign the request.
- -keyout tells OpenSSL the name and location to store new key.
- -x509 tells OpenSSL to generate a self-signed certificate.
- -days tells OpenSSL the number of days the key pair is valid for.
- -out tells OpenSSL where to store the certificate.
Enter the respective options for your certificate. The CN= value is the hostname of your host. The host’s hostname should be resolvable by DNS or the /etc/hosts file.
Since we are using a self-signed certificate, it will not be trusted by container engine runtimes by default. So, we’ll need to run below commands on client machines:
# cp /opt/registry/certs/domain.crt /etc/pki/ca-trust/source/anchors/ # update-ca-trust # trust list | grep -i "hostname"

Start the Container Registry
For this, we can use the official registry image provided by Docker, Inc as docker.io/library/registry:latest. Since we are using docker engine in our case, we can run it using below command:
docker run --name myregistry \ -p 5000:5000 \ -v /opt/registry/data:/var/lib/registry:z \ -v /opt/registry/auth:/auth:z \ -e "REGISTRY_AUTH=htpasswd" \ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \ -v /opt/registry/certs:/certs:z \ -e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt" \ -e "REGISTRY_HTTP_TLS_KEY=/certs/domain.key" \ -e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true \ -d \ docker.io/library/registry:latest

In above command, we have mapped local port 5000 to the container image port 5000.
If we have firewall running on the machine, we need to create allow rules to permit traffic:
# firewall-cmd --add-port=5000/tcp --zone=internal --permanent # firewall-cmd --add-port=5000/tcp --zone=public --permanent # firewall-cmd --reload
Verify if the access to Registry
The curl
command can be used to access the registry:
# curl -u registryuser:registryuserpassword https://<hostname>:5000/v2/_catalog {"repositories":[]}

The certificate can be verified using:
# openssl s_client -connect <hostname>:5000 -servername <hostname>

Be sure to trust the certificate from earlier or use curl’s -k
switch to ignore certificate verification.
Verify Login/Logout to/from the Registry
We can use the docker login
command to log into the registry:
# docker login <hostname>:5000 Username: registryuser Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded

We can use docker logout
command to logout of the registry.
Push/Pull Images from the Registry
At this point, the registry we created is empty. So we first need to push the image to the registry. To push to the registry, use docker tag
to first tag the image and the registry location, and then push the image using docker push
:
# docker tag <image id|<repo name/image name>> registry:5000/<repo>/<image>

We can verify the images present in the container registry using the curl command:

Same way, we can use docker pull
command to pull the images from our private registry.
Managing Registry Lifecycle
Stop registry:
# docker stop myregistry
Remove registry:
# docker rm myregistry
Delete registry image:
# docker rmi registry:latest
[…] post, we are connected to local registry on our machine. If you want to setup a local registry, see steps here. Let’s review the current state of our […]
LikeLike