Cloud Resource
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

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.

  1. 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.

  2. 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
  1. 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.

  1. Create the registry.password File: This file will contain the authentication credentials for accessing your Docker Registry. To create it, you can use the htpasswd 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:

  1. 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
  1. 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:

  1. 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;
    }
}
  1. 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, and REGISTRY_REDIS_WRITETIMEOUT: Connection timeouts for Redis.
  • REGISTRY_REDIS_POOL_MAXIDLE and REGISTRY_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

  1. Navigate to the Docker Compose Directory: Open your terminal and navigate to the directory containing your docker-compose.yaml file.

  2. 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.