|
| 1 | +--- |
| 2 | +title: "Container Registry" |
| 3 | +description: "A description on how to run a local container registry with GMT" |
| 4 | +date: 2025-06-26T01:49:15+00:00 |
| 5 | +weight: 1009 |
| 6 | +--- |
| 7 | + |
| 8 | +GMT does **not** come with a container registry bundled. But since it builds on *docker* it can benefit from it's capability to query a private container registry. |
| 9 | + |
| 10 | +Here we just want to show you the steps we took to get it running. Please consult the manuals of the respective tool vendors for configuration details |
| 11 | + |
| 12 | +## Why would you set up a container registry |
| 13 | + |
| 14 | +GMT will download images on measurement and keep them in the cache by default. If you just measure software inside their containers this usually poses no issue. |
| 15 | +But if you also want to caputre and evaluate host level metrics you will notice that over time the disk will fill up with images. |
| 16 | + |
| 17 | +To always have a clean system you can instruct GMT to delete images on every run and pull images fresh. To not incur the costly network traffic every time you can pull these images only from the local network, effectively centralizing the location where images are kept. |
| 18 | + |
| 19 | +If you run GMT in cluster mode you will then benefit from having the machines always with a clean file sytem and pulling from a central registry that keeps the images cached. |
| 20 | + |
| 21 | +## Container Registry |
| 22 | + |
| 23 | +We choose [registry](https://hub.docker.com/_/registry) which is the *CNCF* supported and most used library. It comes with a reference |
| 24 | +implementation that is suffcient for local or setups behind NATs. |
| 25 | + |
| 26 | +Our compose file for the registry: |
| 27 | + |
| 28 | +```yml |
| 29 | +services: |
| 30 | + registry: |
| 31 | + image: registry:3 |
| 32 | + container_name: registry |
| 33 | + restart: always |
| 34 | +# ports: # do not make available directly to the outside |
| 35 | +# - "5001:5000" # internal, accessed via nginx |
| 36 | + environment: |
| 37 | + REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io |
| 38 | + REGISTRY_STORAGE_DELETE_ENABLED: "false" |
| 39 | + OTEL_TRACES_EXPORTER: none |
| 40 | + volumes: |
| 41 | + - /mnt/cluster_caches/docker:/var/lib/registry # we expect a storage system mounted on /mnt/cluster_caches/docker ... for instance an SSD |
| 42 | + |
| 43 | + nginx: |
| 44 | + image: nginx:alpine |
| 45 | + container_name: registry-nginx |
| 46 | + restart: always |
| 47 | + ports: |
| 48 | + - "5000:5000" |
| 49 | + volumes: |
| 50 | + - ./nginx.conf:/etc/nginx/nginx.conf:ro |
| 51 | +``` |
| 52 | +
|
| 53 | +Our *NGINX* file: |
| 54 | +
|
| 55 | +```nginx |
| 56 | + |
| 57 | +worker_processes 1; |
| 58 | + |
| 59 | +events { worker_connections 1024; } |
| 60 | + |
| 61 | +http { |
| 62 | + server { |
| 63 | + listen 5000; |
| 64 | + |
| 65 | + location /v2/ { |
| 66 | + limit_except GET HEAD { # we do not want to let people store images. Unsure if OPTIONS should also be allowed ... |
| 67 | + deny all; |
| 68 | + } |
| 69 | + proxy_pass http://registry:5000; |
| 70 | + } |
| 71 | + } |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +To have these servers always running we use a *systemd* service in `~/.config/systemd/user/container-registry.service`: |
| 76 | + |
| 77 | +```bash |
| 78 | +[Unit] |
| 79 | +Description=Start Container Registry with NGINX |
| 80 | + |
| 81 | +[Service] |
| 82 | +ExecStart=%h/container-registry/startup-docker.sh |
| 83 | +Type=simple |
| 84 | +Restart=on-failure |
| 85 | +RestartSec=5s |
| 86 | +StartLimitBurst=10 |
| 87 | +StartLimitInterval=0 |
| 88 | + |
| 89 | +[Install] |
| 90 | +WantedBy=default.target] |
| 91 | +``` |
| 92 | + |
| 93 | +And a startup script in `~/container-registry/startup-docker.sh`: |
| 94 | + |
| 95 | +```bash |
| 96 | +#!/bin/bash |
| 97 | +docker context use rootless |
| 98 | +docker compose -f ~/container-registry/compose.yml up -d |
| 99 | +``` |
| 100 | + |
| 101 | +Since the container registry we created is *insecure* (aka not using TLS) *docker* needs special allowance to use it. |
| 102 | + |
| 103 | +In the `daemon.json`: |
| 104 | + |
| 105 | +```json |
| 106 | +{ |
| 107 | + ... |
| 108 | + "insecure-registries": ["YOUR_IP:5000"], |
| 109 | +} |
| 110 | +``` |
| 111 | + |
| 112 | +### Security |
| 113 | + |
| 114 | +It is highly recommended to have docker rootless active for the docker daemon on the machine that runs the registry! |
| 115 | + |
| 116 | +See [Docker Rootless →]({{< relref "installation/installation-linux" >}}) how to do that. |
| 117 | + |
| 118 | +TLS is only required if your registry is public accessible. If you have it local or behind a NAT with only |
| 119 | +controlled machines, it is not needed. |
| 120 | + |
| 121 | +### Set your registry as default |
| 122 | + |
| 123 | +In the `daemon.json`: |
| 124 | + |
| 125 | +```json |
| 126 | +{ |
| 127 | + ... |
| 128 | + "registry-mirrors": ["http://YOUR_IP:5000"] |
| 129 | +} |
| 130 | +``` |
| 131 | + |
| 132 | +### Limit access to only your registry |
| 133 | + |
| 134 | +The default *docker CLI* will always fail-over to Docker Hub. |
| 135 | + |
| 136 | +If you do not want that you should block it on DNS level, which is the safest. |
| 137 | + |
| 138 | +Add to `/etc/hosts`: |
| 139 | + |
| 140 | +```log |
| 141 | +0.0.0.0 registry-1.docker.io auth.docker.io |
| 142 | +``` |
| 143 | + |
| 144 | +### Test your registry |
| 145 | + |
| 146 | +Try with *curl*: |
| 147 | + |
| 148 | +- `$ curl -s http://YOUR_IP:5000/v2/_catalog` |
0 commit comments