Skip to content

Commit 797e4fd

Browse files
authored
Merge pull request #3 from obeone/feature/private-registry
Private registry
2 parents 9f5aa1c + d7cadc4 commit 797e4fd

File tree

6 files changed

+130
-62
lines changed

6 files changed

+130
-62
lines changed

.github/workflows/build-and-publish.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ jobs:
7070
COSIGN_EXPERIMENTAL: true
7171
DIGEST: ${{ steps.docker_build.outputs.digest }}
7272

73-
- name: Updage Docker Hub description
73+
- name: Update Docker Hub description
7474
uses: peter-evans/dockerhub-description@v4
7575
with:
7676
username: ${{ secrets.DOCKERHUB_USERNAME }}

README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
# Multi-Registry Pull Through Cache Setup Guide 🚀
22

3-
Welcome to the Multi-Registry Pull Through Cache Setup Guide! This project is designed to help you create an efficient, bandwidth-saving local mirror for Docker Hub images and other container registries. By setting up a pull-through cache, you can significantly reduce internet traffic and improve the speed of image pulls for your containerized environments. 🌐💨
3+
Welcome to the Multi-Registry Pull Through Cache Setup Guide! This project is designed to help you create an efficient, bandwidth-saving local mirror for Docker Hub images and other container registries, including private registries. By setting up a pull-through cache, you can significantly reduce internet traffic and improve the speed of image pulls for your containerized environments. 🌐💨
44

55
This script will generate a `compose.yaml` file (same as `docker-compose.yml`). It will include one registry service for each registry mirror you wish to set up. A Traefik Proxy will be placed as a frontend for routing and providing a TLS endpoint. Additionally, a Redis service will be provided to enhance performance.
66

7+
## Features ✨
8+
9+
- **Multi-Registry Support**: Set up mirrors for Docker Hub, GitHub Container Registry (GHCR), or any other container registries.
10+
- **Private Registry Integration**: Easily add a private registry to push and pull images from your private repositories.
11+
- **Bandwidth Optimization**: Save bandwidth by caching container images locally, reducing repeated downloads.
12+
- **Speed Improvements**: Expedite image pulls within your network, leading to faster deployments and scaling.
13+
- **Docker and Kubernetes Compatibility**: Seamlessly integrates with Docker and Kubernetes environments.
14+
- **Advanced Configuration**: Customize registry settings, including TTL and credentials, with a user-friendly setup.
15+
- **Simple Deployment**: Leverage Docker Compose for a straightforward setup and management of services.
16+
- **Traefik Proxy Integration**: Use Traefik for intelligent routing and secure TLS endpoints out of the box.
17+
- **Performance Enhancements**: Utilize Redis to improve caching operations and reduce latency.
18+
- **Environment-Friendly**: Lower external data transfer, contributing to a reduced carbon footprint.
19+
720
## Table of Contents 📚
821

922
- [Multi-Registry Pull Through Cache Setup Guide 🚀](#multi-registry-pull-through-cache-setup-guide-)
23+
- [Features ✨](#features-)
1024
- [Table of Contents 📚](#table-of-contents-)
1125
- [Purpose of the Project 🎯](#purpose-of-the-project-)
1226
- [How to Set Up the Project 🛠️](#how-to-set-up-the-project-️)
@@ -46,7 +60,6 @@ By using a pull-through cache, you can:
4660
- Access to the internet to pull initial images
4761
- Basic knowledge of Docker, Kubernetes, and container registries
4862

49-
5063
### Running with Docker
5164

5265
#### Run the Setup Script
@@ -100,7 +113,7 @@ docker run --rm -ti -v "./config.yaml:/app/config.yaml" -v "./compose:/app/compo
100113
```
101114

102115
5. **Review Advanced Configuration**
103-
After running the setup script, you should manually review the `config.yaml` file for advanced configurations such as TLS settings, Let's Encrypt, and more. More details about this file in [CONFIG.md](CONFIG.md)
116+
After running the setup script, you should manually review the `config.yaml` file for advanced configurations such as TLS settings, Let's Encrypt, addition of private registries, and more. More details about this file in [CONFIG.md](CONFIG.md)
104117

105118
```bash
106119
nano config.yaml # or use your preferred text editor
@@ -199,12 +212,12 @@ For Kubernetes clusters, you'll probably need to configure each node's container
199212
200213
## Conclusion 🎉
201214
202-
Congratulations! You've now set up a multi-registry pull-through cache that will serve as a local mirror for your container images. Enjoy faster image pulls, reduced external bandwidth, and a more resilient container environment!
215+
Congratulations! You've now set up a multi-registry pull-through cache that will serve as a local mirror for your container images, including private registry configurations. Enjoy faster image pulls, reduced external bandwidth, and a more resilient container environment!
203216
204217
---
205218
206219
Feel free to contribute to this project by submitting issues or pull requests. For questions or support, open an issue on the project's GitHub page. Happy caching! 🐋💾
207220
208221
---
209222
210-
**Keywords**: Docker, container registry, pull-through cache, Docker Hub mirror, containerd, dockerd, Kubernetes, k3s, RKE, RKE2, image caching, setup guide, local mirror, container image optimization.
223+
**Keywords**: Docker, container registry, pull-through cache, Docker Hub mirror, private registry, containerd, dockerd, Kubernetes, k3s, RKE, RKE2, image caching, setup guide, local mirror, container image optimization.

config.sample.yaml

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,31 @@
55
# in the compose file. The url is the url of the registry. The username and password are the credentials for the registry.
66
# You can add elements to the list. The setup will generate the compose file for every registry, and these elements will
77
# be available for generation of parts configs (like traefik, see below)
8+
# Type is `cache` for caching registries, `registry` for normal registries.
89
registries:
9-
- name: dockerhub
10-
url: https://registry-1.docker.io
11-
username: user
12-
password: pass
13-
- name: ghcr
14-
url: https://ghcr.io
15-
username: user
16-
password: pass
17-
- name: nvcr
18-
url: https://nvcr.io
19-
username: user
20-
password: pass
21-
- name: quay
22-
url: https://quay.io
23-
username: user
24-
password: pass
25-
ttl: 720h
10+
- name: dockerhub
11+
type: cache
12+
url: https://registry-1.docker.io
13+
username: user
14+
password: pass
15+
- name: ghcr
16+
type: cache
17+
url: https://ghcr.io
18+
username: user
19+
password: pass
20+
- name: nvcr
21+
type: cache
22+
url: https://nvcr.io
23+
username: user
24+
password: pass
25+
- name: quay
26+
type: cache
27+
url: https://quay.io
28+
username: user
29+
password: pass
30+
ttl: 720h
31+
- name: private
32+
type: registry
2633

2734
docker:
2835
# The docker compose config. This config is used to generate the docker-compose.yaml file. You can use the baseConfig
@@ -36,15 +43,15 @@ docker:
3643
image: traefik:v2.10
3744
restart: always
3845
command:
39-
- '--providers.file.filename=/etc/traefik/traefik.yaml'
46+
- "--providers.file.filename=/etc/traefik/traefik.yaml"
4047
ports:
41-
- '80:80'
42-
- '443:443'
48+
- "80:80"
49+
- "443:443"
4350
volumes:
44-
- './traefik.yaml:/etc/traefik/traefik.yaml:ro'
45-
- './acme:/etc/traefik/acme:rw'
51+
- "./traefik.yaml:/etc/traefik/traefik.yaml:ro"
52+
- "./acme:/etc/traefik/acme:rw"
4653
networks:
47-
- 'registries'
54+
- "registries"
4855
# Here is a sample of how to use environment variables in the docker compose config
4956
# used to configure (one of) ACME DNS challenge
5057
# environment:
@@ -57,27 +64,26 @@ docker:
5764
image: redis:7.2
5865
restart: always
5966
networks:
60-
- 'registries'
67+
- "registries"
6168
volumes:
62-
- './redis.conf:/usr/local/etc/redis/redis.conf:ro'
69+
- "./redis.conf:/usr/local/etc/redis/redis.conf:ro"
6370
command:
64-
- redis-server
65-
- /usr/local/etc/redis/redis.conf
71+
- redis-server
72+
- /usr/local/etc/redis/redis.conf
6673

6774
networks:
6875
registries: {}
6976

70-
7177
perRegistry:
7278
compose:
7379
image: registry:2
7480
restart: always
7581
volumes:
76-
- './{name}.yaml:/etc/docker/registry/config.yml:ro'
82+
- "./{name}.yaml:/etc/docker/registry/config.yml:ro"
7783
networks:
78-
- registries
84+
- registries
7985
environment:
80-
- 'REGISTRY_HTTP_SECRET=$REGISTRY_HTTP_SECRET'
86+
- "REGISTRY_HTTP_SECRET=$REGISTRY_HTTP_SECRET"
8187

8288
traefik:
8389
# The traefik config. This config is used to generate the traefik.yaml file. As with the docker compose config, you can
@@ -132,26 +138,26 @@ traefik:
132138
router:
133139
rule: "Host(`{name}.registry-cache.example.net`)"
134140
entryPoints:
135-
- web
136-
- websecure
141+
- web
142+
- websecure
137143

138144
# You must use the placeholder {name} in the service. The setup will replace the placeholder with the name of the registry.
139-
service: '{name}'
145+
service: "{name}"
140146
tls: {}
141147

142148
service:
143149
loadBalancer:
144150
# You must the declared service name in the compose config.
145151
servers:
146-
- url: "http://{name}:5000"
152+
- url: "http://{name}:5000"
147153

148154
registry:
149155
# The registry config is the same as the official registry config (https://docs.docker.com/registry/configuration/)
150156
# in one file. As it a different file for every registry, you can use placeholders from the registry config in the
151157
# whole config. The setup will replace the placeholder with the value from the registry config. For example, the
152158
# placeholder {name} will be replaced with the name of the registry.
153159
baseConfig:
154-
version: '0.1'
160+
version: "0.1"
155161
health:
156162
storagedriver:
157163
enabled: true
@@ -161,7 +167,7 @@ registry:
161167
addr: :5000
162168
headers:
163169
X-Content-Type-Options:
164-
- nosniff
170+
- nosniff
165171
log:
166172
fields:
167173
service: registry
@@ -186,4 +192,5 @@ registry:
186192
# Don’t set a db number. If redis key exists, db will be set to the right number.
187193

188194
# Proxy will be configured by the setup. You basically don't need to touch this.
195+
# Proxy will be removed in case of normal registry type. It is only used for cache registries.
189196
proxy: {}

functions.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,17 @@ def create_registry_config(config, registry, db):
104104
Returns:
105105
dict: The updated configuration.
106106
"""
107-
config['proxy']['remoteurl'] = registry['url']
108-
if 'username' in registry and 'password' in registry:
109-
config['proxy']['username'] = registry['username']
110-
config['proxy']['password'] = registry['password']
111-
if 'ttl' in registry:
112-
config['proxy']['ttl'] = registry['ttl']
107+
108+
if registry['type'] == 'cache':
109+
config['proxy']['remoteurl'] = registry['url']
110+
if 'username' in registry and 'password' in registry:
111+
config['proxy']['username'] = registry['username']
112+
config['proxy']['password'] = registry['password']
113+
if 'ttl' in registry:
114+
config['proxy']['ttl'] = registry['ttl']
115+
elif 'proxy' in config:
116+
del config['proxy']
117+
113118

114119
interpolated = interpolate_strings(config, registry)
115120

generate.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,25 @@
88
import functions
99
from functions import console
1010
from rich.text import Text
11+
import copy
1112

1213

1314
# Load config
1415
try:
1516
with open('config.yaml', 'r', encoding='UTF-8') as file:
16-
config = yaml.safe_load(file)
17+
base_config = yaml.safe_load(file)
1718
console.print(Text("Config loaded successfully", style="bold green"))
1819
except FileNotFoundError:
1920
console.print(Text("Error: config.yaml not found", style="bold red"))
2021
raise
2122

2223
try:
23-
registries = config['registries']
24-
docker_config = config['docker']['baseConfig']
25-
docker_perregistry = config['docker']['perRegistry']
26-
traefik_config = config['traefik']['baseConfig']
27-
traefik_perregistry = config['traefik']['perRegistry']
28-
registry_config = config['registry']['baseConfig']
24+
registries = base_config['registries']
25+
docker_config = base_config['docker']['baseConfig']
26+
docker_perregistry = base_config['docker']['perRegistry']
27+
traefik_config = base_config['traefik']['baseConfig']
28+
traefik_perregistry = base_config['traefik']['perRegistry']
29+
registry_config = base_config['registry']['baseConfig']
2930
except KeyError as e:
3031
console.print(Text(f"Error: Missing key in config file - {e}", style="bold red"))
3132
raise
@@ -45,7 +46,13 @@
4546

4647
# Creating registry configuration file
4748
try:
48-
registry_config_file = functions.create_registry_config(registry_config, registry, count_redis_db)
49+
# Retrocompatibility with old config files without type field
50+
if 'type' not in registry:
51+
registry['type'] = 'cache'
52+
console.print(Text(f"No type specified for registry {name}, defaulting to cache", style="bold yellow"))
53+
54+
registry_config_copy = copy.deepcopy(registry_config)
55+
registry_config_file = functions.create_registry_config(registry_config_copy, registry, count_redis_db)
4956
functions.write_yaml_file(f'compose/{name}.yaml', registry_config_file)
5057
console.print(Text(f"Registry configuration file created for {name}", style="bold green"))
5158
except Exception as e:
@@ -54,7 +61,8 @@
5461

5562
# Unsset password before interpolate variables
5663
try:
57-
registry.pop('password')
64+
if 'password' in registry:
65+
registry.pop('password')
5866
except KeyError:
5967
console.print(Text(f"Error: Missing 'password' key in registry configuration for {name}", style="bold red"))
6068
raise

0 commit comments

Comments
 (0)