Настройка собственного Docker Registry

Вы конечно можете использовать как публичный DockerHub, так и публичный или приватный Docker Registry в GitLab, но иногда возникает необходимость поднять свой локальный или сетевой Registry и стоит отметить, что сделать это совершенно несложно и сейчас я расскажу как это сделать.

Первым делом подготавливаем рабочее окружение Docker по инструкциям:

Итак, окружение готово. Проверяем, что можно скачать образы, можно их запускать и все инструменты управления работают и продолжим.

Запускаем образ который у нас будет обслуживать наш Registry. Выбираем, что-то типа LTS, а не RC всякие, мы тут в прод играем (https://hub.docker.com/_/registry).

# docker run -d -p 5000:5000 --name registry registry:2.8.3

Проверка.

# curl -I http://127.0.0.1:5000
HTTP/1.1 200 OK
Cache-Control: no-cache
Date: Mon, 24 Feb 2025 04:11:26 GMT

Выглядит красиво. Так как я фритюрницу от Cloud.ru использую, то надо будет сразу открыть 80 и 443 для всех, там Nginx повесим и 5000 только для доступа с одного конкретного адреса для тестов. И сразу же сделаем еще и доменное имя.

Группа безопасности у меня получилась следующего вида.

Проверяем доступность по сети порта 5000.

$ telnet 213.171.26.110 5000
Trying 213.171.26.110...
Connected to 213.171.26.110.
Escape character is '^]'.
^]
telnet> quit
Connection closed.

Пробуем локально получить образ с DockerHub, назначить ему тег и разместить в нашем хранилище образов.

# docker pull bash
# docker image tag bash:latest localhost:5000/bash:latest
# docker push localhost:5000/bash:latest

Если вы попробуете провести аналогичную операцию с удаленного хоста, то получите ошибку.

Get "https://registry.anton-c.ru:5000/v2/": http: server gave HTTP response to HTTPS client

В этом случае требуется добавить НА КЛИЕНТЕ с которого выполняем push параметр в файл daemon.json.

{
    "insecure-registries" : [ "213.171.26.110/32" ]
}

Перезапускаем демон docker НА КЛИЕНТЕ.

# systemctl restart docker

Проверяем, что необходимые параметры применились.

# docker info
Client: Docker Engine - Community
...
 Insecure Registries:
  213.171.26.110/32
  127.0.0.0/8
 Live Restore Enabled: false

Обратите внимание, что авторизации нет наш registry доступен всем и именно поэтому на этапе тестирования мы его прикрыли firewall для доступа из интернета.

Создадим базовый сервис для Docker Compose.

version: '3'

services:
  private-registry:
    image: registry:2.8.3
    ports:
    - "5000:5000"

Создаем файл авторизации используя apache2-utils.

# apt install apache2-utils
# htpasswd -Bc registry.password admin

Модифицируем docker-compose.yml для использования basic-авторизации.

services:
  private-registry:
    image: registry:2.8.3
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
      REGISTRY_AUTH_HTPASSWD_PATH: /tmp/registry.password
    volumes:
      - ./registry.password:/tmp/registry.password
    ports:
    - "5000:5000"

Проверяем, что больше мы не можем ничего пушить не авторизовавшись.

$ docker push registry.anton-c.ru:5000/bash:latest
The push refers to repository [registry.anton-c.ru:5000/bash]
4c9a226629c6: Preparing 
488f36d19f80: Preparing 
08000c18d16d: Preparing 
no basic auth credentials

Пробуем авторизоваться и повторить фокус.

chernousov@home-workstation-01:~$ docker login registry.anton-c.ru:5000
Username: admin
Password: 
WARNING! Your password will be stored unencrypted in /home/chernousov/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
chernousov@home-workstation-01:~$ docker push registry.anton-c.ru:5000/bash:latest
The push refers to repository [registry.anton-c.ru:5000/bash]
4c9a226629c6: Pushed 
488f36d19f80: Pushed 
08000c18d16d: Pushed 
latest: digest: sha256:e11ea53bf8d08835b861d8a0f34d45b5dcadef38514fb59d14d35dad7cbca204 size: 946

С авторизацией разобрались и теперь по старой схеме просто создаем Let’s encrypt сертификат и конфиг для https хоста и уходим от приседаний с портами и прописывания всяких трастов для http.

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
    listen 80;
    server_name www.registry.anton-c.ru registry.anton-c.ru;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443      ssl http2;

    server_name www.registry.anton-c.ru registry.anton-c.ru;

    access_log  /var/log/nginx/registry.anton-c.ru-access.log;
    error_log  /var/log/nginx/registry.anton-c.ru-error.log warn;

    ssl_certificate /etc/letsencrypt/live/registry.anton-c.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.anton-c.ru/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;

    client_max_body_size 64M;
    fastcgi_buffers 64 4K;

    proxy_connect_timeout 600;
    proxy_send_timeout 600;
    proxy_read_timeout 600;
    send_timeout 600;

    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    if ($host ~ ^www\.(?<domain>.+)$) {
      return  301 $scheme://$domain$request_uri;
    }

    location / {

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;

      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Server $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Scheme $scheme;
      proxy_pass http://127.0.0.1:5000;
    }

}

Собсно вот и все дела.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *