Привет всем! В данной статье мы осветим наш опыт внедрения в платформу Gitorion собственного приватного реестра Docker-образов на базе CNCF Distribution Registry. Рассмотрим настройку аутентификации Docker-registry в Keycloak и подключение Web-интерфейса к Docker-registry.
Назначение и основные функции приватного реестра Docker-образов
Приватный реестр Docker-образов является подсистемой непрерывной доставки Continuous Delivery платформы Gitorion.
Пайплайны Jenkins билдят Docker-образы микросервисов и push-ат их в приватный реестр Docker-registry. Ниже для наглядности приведем команду сборки микросервиса backend:
docker buildx build --push -t registry.gitorion.ru/owneruser/backend/main:5c83f123556419654beb22eda68d1478c7d13825 --cache-to 'type=registry,ref=registry.gitorion.ru/owneruser/backend/main:latest,mode=min' --cache-from 'type=registry,ref=registry.gitorion.ru/owneruser/backend/main:latest' --cache-from 'type=registry,ref=registry.gitorion.ru/php:8.3.1-fpm-alpine3.19' .
после сборки, Docker-образ микросервиса бэкенда:
registry.gitorion.ru/owneruser/backend/main:5c83f123556419654beb22eda68d1478c7d13825
push-ится в частный приватный реестр Docker-образов https://registry.gitorion.ru
Чтобы ускорить процесс сборки, в качестве Docker-кэша используются Docker-образы, которые так же pull-ятся из частного приватного репозитория Docker-образов:
--cache-from 'type=registry,ref=registry.gitorion.ru/owneruser/backend/main:latest' --cache-from 'type=registry,ref=registry.gitorion.ru/php:8.3.1-fpm-alpine3.19'
На этапе деплоя Kubernetes pull-ит Docker-образы микросервисов из приватного реестра Docker-образов и использует для запуска контейнеров микросервисов в кластере Kubernetes:
apiVersion: v1 items: - apiVersion: apps/v1 kind: Deployment metadata: annotations: meta.helm.sh/release-name: staging-owneruser-backend meta.helm.sh/release-namespace: staging labels: app: staging-owneruser-backend app.kubernetes.io/managed-by: Helm name: staging-owneruser-backend namespace: staging spec: replicas: 1 selector: matchLabels: app: staging-owneruser-backend strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: labels: app: staging-owneruser-backend spec: containers: - image: registry.gitorion.ru/owneruser/backend/main:5c83f123556419654beb22eda68d1478c7d13825 imagePullPolicy: IfNotPresent name: backend
Также собственный приватный реестр Docker-образов позволяет обойти проблему с лимитом на количество скачиваний Docker-образов из публичного реестра. Публичные реестры имеют лимит на количество скачиваний с одного IP. При интенсивной работе большой команды программистов, часто запускающих пайплайны, скачивающие базовые образы из публичного реестра, можно вскоре получить ошибку, которая остановит всю работу:
ERROR: failed to solve: alpine:3.19.1: failed to resolve source metadata for docker.io/library/alpine:3.19.1: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/alpine/manifests/sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b: 429 Too Many Requests - Server message: toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
Поэтому, мы скачиваем один раз базовые образы микросервисов из публичного реестра и помещаем их в собственный приватный реестр Docker-образов:
docker login registry.gitorion.ru docker pull php:8.3.1-fpm-alpine3.19 docker tag php:8.3.1-fpm-alpine3.19 registry.gitorion.ru/php:8.3.1-fpm-alpine3.19 docker push registry.gitorion.ru/php:8.3.1-fpm-alpine3.19
И в дальнейшем пайплайны сборки Docker-образов используют базовые образы из частного приватного реестра Docker-образов. Пример базового слоя в Dockerfile микросервиса бэкенда:
FROM registry.gitorion.ru/php:8.3.1-fpm-alpine3.19
Кроме того, Docker-образы из приватного репозитория используются как Docker-кэш для ускорения сборки в команде билдинга Docker-образа docker buildx build
--cache-from 'type=registry,ref=registry.gitorion.ru/php:8.3.1-fpm-alpine3.19'
Агент Jenkins при запуске каждого пайплайна скачивает Docker-образ buildkit, что тоже может привести к блокировке из-за лимита на скачивание из публичного репозитория. Поэтому мы скачали Docker-образ buildkit из публичного реестра, поместили его в приватный реестр платформы, и пайплайны используют Docker-образ buildkit из приватного реестра:
docker buildx create --name container '--driver=docker-container' --config /etс/buildkitd.toml --driver-opt 'image=registry.gitorion.ru/buildkit:buildx-stable-1' --use container
Указанный выше подход позволяет вести разработку на платформе автономно без регулярного скачивания Docker-образов из публичного реестра при запуске каждого пайплайна.
Установка и настройка Docker-registry
Ниже мы приведем спецификацию контейнера в yaml манифесте и поясним ключевые настройки аутентификации Docker-registry в Keycloak. Как получить значения параметров из Keycloak мы поясним в следующем пункте чуть ниже.
containers: - image: registry:2 name: docker-registry env: - name: REGISTRY_AUTH value: "token" - name: REGISTRY_AUTH_TOKEN_REALM value: "https://auth.gitorion.ru/realms/gitorion/protocol/docker-v2/auth" - name: REGISTRY_AUTH_TOKEN_SERVICE value: "docker-registry" - name: REGISTRY_AUTH_TOKEN_ISSUER value: "https://auth.gitorion.ru/realms/gitorion" - name: REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE value: "/opt/certs/localhost_trust_chain.pem" - name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin value: "[https://registry.gitorion.ru]" - name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods value: "[HEAD,GET,OPTIONS,DELETE]" - name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials value: "[true]" - name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers value: "[Authorization,Accept,Cache-Control]" - name: REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers value: "[Docker-Content-Digest]" - name: REGISTRY_STORAGE_DELETE_ENABLED value: "true"
https://auth.gitorion.ru — URL, по которому доступен Keycloak в платформе;
image: registry:2 — используйте официальный образ Docker-registry;
REGISTRY_AUTH — выберите тип аутентификации в Docker-registry по токену из Keycloak;
REGISTRY_AUTH_TOKEN_REALM — задайте путь к области Keycloak, в которой находится Client для Docker-registry;
REGISTRY_AUTH_TOKEN_SERVICE — задайте имя клиента Docker-registry;
REGISTRY_AUTH_TOKEN_ISSUER — задайте источник, выдающий токены;
REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE — подключите SSL-сертификат доступа к области Keycloak, в которой находится Client для Docker-registry. Как получить сертификат области из Keycloak объяснено в следующем пункте ниже;
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin — при подключении аутентификации типа token, Docker-registry активирует механизм безопасности единого источника CORS и разрешает доступ к частному реестру только из своего же домена.
Настройка аутентификации Docker-registry в Keycloak
Чтобы не дублироваться, мы не будем в данной статье останавливаться на создании пользователей, групп и ролей, которые освещены в статье о внедрении в платформу Gitorion единой системы аутентификации SSO на базе Keycloak. Здесь мы рассмотрим только нюансы подключения Docker-registry к Keycloak.
По умолчанию Keycloak запускается без поддержки «docker-v2», и ее нужно включить, передав параметр KC_FEATURES в команде запуска Keycloak, либо через переменную окружения:
containers: - env: - name: KC_FEATURES value: docker image: docker.io/bitnami/keycloak:24.0.4-debian-12-r2 imagePullPolicy: IfNotPresent
В списке «Client Type» на вкладке создания клиента наряду с «OpenID Connect» и «SAML» появится «docker-v2».
Cоздайте Client для приватного реестра Docker-registry и задайте «docker-v2» в поле «Client Type». Введите имя клиента Docker-registry в поле «Client ID» такое же, как задали в переменной окружения REGISTRY_AUTH_TOKEN_SERVICE при настройке Docker-registry в предыдущем пункте выше, и нажмите кнопку Next.
В следующем окне вводить ничего не нужно, просто нажмите кнопку Next и затем кнопку Save.
Далее перейдите к настройкам только что созданного клиента docker-registry и в правом верхнем углу получите параметры настройки Docker-registry, нажав кнопку «Action» и выбрав пункт «Download adapter config».
Выберите пункт «Docker Compose YAML» и нажмите кнопку «Download».
В zip архиве в файле docker-compose.yaml вы найдете значения всех переменных окружения, которые нужно задать в предыдущем пункте настройки Docker-registry выше. В этом же архиве располагается файл certs/localhost_trust_chain.pem с SSL-сертификатом области, который нужно подключить к контейнеру docker-registry и задать в переменной окружения REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE.
Теперь можно залогиниться в наш частный репозиторий Docker-registry пользователем из Keycloak:
docker login registry.gitorion.ru Authenticating with existing credentials... Username (user): user Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
Еще в данном пункте хотим рассказать о неочевидной ошибке, сбивающей с толку, на диагностику и устранение которой может уйти много времени и сил. Даже при правильных настройках команда docker login может получить ошибку:
Cookie not found. Please make sure cookies are enabled in your browser.
а в логах Keycloak появится сообщение:
2024-05-18 18:27:25,916 WARN [org.keycloak.events] (executor-thread-1) type="CUSTOM_REQUIRED_ACTION_ERROR", realmId="1b5c5f6d-630a-4e5f-ad2e-a442eb1ca4d6", clientId="null", userId="null", ipAddress="10.10.7.143", error="cookie_not_found"
Такую ошибку может вызывать окно Keycloak, требующее от пользователя при первом входе сменить логин и пароль. Команда docker login ждет от Keycloak проверки логина и пароля и токен в ответ, чтобы поместить его в cookie. Вместо этого получает в ответ окно с предложением смены пароля и выдает данную ошибку.
Если администратор Keycloak отключит принудительную смену пароля при первом входе, то ошибку все еще может вызвать окно, предлагающее пользователю заполнить его персональные данные в профиле.
Общая рекомендация: перед первой попыткой залогиниться командой docker login, предварительно залогиньтесь в любой другой сервис платформы, имеющий Web-интерфейс, и убедитесь, что пользователь успешно аутентифицируется в Keycloak.
Подключение Web-интерфейса к Docker-registry
Docker-registry в стоке не имеет графического интерфейса пользователя. Можно конечно обращатьca к Docker-registry curl-ом, но это неудобно. Поэтому мы решили подключить Web-интерфейс от Joxit к Docker-registry.
Автор проекта приводит пример подключения своего Web-интерфейса к Docker-registry с аутентификацией по токену из Keycloak. Тестовый пример разработан для Docker-compose, но его можно использовать как отправную точку для подключения Web-интерфейса к Docker-registry в Kubernetes. Позади Ingress-nginx устанавливается промежуточный прокси на базе Nginx, который запрашивает у пользователя логин и пароль при доступе к Web-интерфейсу Docker-registry, передает их в Keycloak, получает токен доступа из Keycloak, и дальше Web-интерфейс использует токен при подключении к Docker-registry.
Пользователь вводит свой логин и пароль из Keycloak и получает доступ к Web-интерфейсу Docker-registry. На стартовой странице появится список всех репозиториев в приватном реестре Docker-образов.
Можно раскрыть один из репозиториев и получить список Tag-ов в нем и дополнительную информацию. Если потребуется, удалить ненужные Docker-образы.
Заключение
В данной статье мы осветили наш опыт внедрения собственного частного реестра Docker-образов на базе Docker-registry c аутентификацией в Keycloak и Web-интерфейсов от Joxit. Будем рады фидбеку, замечаниям и конструктивной критике. Не сочтите за труд и проголосуйте, пожалуйста, ниже. Спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/808017/
Добавить комментарий