CI/CD Kubernetes платформа Gitorion. Приватный реестр Docker-образов с аутентификацией в Keycloak и Web-интерфейсом

от автора

Привет всем! В данной статье мы осветим наш опыт внедрения в платформу 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».

Выбор "Client type"

Выбор «Client type»

Cоздайте Client для приватного реестра Docker-registry и задайте «docker-v2» в поле «Client Type». Введите имя клиента Docker-registry в поле «Client ID» такое же, как задали в переменной окружения REGISTRY_AUTH_TOKEN_SERVICE при настройке Docker-registry в предыдущем пункте выше, и нажмите кнопку Next.

Параметры клиента Docker-registry

Параметры клиента Docker-registry

В следующем окне вводить ничего не нужно, просто нажмите кнопку Next и затем кнопку Save.

Далее перейдите к настройкам только что созданного клиента docker-registry и в правом верхнем углу получите параметры настройки Docker-registry, нажав кнопку «Action» и выбрав пункт «Download adapter config».

Настройки адаптера Docker-registry

Настройки адаптера Docker-registry

Выберите пункт «Docker Compose YAML» и нажмите кнопку «Download».

Скачайте настройки адаптера Docker-registry

Скачайте настройки адаптера Docker-registry

В 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 с предложением смены пароля

Окно Keycloak с предложением смены пароля

Если администратор 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.

Окно аутентификации пользователя в Web-интерфейсе Docker-registry

Окно аутентификации пользователя в Web-интерфейсе Docker-registry

Пользователь вводит свой логин и пароль из Keycloak и получает доступ к Web-интерфейсу Docker-registry. На стартовой странице появится список всех репозиториев в приватном реестре Docker-образов.

Список репозиториев в приватном реестре Docker-образов

Список репозиториев в приватном реестре Docker-образов

Можно раскрыть один из репозиториев и получить список Tag-ов в нем и дополнительную информацию. Если потребуется, удалить ненужные Docker-образы.

Список Tag-ов и дополнительная информация

Список Tag-ов и дополнительная информация

Заключение

В данной статье мы осветили наш опыт внедрения собственного частного реестра Docker-образов на базе Docker-registry c аутентификацией в Keycloak и Web-интерфейсов от Joxit. Будем рады фидбеку, замечаниям и конструктивной критике. Не сочтите за труд и проголосуйте, пожалуйста, ниже. Спасибо за внимание!

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

А какой реестр Docker-образов используете Вы?

0% CNCF Distribution Registry0
26.67% Harbor4
33.33% GitLab5
40% Nexus6
0% другой вариант0

Проголосовали 15 пользователей. Воздержался 1 пользователь.

ссылка на оригинал статьи https://habr.com/ru/articles/808017/


Комментарии

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

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