Одной из основных функций платформы MLOps является возможность отслеживания и записи экспериментов, которыми затем можно делиться и сравнивать. Это также включает в себя хранение и управление моделями машинного обучения и другими артефактами.

MLFlow — популярный проект с открытым исходным кодом, реализующий вышеперечисленные функции. Однако в стандартной установке MLFlow отсутствует какой-либо механизм проверки подлинности. Предоставление кому угодно доступа к вашей информационной панели MLFlow очень часто является бесполезным. В GetInData мы поддерживаем усилия наших клиентов по машинному обучению, настраивая MLFlow в их среде так, как им требуется, с минимальным обслуживанием. В этом блоге я опишу, как вы можете развернуть MLFlow с защитой oauth2 в своей инфраструктуре AWS (Развертывание бессерверного MLFlow на Google Cloud Platform с помощью Cloud Run охватывает развертывание в GCP).

Обзор решения

Вы можете настроить MLFlow разными способами, включая простую установку на локальном хосте. Но чтобы обеспечить совместное управление экспериментами и моделями, большая часть производственных развертываний, скорее всего, будет иметь распределенную архитектуру с удаленным сервером MLFlow и удаленными внутренними серверами и хранилищами артефактов.

На следующей диаграмме показана высокоуровневая архитектура такого распределенного подхода.

Основными компонентами инфраструктуры MLFlow являются:

  • MLFlow Tracking Server, который предоставляет API для регистрации параметров, метрик, экспериментов, метаданных и пользовательского интерфейса для визуализации результатов.
  • Amazon Aurora Serverless используется в качестве внутреннего хранилища, где MLFlow хранит метаданные об экспериментах и ​​запусках, т. е. метрики, теги и параметры.
  • AWS S3 используется в качестве хранилища артефактов, где MLFlow хранит артефакты, например. модели, файлы данных.
  • Oauth2-proxy защищает конечные точки MLFlow с помощью поставщиков, совместимых с OAuth2, например. Google.

Другие компоненты AWS обеспечивают среду выполнения/вычислений (Elastic Container Service, ECS), маршрутизацию (Application Load Balancer, ALB и Route 53 в качестве службы DNS) и безопасность (Secrets Manager и Virtual Private Cloud, VPC).

Настройка клиента OAuth 2.0

Чтобы защитить наш сервер MLFlow, нам необходимо интегрироваться с поставщиком OAuth2. oauth2-proxy поддерживает основных поставщиков OAuth2, и вы можете настроить любой из них. При выборе поставщика проверки подлинности имейте в виду, что не все поддерживаемые поставщики позволяют получить токен авторизации, который требуется для программного доступа, например для конвейеров CI/CD или регистрации показателей запланированных запусков эксперимента). В этом примере мы использовали провайдера Google. Следуйте инструкциям Настройка OAuth 2.0, чтобы создать клиент OAuth 2.0. В процессе:

  • Запишите сгенерированный Client Id и секрет клиента, которые вам понадобятся позже.
  • Укажите https://<your_dns_name_here>/oauth2/callback в поле Authorized redirect URIs.

Служба эластичных контейнеров

Мы развертываем сервисы MLFlow и oauth2-proxy в виде контейнеров, используя Elastic Container Service, ECS. AWS App Runner мог бы стать хорошей бессерверной альтернативой, но на момент написания этого сообщения в блоге он был доступен только в нескольких местах. У нас есть два контейнера, определенные в задаче ECS. Учитывая, что несколько контейнеров в задаче ECS в сетевом режиме awsvpc совместно используют сетевое пространство имен, они могут взаимодействовать друг с другом с помощью локального хоста (аналогично контейнерам в одном модуле Kubernetes).

Соответствующее определение контейнера Terraform для службы MLFlow показано ниже.

{
  name      = "mlflow"
  image     = "gcr.io/getindata-images-public/mlflow:1.22.0"
  entryPoint = ["sh", "-c"]
  command = [
    <<EOT
      /bin/sh -c "mlflow server \
        --host=0.0.0.0 \
        --port=${local.mlflow_port} \
        --default-artifact-root=s3://${aws_s3_bucket.artifacts.bucket}${var.artifact_bucket_path} \
        --backend-store-uri=mysql+pymysql://${aws_rds_cluster.backend_store.master_username}:`echo -n $DB_PASSWORD`@${aws_rds_cluster.backend_store.endpoint}:${aws_rds_cluster.backend_store.port}/${aws_rds_cluster.backend_store.database_name} \
        --gunicorn-opts '${var.gunicorn_opts}'"
    EOT
  ]
  portMappings = [{ containerPort = local.mlflow_port }]
  secrets = [
    {
      name      = "DB_PASSWORD"
      valueFrom = data.aws_secretsmanager_secret.db_password.arn
    }
  ]
}

