Alibaba Cloud proposes a Container Registry service to store Docker images, but in some contexts, you can need to create your own private Docker Registry. In this article, I will show how to set up a private Docker Registry service with a user interface.
You need to create an ECS instance with a public IP address (in my example: 8.208.90.125
):
Then, create a security group to authorize the following ports:
5000
for the Docker Registry8086
for the Docker Registry UIAdd two rules for the ports 5000
and 8086
:
Connect by SSH on the ECS instance:
ssh root@8.208.90.125
The output is:
root@8.208.90.125's password:
Last failed login: Mon Sep 21 02:53:29 CST 2020 from 86.208.0.102 on ssh:notty
There were 356 failed login attempts since the last successful login.
Last login: Sat Sep 19 01:39:43 2020 from 82.67.244.69
Welcome to Alibaba Cloud Elastic Compute Service !
On the ECS instance, install Docker and Docker Compose as the root:
For Docker:
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl start docker
For Docker Compose:
curl -L "https://github.com/docker/compose/releases/download/1.27.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
Let's verify that Docker and Docker Compose are well installed:
docker --version
docker-compose --version
Now, let's install the private Docker Registry. The Docker images will be stored in the /tmp/docker_registry
directory. So, let's create this directory:
mkdir /tmp/docker_registry
Let's create a Docker Compose file to run the Docker Registry service on the port 5000
:
cat << EOF > docker-compose.yml
version: '3'
services:
docker-registry:
image: registry:2
volumes:
- "/tmp/docker_registry:/var/lib/registry"
ports:
- "5000:5000"
restart: always
EOF
So, we expose the ports from 5000/tcp
to 8888/tcp
on the host and we use a volume on /tmp/docker_registry
to store the images.
Let's create the service:
docker-compose up ®Cd
Display the logs of the container:
docker-compose logs
The output is:
Attaching to root_docker-registry_1
docker-registry_1 | time="2020-09-20T18:57:22.21325251Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.214008926Z" level=info msg="redis not configured" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.215304875Z" level=info msg="Starting upload purge in 42m0s" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.23182228Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.232164343Z" level=info msg="listening on [::]:5000" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
Now, let's add a service for a user interface in the Docker Compose file. For that, we use the image parabuzzle/craneoperator
and create the credentials admin / mypassword
:
cat << EOF > docker-compose.yml
version: '3'
services:
docker-registry:
image: registry:2
volumes:
- "/tmp/docker_registry:/var/lib/registry"
ports:
- "5000:5000"
restart: always
docker-registry-ui:
image: parabuzzle/craneoperator:latest
ports:
- "8086:80"
environment:
- REGISTRY_HOST=docker-registry
- REGISTRY_PORT=5000
- REGISTRY_PROTOCOL=http
- SSL_VERIFY=false
- USERNAME=admin
- PASSWORD=mypassword
restart: always
depends_on:
- docker-registry
EOF
Launch the stack:
docker-compose up ®Cd
Verify that the services have started by displaying the logs of the containers:
docker-compose logs
The output is:
Attaching to root_docker-registry-ui_1, root_docker-registry_1
docker-registry-ui_1 | 18:58:13 web.1 | started with pid 7
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.553334 #7] INFO -- : Refreshing Gem list
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.908830 #7] INFO -- : listening on addr=0.0.0.0:80 fd=9
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.909368 #7] INFO -- : worker=0 spawning...
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.910919 #7] INFO -- : worker=1 spawning...
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.912083 #7] INFO -- : worker=2 spawning...
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.912894 #10] INFO -- : worker=0 spawned pid=10
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.913891 #7] INFO -- : master process ready
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.914310 #10] INFO -- : worker=0 ready
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.915186 #12] INFO -- : worker=1 spawned pid=12
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.915516 #12] INFO -- : worker=1 ready
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.916320 #15] INFO -- : worker=2 spawned pid=15
docker-registry-ui_1 | 18:58:13 web.1 | I, [2020-09-20T18:58:13.916582 #15] INFO -- : worker=2 ready
docker-registry_1 | time="2020-09-20T18:57:22.21325251Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.214008926Z" level=info msg="redis not configured" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.215304875Z" level=info msg="Starting upload purge in 42m0s" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.23182228Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
docker-registry_1 | time="2020-09-20T18:57:22.232164343Z" level=info msg="listening on [::]:5000" go.version=go1.11.2 instance.id=b1068e37-1960-4336-bd53-a4014b15c66e service=registry version=v2.7.1
Now, let's push an image on our private Docker Registry.
On a desktop, pull the image alpine
:
docker pull alpine
The output is:
Using default tag: latest
latest: Pulling from library/alpine
df20fa9351a1: Already exists
Digest: sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
Let's tag this image:
docker tag alpine 8.208.90.125:5000/alpine
Then, push it to the Docker Registry:
docker push 8.208.90.125:5000/alpine
We get an error:
The push refers to repository [8.208.90.125:5000/alpine]
Get https://8.208.90.125:5000/v2/: http: server gave HTTP response to HTTPS client
As we configure the Docker Registry on HTTP instead of HTTPS, we have to authorize the connection to the Docker client. On MacOS, open the Docker Desktop and under the Preferences section, in the Docker Engine tab, enter the following configuration:
{ "insecure-registries":["8.208.90.125"] }
On Linux, we would put this configuration in the /etc/docker/daemon.json
file.
Now, let's try again to push the alpine
on the Docker Registry:
docker push 8.208.90.125:5000/alpine
This time, it works because we authorized Docker Engine to use a Docker Registry that is not HTTPS:
The push refers to repository [8.208.90.125:5000/alpine]
50644c29ef5a: Layer already exists
latest: digest: sha256:a15790640a6690aa1730c38cf0a440e2aa44aaca9b0e8931a9f2b0d7cc90fd65 size: 528
On a web browser on the desktop, log in on the Docker Registry UI by visiting the webpage http://8.208.90.125:8086/
. We have to authenticate with the credentials.
Then, the list of the containers in the Docker Registry is displayed:
Now, we can see the alpine
image. Everything works!
Now you know how to set up a Docker Registry with an HTML user interface. Docker Registry doesn't have HTTPS. In general, the best practice is to use the SSL termination provided by a Load Balancer (SLB) or by a proxy server like NGINX.
By Bruno Delb
8 posts | 1 followers
FollowFarruh - August 11, 2023
Alibaba Clouder - October 18, 2018
Alibaba Container Service - May 31, 2023
Alibaba Clouder - June 14, 2019
Fouad - June 19, 2018
Alibaba Clouder - September 16, 2019
8 posts | 1 followers
FollowA secure image hosting platform providing containerized image lifecycle management
Learn MoreProvides a control plane to allow users to manage Kubernetes clusters that run based on different infrastructure resources
Learn MoreAlibaba Cloud Container Service for Kubernetes is a fully managed cloud container management service that supports native Kubernetes and integrates with other Alibaba Cloud products.
Learn MoreAn agile and secure serverless container instance service.
Learn MoreMore Posts by Bruno Delb