Установка Kubeflow

Раздел по ML-сценариям уточняется. Отдельные шаги и примеры могут быть дополнены. При возникновении вопросов обратитесь к команде платформы «Штурвал».

Инструкция описывает установку Kubeflow в созданном клиентском кластере. Потребуется доступ к клиентскому кластеру, кластеру управления и хосту зеркала.

В результате в кластере будут развернуты:

  • Kubeflow — notebooks, pipelines, experiments, training jobs, serving (KServe внутри кластера), Katib, TensorBoard;
  • Ingress для доступа к Kubeflow по адресу kubeflow.<commonName>.

Дополнительно: Внешний доступ к KServe.

Как работать с этой страницей

Шаг 1 выполняется в кластере управления: создание отдельного OIDC-клиента для Kubeflow. Не используйте OIDC-клиента других сервисов платформы.

Шаг 2 выполняется в клиентском кластере: SSP для Cilium, цепочка установки kubeflow-step-0 … kubeflow-step-4, проверка лейблов Istio. После шага 1 перейдите в клиентский кластер.

В конце каждой вкладки GUI и CLI указано, как проверить результат. Не переходите к следующему шагу, пока не получите ожидаемый результат проверки.

Внешний доступ к KServe на установку Kubeflow не влияет и описан отдельно: Внешний доступ к KServe.

Для шагов в клиентском кластере приведены вкладки GUI и CLI. Загрузка патчей в зеркало выполняется на хосте зеркала и только из консоли.

В GUI манифесты Kubernetes и кастомных ресурсов платформы загружаются через импорт манифестов: иконка импорта слева от имени пользователя → вставьте YAML → Проверить → Сохранить. Несколько объектов в одном файле разделяйте ---. Установка чартов: Как развернуть новый сервис.

Подставляйте свои значения вместо плейсхолдеров:

Плейсхолдер Откуда взять
<commonName> status.appliedCustomValues.controller.shturval.commonName у SSC shturval-ingress-controller
<CLUSTER_NAME> имя клиентского кластера

Перед началом

Клиентский кластер уже установлен. Проверьте:

  • ShturvalUpdate shturval-update в неймспейсе shturval-update-system имеет .status.ready=true;
  • у SSC shturval-ingress-controller заполнен commonName — из него собирается хост kubeflow.<commonName>;
  • лицензия поддерживает Enterprise ML: Виды лицензии.

Для CLI-пути на рабочей машине администратора нужны kubectl и openssl. openssl потребуется, чтобы сгенерировать cookie_secret для oauth2-proxy Kubeflow и при HTTPS снять CA внешнего S3.

  1. Откройте клиентский кластер.
  2. Администрирование → Кастомные ресурсы → группа update.shturval.tech → ShturvalUpdate → объект shturval-update. В статусе должно быть ready: true.
  3. Сервисы и репозитории → Установленные сервисы → shturval-ingress-controller → Управлять → вкладка Манифест. Найдите controller.shturval.commonName и сохраните значение — это <commonName>.
export KUBECONFIG_CLIENT=<путь-к-kubeconfig-клиентского-кластера>

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get su -n shturval-update-system shturval-update \
  -o jsonpath='{.status.ready}{"\n"}'

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get ssc shturval-ingress-controller \
  -o jsonpath='{.status.appliedCustomValues.controller.shturval.commonName}{"\n"}'

Этот шаг выполняется на хосте зеркала, не в GUI кластера. Без него клиентский кластер не скачает Helm-чарты Kubeflow.

sudo -i
cd /opt/mirror

Примените архивы из комплекта поставки в этом порядке:

Компонент Что добавляет в зеркало
Kubeflow, архивы 1–4 базовые чарты и образы Kubeflow
Kubeflow Helm patch обновления Helm-чартов Kubeflow
Kubeflow patch дополнительные исправления Kubeflow

Для каждого архива:

rm -rf shturval-patch && mkdir shturval-patch
wget <URL_архива_из_поставки> -O shturval-patch/<имя-файла>.tgz
./stm patch apply
rm -rf shturval-patch
Обратите внимание! URL архивов берите только из комплекта поставки. Не публикуйте внутренние ссылки на файловые серверы.