Настройка контейнера проста — мы просто запускаем сервер MLFlow с некоторыми параметрами. Конфиденциальные данные, т. е. пароль базы данных, извлекаются из диспетчера секретов (более дешевым, но менее надежным вариантом было бы использование хранилища параметров диспетчера систем). Однако передача URI внутреннего хранилища на данный момент немного запутана. AWS ECS не позволяет интерполировать секреты в аргументах CLI во время выполнения, поэтому нам нужна оболочка. Желательно, чтобы сервер MLFlow предоставлял возможность указать это значение через переменную окружения (есть открытый вопрос для this).

Задаче ECS также отводится роль доступа к S3, где MLFlow хранит артефакты.

resource "aws_iam_role_policy" "s3" {
  name = "${var.unique_name}-s3"
  role = aws_iam_role.ecs_task.id
policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = ["s3:ListBucket"]
        Resource = ["arn:aws:s3:::${aws_s3_bucket.artifacts.bucket}"]
      },
      {
        Effect   = "Allow"
        Action   = ["s3:*Object"]
        Resource = ["arn:aws:s3:::${aws_s3_bucket.artifacts.bucket}/*"]
      },
    ]
  })
}

Точно так же определение контейнера oauth2-proxy выглядит следующим образом;

{
  name      = "oauth2-proxy"
  image     = "bitnami/oauth2-proxy:7.2.1"
  command   = [
    "--http-address", "0.0.0.0:8080",
    "--upstream", "http://localhost:${local.mlflow_port}",
    "--email-domain", "*",
    "--provider", "google",
    "--skip-jwt-bearer-tokens", "true",
    "--extra-jwt-issuers", "https://accounts.google.com=32555940559.apps.googleusercontent.com"
  ]
  portMappings = [{ containerPort = local.oauth2_proxy_port }]
  secrets = [
    {
      name      = "OAUTH2_PROXY_CLIENT_ID"
      valueFrom = data.aws_secretsmanager_secret.oauth2_client_id.arn
    },
    {
      name      = "OAUTH2_PROXY_CLIENT_SECRET"
      valueFrom = data.aws_secretsmanager_secret.oauth2_client_secret.arn
    },
    {
      name      = "OAUTH2_PROXY_COOKIE_SECRET"
      valueFrom = data.aws_secretsmanager_secret.oauth2_cookie_secret.arn
    },
  ]
}

Это минимальная конфигурация. В производственной среде вам, вероятно, потребуется ограничить аутентификацию определенными доменами (параметр --email-domain) и определить дополнительные параметры, например, --cookie-refresh.

Обратите внимание, что для поддержки программного доступа требуется параметр конфигурации --extra-jwt-issuers.

Предпосылка нашей установки состоит в том, чтобы поместить oauth2-proxy перед сервером MLFlow, тем самым добавив возможности авторизации. По этой причине мы настроили балансировщик нагрузки службы ECS так, чтобы он указывал на контейнер oauth2-proxy, который, как следует из названия, действует как прокси-сервер для сервера MLFlow.

resource "aws_ecs_service" "mlflow" {
# other attributes
load_balancer {
    target_group_arn = aws_lb_target_group.mlflow.arn
    container_name   = "oauth2-proxy"
    container_port   = local.oauth2_proxy_port
  }
}

Развертывание

Полный стек Terraform доступен здесь для простого и автоматического развертывания всех необходимых ресурсов AWS.

Стек Terraform создаст следующие ресурсы

  • VPC с соответствующей настройкой сети, например. подсети, в которых работает большая часть ресурсов AWS
  • Сегмент S3 для хранения артефактов MLFlow.
  • Необходимые роли и политики IAM для доступа к корзине S3, секретам в Secrets Manager и запуску задач ECS.
  • База данных Aurora Serverless для хранения метаданных MLFlow.
  • Кластер ECS со службой, на которой работает сервер отслеживания MLFlow и контейнеры oauth2-proxy.
  • Балансировщик нагрузки приложений, ALB, для маршрутизации трафика в службу ECS и для терминации SSL.
  • Запись A в Route 53 для направления трафика на ALB.

Однако перед запуском команд Terraform необходимо выполнить несколько шагов вручную.

Предпосылки

У вас должны быть установлены следующие инструменты

  • Интерфейс командной строки AWS
  • Интерфейс командной строки Terraform (v1.0.0+)

