A Docker registry is a storage and content delivery system that holds named Docker images, available in different tagged versions. Users using Docker interact with a registry by using docker push and docker pull commands. Sometimes it makes sense to store Docker images on a local registry rather than pushing them to Docker hub. In this guide we will setup Private Docker Registry on CentOS 7 secured with Let’s Encrypt SSL Certificate.
You’ll save a lot of bandwidth for a big team and keep the images that you don’t want to be exposed to the public safe. Creating a local docker registry on CentOS 7 is a matter of following few steps. For installation of Docker on different distributions refer to How to install Docker CE on Linux Systems.
Step 1: Install Docker CE on CentOS 7
We’ll use registry 2 Docker image to create a running instance of Docker registry on CentOS 7.
Update your CentOS 7 system:
sudo yum -y update
Run the commands below to install Docker CE on CentOS 7.
sudo curl -o /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
Then install Docker CE packages:
sudo yum -y install docker-ce docker-ce-cli containerd.io
If you would like to use Docker as a non-root user, you should now consider adding your user to the “docker” group:
sudo usermod -aG docker $USER
newgrp docker
Run the command below to see a version of docker installed.
$ docker --version
Docker version 24.0.2, build cb74dfc
Start and enable docker service:
sudo systemctl enable --now docker
Status should be running:
$ systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2023-06-28 15:24:38 UTC; 3s ago
Docs: https://docs.docker.com
Main PID: 1690 (dockerd)
Tasks: 8
Memory: 30.0M
CGroup: /system.slice/docker.service
└─1690 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Jun 28 15:24:38 cent7.mylab.io systemd[1]: Starting Docker Application Container Engine...
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.443444615Z" level=info msg="Starting up"
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.483135985Z" level=info msg="Loading containers: start."
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.768228458Z" level=info msg="Loading containers: done."
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.794003159Z" level=warning msg="WARNING: bridge-nf-call-iptables is disabled"
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.794040821Z" level=warning msg="WARNING: bridge-nf-call-ip6tables is disabled"
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.794087923Z" level=info msg="Docker daemon" commit=659604f graphdriver=overlay2 version=24.0.2
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.794320719Z" level=info msg="Daemon has completed initialization"
Jun 28 15:24:38 cent7.mylab.io systemd[1]: Started Docker Application Container Engine.
Jun 28 15:24:38 cent7.mylab.io dockerd[1690]: time="2023-06-28T15:24:38.840934454Z" level=info msg="API listen on /run/docker.sock"
Step 2: Generate Let’s Encrypt SSL Certificates
As promised earlier we’ll use Let’s Encrypt SSL Certificates to secure our Docker Registry setup running on CentOS 7.
Install certbot
tool that will be used to request for Let’s Encrypt certificate.
sudo yum -y install epel-release
sudo yum -y install certbot
Request for SSL certificate:
export DOMAIN="registry.domain.com"
export EMAIL="[email protected]"
certbot certonly --standalone -d $DOMAIN --preferred-challenges http --agree-tos -n -m $EMAIL --keep-until-expiring
Expected certificates generation output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for registry.geeksforgeeks.org
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/registry.geeksforgeeks.org/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/registry.geeksforgeeks.org/privkey.pem
Your cert will expire on 2021-07-28. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Your certs will be saved under /etc/letsencrypt/live/
/etc/letsencrypt/live/registry.domain.com/fullchain.pem
/etc/letsencrypt/live/registry.domain.com/privkey.pem
Where:
- fullchain.pem ⇒ combined file
cert.pem
andchain.pem
- chain.pem ⇒ intermediate certificate
- cert.pem ⇒ SSL Server cert(includes public-key)
- privkey.pem ⇒ private-key file
Step 3: Run Docker registry on CentOS 7
You can either run docker registry with SSL or without. We’ll demonstrate how you can run Docker registry with either of the methods.
But first, create a directory that will hold Docker registry images:
sudo mkdir /var/lib/docker/registry
Run Local Docker registry without SSL
docker run -d -p 5000:5000 \
--name docker-registry \
--restart=always \
-v /var/lib/docker/registry:/var/lib/registry \
registry:2
Run Local Docker registry with SSL
Create directory and place certs on the host:
export DOMAIN="registry.domain.com"
mkdir /certs
sudo cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem /certs/fullchain.pem
sudo cp /etc/letsencrypt/live/$DOMAIN/privkey.pem /certs/privkey.pem
sudo cp /etc/letsencrypt/live/$DOMAIN/cert.pem /certs/cert.pem
Create a Docker Registry container:
docker run -d --name docker-registry --restart=always \
-p 5000:5000 \
-e REGISTRY_HTTP_ADDR=0.0.0.0:5000 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain.pem \
-e REGISTRY_HTTP_TLS_KEY=/certs/privkey.pem \
-v /certs:/certs \
-v /var/lib/docker/registry:/var/lib/registry \
registry:2
Replace registry.domain.com
with your registry subdomain name.
It will download registry:2 docker image if it doesn’t exist and create a container
Unable to find image 'registry:2' locally
2: Pulling from library/registry
ddad3d7c1e96: Pull complete
6eda6749503f: Pull complete
363ab70c2143: Pull complete
5b94580856e6: Pull complete
12008541203a: Pull complete
Digest: sha256:bac2d7050dc4826516650267fe7dc6627e9e11ad653daca0641437abdf18df27
Status: Downloaded newer image for registry:2
ed960bd27529be26e7ef728027844a62b0731b08bafdbbf63dea328dac46e024
Check container state:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ed960bd27529 registry:2 "/entrypoint.sh /etc…" 28 seconds ago Up 27 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp docker-registry
To push images to Registry Container server, set like below:
$ curl https://$DOMAIN:5000/v2/_catalog
{"repositories":[]}
If you have SELinux enabled, you may encounter a problem using port 5000, consider disabling SELinux or putting it on permissive mode if you get issues.
If firewalld is enabled and running, allow the port on the firewall.
sudo firewall-cmd --add-port=5000/tcp --permanent
sudo firewall-cmd --reload
Step 4: Add Insecure Registry to Docker Engine
By default, docker uses https to connect to docker registry. But there can be use cases to use an insecure registry, especially if you’re on a trusted network. This eliminates the need for a CA-signed certificate for internal use or to trust self-signed certificate in all docker nodes. Here are the steps to add Insecure Registry to Docker Engine.
For Ubuntu Xenial, edit /etc/docker/daemon.json and update the key “insecure-registries”. e.g.
{
"insecure-registries" : ["registry.domain.com:5000"]
}
For CentOS 7, edit the file /etc/docker/daemon.json, e.g.
{
"insecure-registries" : ["registry.domain.com:5000"]
}
For Ubuntu trusty, edit the file /etc/default/docker and update DOCKER_OPTS, e.g
DOCKER_OPTS='--insecure-registry registry.domain.com:5000'
Then restart Docker engine
sudo systemctl restart docker
Step 5: Pushing Docker images to the local registry
Now that the registry is ready, you can start pushing docker images to it. If you don’t have an active DNS server, use /etc/hosts file to map the hostname to IP Address.
$ sudo vim /etc/hosts
192.168.1.23 registry.domain.com
I’ll download ubuntu latest docker image from Docker hub and push it to my local Docker registry.
$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
345e3491a907: Pull complete
57671312ef6f: Pull complete
5e9250ddb7d0: Pull complete
Digest: sha256:cf31af331f38d1d7158470e095b132acd126a7180a54f263d386da88eb681d93
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
Tag the image as registry.domain.com:5000/ubuntu. This creates an additional tag for the existing image. When the first part of the tag is a hostname and port, Docker interprets this as the location of a registry, when pushing.
docker tag ubuntu $DOMAIN:5000/ubuntu
Push the image to the local registry running at registry.domain.com:5000/ubuntu
$ docker push $DOMAIN:5000/ubuntu
Using default tag: latest
The push refers to repository [registry.domain.com:5000/ubuntu]
2f140462f3bc: Pushed
63c99163f472: Pushed
ccdbb80308cc: Pushed
latest: digest: sha256:86ac87f73641c920fb42cc9612d4fb57b5626b56ea2a19b894d0673fd5b4f2e9 size: 943
If the image upload was successful, you should get sha256 hash at the end. Pushed images are stored under /var/lib/registry/docker/registry/v2/repositories directory.
$ ls /var/lib/docker/registry/docker/registry/v2/repositories/
ubuntu
This is the same method you’ll use to push custom docker images. To download docker images on the local registry, use the command:
$ docker pull registry-hostname:500/image:tag
#E.g
$ docker pull registry.domain.com:5000/ubuntu
On my next guide, I’ll cover configuring nginx proxy for accessing the repository over https.
You can also take a look at Install Docker UI manager – Portainer