Docker Registry
Setting Up Your Own Docker Registry Using Docker-Compose
The world of Docker has revolutionized the way we think about software development and deployment. Docker’s containerization technology has made it simple to package applications with their dependencies and to ensure they run seamlessly in any environment. However, one crucial part of the Docker ecosystem is the Docker Registry. A Docker Registry is a stateless, scalable server-side application that stores and distributes Docker images. Public registries like Docker Hub are widely used, but sometimes you might want to maintain your own Docker Registry for privacy, security, or even network performance reasons.
In this blog post, we will walk you through setting up your own Docker Registry using Docker Compose. Docker Compose allows you to define and manage multi-container Docker applications. With Docker Compose, you can configure all of your application’s services in a single file and then spin everything up with just a single command.
Prerequisites and Initial Setup
Before we dive into the process of setting up your own Docker Registry, there are a few prerequisites and initial setup steps you’ll need to complete.
-
Install Docker and Docker Compose: If you haven’t already, you’ll need to install Docker and Docker Compose on your system. Instructions for installing Docker can be found on the official Docker documentation, and Docker Compose installation instructions are available on the official Docker Compose documentation.
-
Create the Required Directories: Next, you’ll need to create the directories that will be used in your
docker-compose.yml
file. These directories will store your Docker Registry data, authentication credentials, and Nginix configuration:
mkdir -p /data/nginx/conf.d
mkdir -p /data/nginx/certs
mkdir -p /data/registry/auth
mkdir -p /data/registry/data
mkdir -p /data/registry/config
- Generate a Self-Signed SSL Certificate: For the Nginx server, we will need an SSL certificate. For testing purposes, you can generate a self-signed certificate as follows:
openssl req -x509 -newkey rsa:4096 -keyout /data/nginx/certs/registry.yourdomain.com.key -out /data/nginx/certs/registry.yourdomain.com.crt -days 365 -nodes
This command will prompt you to enter some information for the certificate. You can enter whatever you’d like, or leave the fields blank.
- Create the
registry.password
File: This file will contain the authentication credentials for accessing your Docker Registry. To create it, you can use thehtpasswd
command from the Apache HTTP Server project. Install it using your system’s package manager, and then run:
htpasswd -Bc /data/registry/auth/registry.password <username>
Replace <username>
with the username you’d like to use. This command will prompt you to enter a password for the user.
Adding config.yml
to the Initial Setup
In addition to the prerequisites and setup steps previously outlined, we’ll need to create a config.yml
file for your Docker Registry. This configuration file determines the settings and behavior of your Docker Registry, and is required for its operation.
Here is how you can create the config.yml
file:
- Create the
config.yml
File: Using your preferred text editor, create a new file at the path/data/registry/config/config.yml
.
Input the Configuration: Paste the following configuration into your config.yml
file:
version: 0.1
log:
fields:
service: registry
storage:
delete:
enabled: true
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /data/docker/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
- Save and Close the File: Once you’ve pasted the configuration into your file, save it and close your text editor.
This configuration sets up a Docker Registry with filesystem storage at /data/docker/registry
, enables the deletion of images, and sets up basic health checks. The http
block configures the address and port that the Docker Registry will listen on, as well as some security headers.
With this step completed, your initial setup is now complete, and you’re ready to deploy your Docker Registry! Follow along with the rest of the guide to learn how to start your registry, and how to use it to store and distribute Docker images.
With these prerequisites and initial setup steps completed, you’re now ready to proceed with setting up your own Docker Registry! In the following sections, we’ll discuss how to customize the docker-compose.yml
file to suit your needs, and then we’ll walk you through starting up your Docker Registry and accessing it for the first time.
Creating the default.conf
File for nginx Configuration
To ensure the seamless operation of your private Docker registry, we will need to set up nginx. This will provide a robust, reliable interface between your Docker clients and your Docker Registry server. In this context, we will create a default.conf
file to define our nginx server configurations.
Here’s how you can create and configure the default.conf
file:
- Create the
default.conf
File: Using your preferred text editor, create a new file at the path/data/nginx/conf.d/default.conf
.
Input the Configuration: Copy and paste the following configuration into your default.conf
file:
server {
listen 80;
server_name reg;
return 301 https://$host$request_uri;
}
# Log formatting
map "$time_iso8601:xOx:$msec" $time_iso8601_ms { ~(^\S+)([+\-]\S+):xOx:\d+\.(\d+)$ $1.$3$2; }
log_format logstash '[$time_iso8601_ms] $remote_addr $host $upstream_addr "$request" $status $upstream_status $upstream_cache_status $request_time $upstream_response_time $request_length $bytes_sent $body_bytes_sent $connection_requests $scheme $ssl_protocol $ssl_cipher "$http_referer" "$http_user_agent" $remote_port "registry-nginx" ""registry.yourdomain.com';
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name registry.yourdomain.com;
# Increase client_max_body_size
client_max_body_size 1000M;
ssl_certificate /etc/nginx/certs/registry.yourdomain.com.crt;
ssl_certificate_key /etc/nginx/certs/registry.yourdomain.com.key;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
ssl_prefer_server_ciphers on;
chunked_transfer_encoding on;
proxy_ssl_server_name on;
# Logging Settings
access_log /var/log/nginx/access.log logstash;
error_log /var/log/nginx/error.log notice;
location / {
client_max_body_size 1000M;
client_body_buffer_size 10M;
proxy_busy_buffers_size 12M;
proxy_buffers 8 2M;
proxy_buffer_size 12M;
proxy_pass http://ui/;
}
location /v2/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Docker uses chunked Transfer-Encoding, so we need these settings
chunked_transfer_encoding on;
proxy_buffering off;
proxy_pass http://reg:5000;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
- Save and Close the File: Once you’ve added the configuration, save the file and close your text editor.
This default.conf
file configuration sets up nginx to listen on ports 80 and 443, redirects all HTTP traffic to HTTPS, and configures the necessary proxy settings for your Docker registry. The configuration also includes SSL settings and paths to your SSL certificate and key.
Please make sure to replace registry.yourdomain.com
with your domain name in the server_name field and in the ssl_certificate and ssl_certificate_key paths.
With this step completed, your initial setup for the Docker registry with nginx is now complete, and you’re ready to deploy your Docker registry using Docker Compose.
Deploying the Docker Registry with Docker Compose
After completing the prerequisite steps, we are now ready to deploy our Docker registry. The Docker Compose utility makes this process simple and straightforward.
Using Docker Compose, we can run our services, defined in the docker-compose.yaml
file, with a single command. This command is docker-compose up -d
, which instructs Docker Compose to start up our services in detached mode (running in the background).
In our setup, we’ll create a private Docker Registry along with a user-friendly UI and an Nginx reverse proxy for secure access. The Docker Compose file for this setup is as follows:
version: '3'
services:
redis:
image: redis:6.2.6
container_name: redis
environment:
- REDIS_PASSWORD=<redis_secret>
networks:
- regnet
registry:
image: registry:2.8.2
container_name: reg
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
- REGISTRY_HTTP_SECRET=<http_secret>
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/data
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM=Registry
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password
- REGISTRY_REDIS_ADDR=redis:6379
- REGISTRY_REDIS_PASSWORD=<redis_secret>
- REGISTRY_REDIS_DB=0
- REGISTRY_REDIS_DIALTIMEOUT=10ms
- REGISTRY_REDIS_READTIMEOUT=10ms
- REGISTRY_REDIS_WRITETIMEOUT=10ms
- REGISTRY_REDIS_POOL_MAXIDLE=16
- REGISTRY_REDIS_POOL_MAXACTIVE=64
- REGISTRY_REDIS_POOL_IDLETIMEOUT=300s
volumes:
- /data/registry/auth:/auth
- /data/registry/data:/data
- /data/registry/config/config.yml:/etc/docker/registry/config.yml
restart: always
networks:
- regnet
restart: unless-stopped
ui:
image: joxit/docker-registry-ui:2.5.2-debian
container_name: ui
environment:
- REGISTRY_TITLE=My Private Docker Registry
- NGINX_PROXY_PASS_URL=http://reg:5000
- DELETE_IMAGES=true
- SINGLE_REGISTRY=true
depends_on:
- registry
networks:
- regnet
restart: unless-stopped
nginx:
image: nginx:1.25.1
container_name: nginx
volumes:
- /data/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
- /data/nginx/certs:/etc/nginx/certs/
ports:
- 443:443
depends_on:
- ui
networks:
- regnet
restart: unless-stopped
networks:
regnet:
name: regnet
Please note that this guide assumes a basic understanding of Docker, Docker Compose, and the Linux command line. If you’re not familiar with these technologies yet, you might want to brush up on those skills first.
Environment Variables for Docker Registry
These environment variables define the behavior of your Docker Registry service. Here’s a brief description of each:
REGISTRY_STORAGE_DELETE_ENABLED
: Enables deletion of blobs in your Docker Registry. Useful if you need to maintain disk space.REGISTRY_HTTP_SECRET
: A secret for securing the communication between clients and the registry. It should be a random string.REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
: Specifies the root directory for the registry storage.REGISTRY_AUTH
: Specifies the authentication method, in this case,htpasswd
.REGISTRY_AUTH_HTPASSWD_REALM
: The realm users see when they are asked to authenticate.REGISTRY_AUTH_HTPASSWD_PATH
: Path to the file containing htpasswd user and hashed password pairs.REGISTRY_REDIS_ADDR
: Specifies the address of your Redis service for cache storage.REGISTRY_REDIS_PASSWORD
: Password to connect to your Redis service.REGISTRY_REDIS_DB
: Specifies the Redis database number to use.REGISTRY_REDIS_DIALTIMEOUT
,REGISTRY_REDIS_READTIMEOUT
, andREGISTRY_REDIS_WRITETIMEOUT
: Connection timeouts for Redis.REGISTRY_REDIS_POOL_MAXIDLE
andREGISTRY_REDIS_POOL_MAXACTIVE
: Controls the maximum number of idle and active connections to Redis.REGISTRY_REDIS_POOL_IDLETIMEOUT
: Specifies the maximum amount of time that an idle (keep-alive) connection will remain idle before closing itself.
These variables together ensure secure communication, user authentication, Redis cache usage, and proper storage management for your Docker Registry.
Step: Deploying the Services
-
Navigate to the Docker Compose Directory: Open your terminal and navigate to the directory containing your
docker-compose.yaml
file. -
Run Docker Compose: Enter the following command to start your services:
docker-compose up -d
This docker-compose file spins up four services: the Docker Registry, a Redis instance for caching, a UI for the Docker Registry, and an Nginx server to handle secure access. All of the services are on a dedicated network, ensuring that your Docker Registry setup is isolated and secure.
Once the command completes, your private Docker registry, along with the associated services (including redis, nginx, and the UI), should be up and running. You can access your Docker registry UI by opening a web browser and navigating to https://registry.yourdomain.com
(replace yourdomain.com
with your actual domain).
Remember, always monitor the output of the docker-compose up -d
command to ensure that all services are running correctly and to troubleshoot any issues that may arise.
Using Your Private Docker Registry
After setting up your private Docker Registry, you can start pushing and pulling images to and from it. Here are the basic steps you’ll need to follow:
Step 1: Pull an Image
Start by pulling an image from the Docker public hub. This image will be uploaded to your private registry. We will use the Ubuntu image for this demonstration.
docker pull ubuntu
Step 2: Login to Your Private Registry
Before you can push images to your private registry, you need to login. Use the username and password you created earlier in the registry.password
section.
docker login https://registry.yourdomain.com
Remember to replace registry.yourdomain.com
with your own domain.
Step 3: Tag the Image
Next, you need to tag the image so that it points to your private registry.
docker image tag ubuntu registry.yourdomain.com/myfirstimage:1
In this command, ubuntu
is the name of the image, registry.yourdomain.com
is the domain of your private registry, myfirstimage
is the name you want to give to your image, and 1
is the tag for this image.
Step 4: Push the Image
Once your image is tagged, you can push it to your private registry with the docker push
command.
docker push registry.yourdomain.com/myfirstimage:1
Step 5: Pull the Image
Finally, you can pull the image back from your private registry to any docker host connected to it.
docker pull registry.yourdomain.com/myfirstimage:1
And there you have it! You’ve just successfully pushed and pulled an image to and from your private Docker Registry. Continue with this process for all the images you’d like to host privately.
Note: Ensuring Trusted Communication with Your Private Docker Registry
It’s essential to remember that Docker requires secure communication via HTTPS when interacting with a private registry. If your registry’s certificate isn’t signed by a recognized Certificate Authority (CA), Docker will consider it as self-signed and block communication due to security reasons.
You can overcome this by ensuring that your Docker host has the private registry’s certificate installed in its trusted certificate store. This process varies between operating systems, so please refer to your respective OS documentation for instructions.
Keep this in mind before you start pushing or pulling images from your private Docker registry, as not having proper certificates may lead to connection errors. Always prioritize the security and trustworthiness of your Docker communication.