Featured image of post Container (7): Building Your Own Container Image Registry

Container (7): Building Your Own Container Image Registry

Building Your Own Container Image Registry

Motivation

Due to the network environment issues in China, we cannot directly pull container images from Docker Hub. To facilitate the deployment of some container services on computers within China, I decided to build my own container image registry (i.e., Registry) on a server located overseas.

Solution

Docker official provides the image of container image registry Registry, we can use this image to deploy our own container image registry.

We also need to configure a graphical interface for this registry to facilitate viewing. There are quite a few third-party graphical interfaces available online, and here I chose Joxit/docker-registry-ui.

Deployment, Configuration and Usage

Deployment of Image Registry Service

  1. Deploy Container

    Use the following docker-compose.yml file to deploy the image registry service:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
    services:
      registry-ui:
        image: joxit/docker-registry-ui:main
        restart: always
        ports:
          - 8002:80
        environment:
          - SINGLE_REGISTRY=true
          - REGISTRY_TITLE=Docker Registry UI
          - DELETE_IMAGES=true
          - SHOW_CONTENT_DIGEST=true
          - NGINX_PROXY_PASS_URL=http://registry:5000
          - SHOW_CATALOG_NB_TAGS=true
          - CATALOG_MIN_BRANCHES=1
          - CATALOG_MAX_BRANCHES=1
          - TAGLIST_PAGE_SIZE=100
          - REGISTRY_SECURED=false
          - CATALOG_ELEMENTS_LIMIT=1000
        container_name: registry-ui
        networks:
          traefik-net:
            aliases:
              - registry-ui
    
      registry:
        image: registry:3
        container_name: registry
        restart: always
        environment:
          REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
          REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '[http://registry-ui.jinli.io]'
          REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods: '[HEAD,GET,OPTIONS,DELETE]'
          REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials: '[true]'
          REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers: '[Authorization,Accept,Cache-Control]'
          REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers: '[Docker-Content-Digest]'
          REGISTRY_STORAGE_DELETE_ENABLED: 'true'
        volumes:
          - ${DATA_DIR}:/var/lib/registry
        networks:
          traefik-net:
            aliases:
              - registry
    
    networks:
      traefik-net:
        external: true
    

    Here we use two images:

    • registry: Docker official provides the image of container image registry
    • docker-registry-ui: Third-party graphical interface for container image registry developed by Joxit
  2. Reverse Proxy

    We still use the previous Traefik plus Cloudflare Tunnel solution, and we need to configure Traefik for both the registry service and the graphical interface service.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    http:
       routers:
         registry-router:
           rule: "Host(`registry.example.com`)"
           entryPoints:
             - web
           service: registry-service
           #tls:
           #  certResolver: le
    
       services:
         registry-service:
           loadBalancer:
             servers:
               - url: "http://registry:5000"
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
     http:
       routers:
         registry-ui-router:
           rule: "Host(`registry-ui.example.com`)"
           entryPoints:
             - web
           service: registry-ui-service
           #tls:
           #  certResolver: le
    
       services:
         registry-ui-service:
           loadBalancer:
             servers:
               - url: "http://registry-ui:80"
    

Testing

After deployment, we can test whether we can access the graphical interface. For example, the above settings will publish the graphical interface to https://registry-ui.example.com. Open the browser and enter the above URL. If all previous settings are correct, you will see the following page:

docker-registry-ui

We haven’t pushed any images to the registry yet, so the registry appears empty.

Usage

Assuming the container image registry service is deployed on computer A, and we want to pull and use a certain image on computer B. The steps are as follows:

Computer A: Pushing Images to the Registry

On computer A, you need to perform the following operations:

  1. Build the image locally, or pull the image from platforms like Docker Hub or GitHub. For example, pull the registry image from Docker Hub:
    1
    
    docker pull registry:3
    
  2. Tag the image with a new label:
    1
    
    docker tag registry:3 registry.example.com/registry:3
    
  3. Push the image to the self-hosted registry:
    1
    
    docker push registry.example.com/registry:3
    

After completing the above operations, you can see the registry image has been successfully uploaded on https://registry-ui.example.com:

docker-registry-ui

Computer B: Pulling Images from Our Registry

When using Docker on computer B, you only need to add our registry name registry.example.com/ before the image name you want to use, for example:

1
docker pull registry.example.com/registry:3

If using docker compose, it’s the same, just replace the image names in docker-compose.yml accordingly.

Licensed under CC BY-NC-SA 4.0
Last updated on Wednesday, March 11, 2026
comments powered by Disqus