Ручные шаги

  • Создайте корзину S3 для хранения состояния Terraform. Тем не менее, этот шаг не является строго обязательным, если вы решите сохранить состояние локально.
export TF_STATE_BUCKET=<bucketname>
aws s3 mb s3://$TF_STATE_BUCKET
aws s3api put-bucket-versioning --bucket $TF_STATE_BUCKET --versioning-configuration Status=Enabled
aws s3api put-public-access-block \
    --bucket $TF_STATE_BUCKET \
    --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

Включение управления версиями и блокировка общего доступа не являются обязательными (но рекомендуемыми).

  • Создайте таблицу DynamoDB для блокировки состояния. Этот шаг не является строго обязательным, если вы не включаете блокировку состояния и проверку согласованности.
export TF_STATE_LOCK_TABLE=<tablename>
aws dynamodb create-table \
   --table-name $TF_STATE_LOCK_TABLE \
   --attribute-definitions AttributeName=LockID,AttributeType=S \
   --key-schema AttributeName=LockID,KeyType=HASH \
   --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
  • Создавайте секреты в Менеджере секретов. Сюда входят идентификаторы OAuth2, ключи доступа к корзине S3 и пароль базы данных.
aws secretsmanager create-secret \
   --name mlflow/oauth2-cookie-secret \
   --description "OAuth2 cookie secret" \
   --secret-string "<cookie_secret_here>"
aws secretsmanager create-secret \
   --name mlflow/store-db-password \
   --description "Password to RDS database for MLFlow" \
   --secret-string "<db_password_here>"
# This is a Client Id obtained when setting up OAuth 2.0 client 
aws secretsmanager create-secret \
   --name mlflow/oauth2-client-id \
   --description "OAuth2 client id" \
   --secret-string "<oauth2_client_id_here>"
# This is a Client Secret obtained when setting up OAuth 2.0 client 
aws secretsmanager create-secret \
   --name mlflow/oauth2-client-secret \
   --description "OAuth2 client secret" \
   --secret-string "<oauth2_client_secret_here>"

Предоставленный стек Terraform предполагает, что у вас есть существующая зона хостинга Route 53 и общедоступный сертификат SSL/TLS от Amazon.

Развернуть Млфлов

Выполните следующую команду, чтобы создать все необходимые ресурсы инфраструктуры.

terraform init \
  -backend-config="bucket=$TF_STATE_BUCKET" \
  -backend-config="dynamodb_table=$TF_STATE_LOCK_TABLE" 
export TF_VAR_hosted_zone=<hosted_zone_name>
export TF_VAR_dns_record_name=<mlflow_dns_record_name>
export TF_VAR_domain=<domain>
terraform plan
terraform apply

Настройка инфраструктуры AWS может занять несколько минут. После завершения вы можете перейти к пользовательскому интерфейсу MLFlow (URL-адрес будет напечатан в выходной переменной mlflow_uri). Авторизуйтесь, используя свой аккаунт Google.

Программный доступ

Многие варианты использования MLFlow включают программный доступ к API сервера отслеживания MLFlow, например. регистрируя параметры или метрики в ваших пайплайнах кедро. В таких сценариях вам необходимо передать токен Bearer в заголовке HTTP Authorization. Получение такого токена зависит от провайдера. Например, для Google вы можете получить токен, выполнив следующую команду:

gcloud auth print-identity-token

Авторизованная команда curl со списком ваших экспериментов будет выглядеть так:

Передача маркера авторизации другим инструментам зависит от пакета SDK. Например, MMLFLow Python SDK поддерживает аутентификацию Bearer через переменную среды MLFLOW_TRACKING_TOKEN.

Краткое содержание

В этом руководстве мы рассмотрели, как безопасно разместить сервер MLflow с открытым исходным кодом на AWS с помощью ECS, Amazon S3 и Amazon Aurora Serverless. Как видите, это несложное решение, обеспечивающее хорошие меры безопасности (относящиеся как к доступу пользователей, так и к безопасности данных), минимальное обслуживание и приемлемую стоимость развертывания. Пожалуйста, посетите Развертывание бессерверного MLFlow на Google Cloud Platform с помощью Cloud Run, если вы предпочитаете инфраструктуру Google.

Вам понравился наш пост? Если вы хотите узнать больше, скачайте нашу бесплатную электронную книгу «MLOps: Power Up Machine Learning Process. Введение в Vertex AI, Snowflake и dbt Cloud».

Первоначально опубликовано на https://getindata.com.

Автор блога: Marek Jędraszewski — Data Engineer