registry: Upgrade to v3, lower bcrypt cost, route /v2 directly

- Upgrade registry to 3.0.0 (new config path, redis addrs)
- Generate htpasswd with bcrypt cost 5; cost 12 added ~350ms per request
- Route /v2 straight to the registry instead of through the UI's nginx

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kacper Donat 2026-10-26 21:29:40 +01:00
parent 0cb34f5faa
commit bf9d98a0d5
4 changed files with 27 additions and 16 deletions

View File

@ -11,7 +11,7 @@ storage:
{{ registry_storage|to_nice_yaml(indent=2, width=140)|indent(2) }} {{ registry_storage|to_nice_yaml(indent=2, width=140)|indent(2) }}
redis: redis:
addr: redis:6379 addrs: [redis:6379]
http: http:
addr: :5000 addr: :5000

View File

@ -9,20 +9,28 @@ services:
memory: 256M memory: 256M
registry: registry:
image: registry:2 image: registry:3.0.0
secrets: secrets:
- source: htpasswd_{{ registry_htpasswd.stat.checksum }} - source: htpasswd_{{ registry_htpasswd.stat.checksum }}
target: /etc/docker/registry/htpasswd target: /etc/docker/registry/htpasswd
configs: configs:
- source: registry_{{ registry_config.checksum }} - source: registry_{{ registry_config.checksum }}
target: /etc/docker/registry/config.yml target: /etc/distribution/config.yml
environment: environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true - REGISTRY_STORAGE_DELETE_ENABLED=true
deploy: deploy:
placement: placement:
constraints: constraints:
- node.role == manager - node.role == manager
networks: ['default'] labels:
- traefik.enable=true
- traefik.http.routers.{{ service }}-api.rule=Host(`{{ service }}.{{ main_domain }}`) && PathPrefix(`/v2`)
- traefik.http.routers.{{ service }}-api.priority=100
- traefik.http.routers.{{ service }}-api.tls=true
- traefik.http.routers.{{ service }}-api.tls.certresolver=lets-encrypt
- traefik.http.routers.{{ service }}-api.service={{ service }}-api
- traefik.http.services.{{ service }}-api.loadbalancer.server.port=5000
networks: ['{{ ingress_network }}', 'default']
ui: ui:
image: joxit/docker-registry-ui:2.5.6 image: joxit/docker-registry-ui:2.5.6
@ -42,14 +50,14 @@ services:
networks: ['{{ ingress_network }}', 'default'] networks: ['{{ ingress_network }}', 'default']
image-cleanup-job: image-cleanup-job:
image: registry:2 image: registry:3.0.0
command: ["registry", "garbage-collect", "/etc/docker/registry/config.yml", "-m"] command: ["registry", "garbage-collect", "/etc/distribution/config.yml", "-m"]
secrets: secrets:
- source: htpasswd_{{ registry_htpasswd.stat.checksum }} - source: htpasswd_{{ registry_htpasswd.stat.checksum }}
target: /etc/docker/registry/htpasswd target: /etc/docker/registry/htpasswd
configs: configs:
- source: registry_{{ registry_config.checksum }} - source: registry_{{ registry_config.checksum }}
target: /etc/docker/registry/config.yml target: /etc/distribution/config.yml
deploy: deploy:
placement: placement:
constraints: constraints:

View File

@ -7,16 +7,17 @@
tags: tags:
- config - config
# Registry checks the bcrypt hash on every request, so a low cost keeps it fast.
# Salt is derived from the user name to keep the file stable between runs.
- name: 'Generate passwords file for "{{ service }}"' - name: 'Generate passwords file for "{{ service }}"'
community.general.htpasswd: ansible.builtin.copy:
path: "{{ remote_service_path }}/config/htpasswd" dest: "{{ remote_service_path }}/config/htpasswd"
name: "{{ registry_user.name }}" content: |
crypt_scheme: bcrypt {% for registry_user in registry_users %}
password: "{{ registry_user.password }}" {{ registry_user.name }}:{{ registry_user.password | password_hash('bcrypt', salt=((service ~ ':' ~ registry_user.name) | hash('sha256'))[:22], rounds=registry_bcrypt_rounds) }}
loop: "{{ registry_users }}" {% endfor %}
loop_control: mode: "0600"
loop_var: registry_user no_log: true
label: "{{ registry_user.name }}"
tags: tags:
- config - config

View File

@ -0,0 +1,2 @@
---
registry_bcrypt_rounds: 5