Эти значения понадобятся в манифестах следующих шагов.

Параметр Обязателен Назначение Откуда взять Где используется
CERT_CLUSTER_ISSUER Да ClusterIssuer для TLS ingress Kubeflow. Обычно shturval-self-signed имя ClusterIssuer в клиентском кластере: Администрирование → ClusterIssuers. Если своего issuer нет, используйте shturval-self-signed шаг 2, TLS ingress Kubeflow
cookie_secret Да для oauth2-proxy Kubeflow сгенерируйте командой openssl rand -hex 16 шаг 2, kubeflow-step-1

Выберите хранилища Kubeflow Pipelines и Katib

Kubeflow Pipelines использует один экземпляр MySQL и одно объектное хранилище для всего кластера — это ограничение исходного проекта Kubeflow. Общая учётная запись KFP UI должна иметь доступ к бакетам всех профилей. Katib хранит метаданные экспериментов в отдельной базе MySQL, которую можно разместить на том же сервере. KFP поддерживает MySQL, но не PostgreSQL.

Обратите внимание! Объектное хранилище должно поддерживать AWS IAM API (создание пользователей и политик), а не только операции S3 вроде PutObject/GetObject. Контроллер профилей Pipelines (sync.py) создаёт IAM-пользователя и policy на каждый Profile. Upstream Kubeflow ориентирован на SeaweedFS. Обычный «S3-compatible» без IAM (часть реализаций Ceph RGW, MinIO без IAM) не подойдёт.

Подготовьте значения внешних MySQL и S3, которые понадобятся на шаге 2:

Параметр Назначение Где используется
KFP_MYSQL_HOST / KFP_MYSQL_PORT адрес внешнего MySQL для Pipelines шаг 2, kubeflow-step-2
KFP_MYSQL_PIPELINE_DB / KFP_MYSQL_METADATA_DB две базы: pipelines и metadata шаг 2, kubeflow-step-2
KFP_MYSQL_USER / KFP_MYSQL_PASSWORD учётная запись MySQL шаг 2, kubeflow-step-2
KFP_S3_ENDPOINT URL объектного хранилища (со схемой https:// или http://). При HTTPS с эндпойнта снимается CA и передаётся в s3.caCert чарта step-2 шаг 2, kubeflow-step-2
KFP_AWS_IAM_ENDPOINT endpoint AWS IAM API того же хранилища: sync.py создаёт per-profile пользователей и policy шаг 2, kubeflow-step-2
KFP_AWS_REGION / KFP_S3_BUCKET регион и bucket артефактов шаг 2, kubeflow-step-2
KFP_AWS_ACCESS_KEY / KFP_AWS_SECRET_KEY глобальные ключи для KFP UI и controller шаг 2, kubeflow-step-2
KATIB_MYSQL_HOST / KATIB_MYSQL_PORT / KATIB_MYSQL_DB внешняя MySQL для Katib шаг 2, kubeflow-step-3
KATIB_MYSQL_USER / KATIB_MYSQL_PASSWORD учётная запись Katib шаг 2, kubeflow-step-3
KATIB_MYSQL_SECRET_NAME имя Secret с credentials Katib, по умолчанию katib-mysql-secrets шаг 2, kubeflow-step-3

Шаг 1. В кластере управления создайте OIDC-клиент для Kubeflow

OIDC-клиент нужен для доступа в Kubeflow через SSO платформы. Ресурс создаётся в кластере управления, в неймспейсе с именем клиентского кластера.

Клиент должен принимать redirect URI для kubeflow.<commonName>. При providerType: shturval платформа формирует клиента внутреннего провайдера.

  1. Откройте кластер управления.
  2. Импортируйте манифест, использовав свои значения параметров:
apiVersion: auth.shturval.tech/v1beta1
kind: AuthOidcClient
metadata:
  name: <CLUSTER_NAME>-kubeflow
  namespace: <CLUSTER_NAME>
spec:
  providerType: shturval

Либо создайте объект в Администрирование → Кастомные ресурсы → API-группа auth.shturval.tech → AuthOidcClient → + Добавить.

  1. Дождитесь, пока в статусе объекта появится ready: true, заполнятся status.clientInfo.issuerUrl и status.clientSecretRef.
  2. Перейдите в неймспейс <CLUSTER_NAME> и откройте Secret из clientSecretRef (имя вида <CLUSTER_NAME>-kubeflow-<случайный-суффикс>). Скопируйте client_id и client_secret.
  3. Сохраните issuer URL из статуса AuthOidcClient — это OIDC_ISSUER_URL.
export KUBECONFIG_MGMT=<путь-к-kubeconfig-кластера-управления>
export CLUSTER_NAME=<имя-клиентского-кластера>

kubectl --kubeconfig "${KUBECONFIG_MGMT}" apply -f - <<EOF
apiVersion: auth.shturval.tech/v1beta1
kind: AuthOidcClient
metadata:
  name: ${CLUSTER_NAME}-kubeflow
  namespace: ${CLUSTER_NAME}
spec:
  providerType: shturval
EOF

Дождитесь готовности (до ~180 с):

kubectl --kubeconfig "${KUBECONFIG_MGMT}" \
  get authoidcclient "${CLUSTER_NAME}-kubeflow" -n "${CLUSTER_NAME}" \
  -o jsonpath='{.status.ready}{"\n"}'

Извлеките параметры:

SECRET_NAME="$(kubectl --kubeconfig "${KUBECONFIG_MGMT}" \
  get authoidcclient "${CLUSTER_NAME}-kubeflow" -n "${CLUSTER_NAME}" \
  -o jsonpath='{.status.clientSecretRef.name}')"

SECRET_NS="$(kubectl --kubeconfig "${KUBECONFIG_MGMT}" \
  get authoidcclient "${CLUSTER_NAME}-kubeflow" -n "${CLUSTER_NAME}" \
  -o jsonpath='{.status.clientSecretRef.namespace}')"

export OIDC_CLIENT_ID="$(kubectl --kubeconfig "${KUBECONFIG_MGMT}" \
  get secret "${SECRET_NAME}" -n "${SECRET_NS}" \
  -o jsonpath='{.data.client_id}' | base64 -d)"

export OIDC_CLIENT_SECRET="$(kubectl --kubeconfig "${KUBECONFIG_MGMT}" \
  get secret "${SECRET_NAME}" -n "${SECRET_NS}" \
  -o jsonpath='{.data.client_secret}' | base64 -d)"

export OIDC_ISSUER_URL="$(kubectl --kubeconfig "${KUBECONFIG_MGMT}" \
  get authoidcclient "${CLUSTER_NAME}-kubeflow" -n "${CLUSTER_NAME}" \
  -o jsonpath='{.status.clientInfo.issuerUrl}')"
Параметр Назначение Откуда взять Где используется
OIDC_CLIENT_ID идентификатор OIDC-клиента Kubeflow Secret из status.clientSecretRef у AuthOidcClient <CLUSTER_NAME>-kubeflow в неймспейсе <CLUSTER_NAME>: ключ client_id шаг 2, kubeflow-step-1
OIDC_CLIENT_SECRET секрет OIDC-клиента Kubeflow тот же Secret: ключ client_secret шаг 2, kubeflow-step-1
OIDC_ISSUER_URL URL платформы статус AuthOidcClient: status.clientInfo.issuerUrl шаг 2, kubeflow-step-1

Шаг 2. Установите Kubeflow

Обратите внимание! Все действия этого шага — в клиентском кластере. Только OIDC-клиент на шаге 1 создается в кластере управления, далее все в клиентском.

Kubeflow устанавливается с помощью SSC kubeflow-step-0 — kubeflow-step-4. Все пять сервисов можно создать одновременно в режиме Авто: зависимости обеспечат последовательную установку. В спецификации каждого сервиса укажите предыдущий шаг в spec.dependency. Дождитесь, когда все SSC перейдут в состояние Healthy.

Дополнительно примените SSP shturval-networking-for-istio для shturval-networking (Cilium). Kubeflow работает через Istio: в поды добавляется sidecar, который сам ведёт сеть пода. Cilium по умолчанию считает себя единственным сетевым плагином на узле и может перехватывать тот же трафик. Конфигурация SSP разрешает Cilium сосуществовать с sidecar Istio и оставляет socket-балансировку Cilium только на хосте, не внутри подов.

После установки интерфейс Kubeflow доступен по адресу https://kubeflow.<commonName>/. Снаружи запрос принимает Ingress (ingressClassName: nginx) на хост kubeflow.<commonName>, внутри кластера он направляет трафик на сервис istio-ingressgateway порт 8080 — это вход Istio для Kubeflow. Хост, TLS и backend задаются в спецификации kubeflow-step-2. Запись DNS kubeflow.<commonName> должна указывать на Ingress клиентского кластера.

2.1. ShturvalServicePatch для Cilium

  1. Перейдите в клиентский кластер.
  2. Импортируйте SSP:
apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServicePatch
metadata:
  name: shturval-networking-for-istio
spec:
  patchOrder: 100
  customvalues:
    socketLB:
      hostNamespaceOnly: true
    cni:
      exclusive: false
  shturvalServiceConfigName: shturval-networking

Проверить применение ShturvalServicePatch: Установленные сервисы → shturval-networking → вкладка ShturvalServicePatch.

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" apply -f - <<'EOF'
apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServicePatch
metadata:
  name: shturval-networking-for-istio
spec:
  patchOrder: 100
  customvalues:
    socketLB:
      hostNamespaceOnly: true
    cni:
      exclusive: false
  shturvalServiceConfigName: shturval-networking
EOF

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get shturvalservicepatch shturval-networking-for-istio

2.2. Установка Kubeflow

Репозиторий shturval, неймспейс default для всех сервисов. Имена экземпляров должны совпадать с именами чартов: kubeflow-step-0 … kubeflow-step-4.

Перед установкой SSC выполните два дополнительных действия:

  1. Включите shturval-policy-manager и дождитесь, когда сервис перейдёт в состояние Healthy.
  2. Создайте ClusterPolicy enforce-istio-injection-kubeflow. Она возвращает лейбл istio-injection=enabled на неймспейс default, если контроллер платформы снимает его при обработке системных лейблов. Без этого лейбла поды Kubeflow создаются без sidecar-контейнера Istio и не могут корректно работать в сервисной сетке с mTLS.

Включите менеджер политик:

  1. Откройте Сервисы и репозитории → Установленные сервисы → shturval-policy-manager → Управлять.
  2. На вкладке Сервис измените режим управления на Авто и нажмите Сохранить.
  3. Дождитесь состояния Healthy. В неймспейсе kyverno все поды контроллеров должны перейти в состояние Running. Установка может занять до 10 минут.

После запуска менеджера политик откройте Безопасность → Менеджер политик безопасности → + Добавить политику безопасности и создайте политику:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-istio-injection-kubeflow
  annotations:
    policies.kyverno.io/title: Enforce istio-injection=enabled on default namespace
    policies.kyverno.io/category: Istio
spec:
  rules:
    - name: add-istio-injection-label
      match:
        any:
          - resources:
              kinds:
                - Namespace
              names:
                - default
              operations:
                - CREATE
                - UPDATE
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              istio-injection: enabled

Убедитесь, что enforce-istio-injection-kubeflow появилась в списке политик и не находится в состоянии ошибки.

  1. Сервисы и репозитории → Доступные чарты, репозиторий shturval. Действия в клиентском кластере.
  2. Установите kubeflow-step-0: неймспейс default, режим Авто. Customvalues не нужны. Это базовые CRD.
  3. Установите kubeflow-step-1 (Dex и oauth2-proxy). Зависимость: kubeflow-step-0. Режим Авто. В спецификации укажите OIDC-параметры с шага 1 и cookie_secret из раздела «Подготовьте параметры»:
dex:
  oidc:
    client_id: "<OIDC_CLIENT_ID>"
    client_secret: "<OIDC_CLIENT_SECRET>"
oauth2-proxy:
  oauth2Cfg:
    oidc_issuer_url: "<OIDC_ISSUER_URL>"
    redirect_url: https://kubeflow.<commonName>/oauth2/callback
  oidc:
    client_id: "<OIDC_CLIENT_ID>"
    client_secret: "<OIDC_CLIENT_SECRET>"
    cookie_secret: "<cookie_secret>"
  1. Установите kubeflow-step-2 (Pipelines, хранилища и ingress). Зависимость: kubeflow-step-1. Режим Авто. В спецификации укажите внешние MySQL и S3 с поддержкой AWS IAM, поле serviceName оставьте пустым:
platform-agnostic-mutli-user:
  seaweedfs:
    enabled: false
  mysql:
    enabled: false
    external:
      host: "<KFP_MYSQL_HOST>"
      port: <KFP_MYSQL_PORT>
      pipelineDatabase: "<KFP_MYSQL_PIPELINE_DB>"
      metadataDatabase: "<KFP_MYSQL_METADATA_DB>"
      username: "<KFP_MYSQL_USER>"
      password: "<KFP_MYSQL_PASSWORD>"
      serviceName: ""
  pipelinesProfileController:
    env:
      awsEndpointUrl: "<KFP_AWS_IAM_ENDPOINT>"
      s3EndpointUrl: "<KFP_S3_ENDPOINT>"
      awsRegion: "<KFP_AWS_REGION>"
      s3Bucket: "<KFP_S3_BUCKET>"
    awsCredentials:
      accessKeyValue: "<KFP_AWS_ACCESS_KEY>"
      secretKeyValue: "<KFP_AWS_SECRET_KEY>"
  s3:
    caCert: "<PEM-сертификат-CA-если-S3-по-HTTPS>"
  ingress:
    enabled: true
    annotations:
      cert-manager.io/cluster-issuer: "<CERT_CLUSTER_ISSUER>"
      cert-manager.io/revision-history-limit: "5"
    ingressClassName: nginx
    rules:
      - host: kubeflow.<commonName>
        http:
          paths:
            - backend:
                service:
                  name: istio-ingressgateway
                  port:
                    number: 8080
              path: /
              pathType: Prefix
    tls:
      - hosts:
          - kubeflow.<commonName>
        secretName: kubeflow-ingress-tls

Если S3 работает по HTTP, оставьте s3.caCert пустым. Если по HTTPS, вставьте PEM корневого сертификата.

  1. Установите kubeflow-step-3 (Katib). Зависимость: kubeflow-step-2. Режим Авто. Спецификация:
katib:
  mysql:
    enabled: false
    external:
      host: "<KATIB_MYSQL_HOST>"
      port: <KATIB_MYSQL_PORT>
      database: "<KATIB_MYSQL_DB>"
      username: "<KATIB_MYSQL_USER>"
      password: "<KATIB_MYSQL_PASSWORD>"
      secretName: "<KATIB_MYSQL_SECRET_NAME>"
      serviceName: ""
  1. Установите kubeflow-step-4 (завершающие компоненты). Customvalues не нужны. Зависимость: kubeflow-step-3. Режим Авто.
  2. Дождитесь, когда kubeflow-step-0 … kubeflow-step-4 перейдут в состояние Healthy. Если сервис долго не переходит в это состояние, найдите причину: Устранение неполадок.

После установки kubeflow-step-2 проверьте ConfigMap namespace-labels-data-<случайный-суффикс> в неймспейсе default:

  1. Откройте неймспейс default → Хранилище → ConfigMaps и найдите объект, имя которого начинается с namespace-labels-data-.
  2. В значении ключа namespace-labels.yaml должна быть строка istio-injection: "enabled".
  3. Если строки нет, добавьте её и сохраните ConfigMap. Не добавляйте строку повторно.

Контроллер профилей использует эту ConfigMap при создании неймспейсов. Без указанной строки новые неймспейсы Profile создаются без автоматической инъекции sidecar-контейнера Istio.

Поле spec.dependency в GUI задайте на вкладке Манифест или импортируйте SSC YAML целиком.

Проверьте:

  1. Сервисы и репозитории → Установленные сервисы. У shturval-policy-manager и kubeflow-step-0 … kubeflow-step-4 режим Авто, состояние Healthy.
  2. В менеджере политик есть ClusterPolicy enforce-istio-injection-kubeflow, и она не находится в состоянии ошибки.
  3. Откройте неймспейс default и проверьте лейбл istio-injection=enabled. Если лейбла нет, см. устранение неполадок.
  4. В ConfigMap namespace-labels-data-<случайный-суффикс> в неймспейсе default ключ namespace-labels.yaml содержит строку istio-injection: "enabled".
  5. В браузере откройте https://kubeflow.<commonName>/. Должен открыться вход платформы (SSO), затем интерфейс Kubeflow. Если страница не открывается, проверьте DNS kubeflow.<commonName> на Ingress кластера и значение <commonName> у SSC shturval-ingress-controller.

Включите менеджер политик:

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" apply -f - <<'EOF'
apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServicePatch
metadata:
  name: kyverno-enable
spec:
  shturvalServiceConfigName: shturval-policy-manager
  patchOrder: 1
  mode: auto
EOF

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" wait \
  --for=jsonpath='{.status.ready}'=true ssc/shturval-policy-manager \
  --timeout=600s

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get ssc shturval-policy-manager
kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get pods -n kyverno

После перехода shturval-policy-manager в состояние Healthy создайте ClusterPolicy:

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" apply -f - <<'EOF'
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-istio-injection-kubeflow
  annotations:
    policies.kyverno.io/title: Enforce istio-injection=enabled on default namespace
    policies.kyverno.io/category: Istio
spec:
  rules:
    - name: add-istio-injection-label
      match:
        any:
          - resources:
              kinds:
                - Namespace
              names:
                - default
              operations:
                - CREATE
                - UPDATE
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              istio-injection: enabled
EOF

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get clusterpolicy enforce-istio-injection-kubeflow

Создайте все пять SSC сразу с mode: auto.

kubeflow-step-0 — базовые CRD и компоненты, без OIDC.

kubeflow-step-1 — Dex и oauth2-proxy. OIDC-параметры с шага 1 и cookie_secret из раздела «Подготовьте параметры».

kubeflow-step-2 — Pipelines, хранилища и ingress. Поле serviceName оставьте пустым. Объектное хранилище должно поддерживать AWS IAM. Если S3 работает по HTTP, оставьте s3.caCert пустым. Если по HTTPS, вставьте PEM корневого сертификата.

kubeflow-step-3 — Katib.

kubeflow-step-4 — завершающие компоненты. Customvalues не нужны.

apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServiceConfig
metadata:
  name: kubeflow-step-0
spec:
  chart: kubeflow-step-0
  mode: auto
  namespace: default
  reponame: shturval
  version: 0.1.0
---
apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServiceConfig
metadata:
  name: kubeflow-step-1
spec:
  chart: kubeflow-step-1
  customvalues:
    dex:
      oidc:
        client_id: "<OIDC_CLIENT_ID>"
        client_secret: "<OIDC_CLIENT_SECRET>"
    oauth2-proxy:
      oauth2Cfg:
        oidc_issuer_url: "<OIDC_ISSUER_URL>"
        redirect_url: https://kubeflow.<commonName>/oauth2/callback
      oidc:
        client_id: "<OIDC_CLIENT_ID>"
        client_secret: "<OIDC_CLIENT_SECRET>"
        cookie_secret: "<cookie_secret>"
  dependency:
  - kubeflow-step-0
  mode: auto
  namespace: default
  reponame: shturval
  version: 0.1.0
---
apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServiceConfig
metadata:
  name: kubeflow-step-2
spec:
  chart: kubeflow-step-2
  customvalues:
    platform-agnostic-mutli-user:
      seaweedfs:
        enabled: false
      mysql:
        enabled: false
        external:
          host: "<KFP_MYSQL_HOST>"
          port: <KFP_MYSQL_PORT>
          pipelineDatabase: "<KFP_MYSQL_PIPELINE_DB>"
          metadataDatabase: "<KFP_MYSQL_METADATA_DB>"
          username: "<KFP_MYSQL_USER>"
          password: "<KFP_MYSQL_PASSWORD>"
          serviceName: ""
      pipelinesProfileController:
        env:
          awsEndpointUrl: "<KFP_AWS_IAM_ENDPOINT>"
          s3EndpointUrl: "<KFP_S3_ENDPOINT>"
          awsRegion: "<KFP_AWS_REGION>"
          s3Bucket: "<KFP_S3_BUCKET>"
        awsCredentials:
          accessKeyValue: "<KFP_AWS_ACCESS_KEY>"
          secretKeyValue: "<KFP_AWS_SECRET_KEY>"
      s3:
        caCert: "<PEM-сертификат-CA-если-S3-по-HTTPS>"
      ingress:
        enabled: true
        annotations:
          cert-manager.io/cluster-issuer: "<CERT_CLUSTER_ISSUER>"
          cert-manager.io/revision-history-limit: "5"
        ingressClassName: nginx
        rules:
          - host: kubeflow.<commonName>
            http:
              paths:
                - backend:
                    service:
                      name: istio-ingressgateway
                      port:
                        number: 8080
                  path: /
                  pathType: Prefix
        tls:
          - hosts:
              - kubeflow.<commonName>
            secretName: kubeflow-ingress-tls
  dependency:
  - kubeflow-step-1
  mode: auto
  namespace: default
  reponame: shturval
  version: 0.1.0
---
apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServiceConfig
metadata:
  name: kubeflow-step-3
spec:
  chart: kubeflow-step-3
  customvalues:
    katib:
      mysql:
        enabled: false
        external:
          host: "<KATIB_MYSQL_HOST>"
          port: <KATIB_MYSQL_PORT>
          database: "<KATIB_MYSQL_DB>"
          username: "<KATIB_MYSQL_USER>"
          password: "<KATIB_MYSQL_PASSWORD>"
          secretName: "<KATIB_MYSQL_SECRET_NAME>"
          serviceName: ""
  dependency:
  - kubeflow-step-2
  mode: auto
  namespace: default
  reponame: shturval
  version: 0.1.0
---
apiVersion: ops.shturval.tech/v1beta2
kind: ShturvalServiceConfig
metadata:
  name: kubeflow-step-4
spec:
  chart: kubeflow-step-4
  dependency:
  - kubeflow-step-3
  mode: auto
  namespace: default
  reponame: shturval
  version: 0.1.0

Примените собранный манифест SSC (kubectl apply -f или kubectl apply -f -). Дождитесь состояния Healthy для каждого:

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get ssc kubeflow-step-0 kubeflow-step-1 kubeflow-step-2 kubeflow-step-3 kubeflow-step-4
kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get pods -n default

Когда все пять SSC перейдут в состояние Healthy:

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get ns default -o jsonpath='{.metadata.labels.istio-injection}{"\n"}'
kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get pods -A | grep -v "Running\|Completed"

Ожидаемый лейбл неймспейса default: enabled.

Найдите ConfigMap с настройками лейблов для неймспейсов Profile:

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get configmap -n default -o name \
  | grep '^configmap/namespace-labels-data-'

Откройте найденную ConfigMap для редактирования:

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" edit \
  -n default configmap/namespace-labels-data-<случайный-суффикс>

В значении data.namespace-labels.yaml должна быть строка:

istio-injection: "enabled"

Если строки нет, добавьте её и сохраните ConfigMap. Не добавляйте строку повторно. Затем проверьте результат:

kubectl --kubeconfig "${KUBECONFIG_CLIENT}" get \
  -n default configmap namespace-labels-data-<случайный-суффикс> \
  -o jsonpath='{.data.namespace-labels\.yaml}' \
  | grep '^istio-injection:'

Дальше: