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

Здесь в игру вступает MLflow. MLflow - это платформа с открытым исходным кодом для управления жизненным циклом машинного обучения.

Databricks планирует выпустить размещенную и поддерживаемую версию своего собственного существа. Однако, если у вас есть небольшая команда ученых, вы все равно можете извлечь выгоду из MLflow, избегая при этом многих головных болей DevOps.

Вот как я развернул MLflow в AWS Elastic Beanstalk для воспроизводимого и совместного анализа данных в моей команде:

1. Создайте простой образ Docker для MLflow.

MLflow красиво упакован, поэтому мне нужна была только база Python 3.6 и небольшая конфигурация. Вот Dockerfile, но вы также можете просто вытащить изображение или просмотреть репо, где я объясню, как его запустить.

FROM python:3.6
LABEL maintainer="Jose Rivera <[email protected]>"
ENV MLFLOW_VERSION 0.8.2
ENV TERM linux
ENV BUCKET bucket
RUN pip install mlflow==$MLFLOW_VERSION
RUN mkdir -p /mlflow/
EXPOSE 5000
CMD mlflow server \
    --file-store /mlflow \
    --default-artifact-root s3://${BUCKET}/mlflow-artifacts \
    --host 0.0.0.02. Deploy this image using AWS Elastic Beanstalk

AWS Elastic Beanstalk (EB) - это собственный PaaS AWS, поэтому я уже некоторое время использую его для проектов, где мне нужно развернуть веб-приложение или рабочее приложение и забыть о масштабировании. Я также видел, как он растет, поэтому теперь он предлагает довольно много хороших функций, таких как балансировка нагрузки, потоковая передача журналов и простая интеграция с базами данных и VPC. Из всего этого я выбрал Elastic Beanstalk, потому что он предлагал действительно простую платформу для развертывания и масштабирования приложений Docker, а также потому, что я мог завершить HTTPS-соединение с помощью SSL-сертификатов, предоставляемых AWS Certificate Manager (они бесплатны). Более того, добавить базовую аутентификацию HTTP для обеспечения некоторой элементарной безопасности было несложно. Само собой разумеется, что этот сервис не лишен причуд AWS! Вот подробности:

Архитектура

В одном предложении архитектуру решения можно резюмировать как докеризованное веб-приложение, расположенное за обратным прокси-сервером Nginx, обслуживаемое балансировщиком нагрузки.

Развертывание, шаг №1: создание единого файла конфигурации контейнера

AWS Elastic Beanstalk требует, чтобы конфигурация вашего приложения была записана в Dockerrun.aws.json. Это тот, который я создал для создания простого обратного прокси-сервера Nginx, который мог бы обслуживать веб-приложение MLflow:

{
  "AWSEBDockerrunVersion": "1",
  "Image": {
    "Name": "launchpadrecruits/mlflow",
    "Update": "true"
  },
  "Ports": [
    {
      "ContainerPort": "5000"
    }
  ],
  "Volumes": [
    {
      "HostDirectory": "/var/mlflow",
      "ContainerDirectory": "/mlflow"
    }
  ],
  "Logging": "/var/log/nginx"
}

Шаг 2: предоставление базовой аутентификации HTTP с помощью обратного прокси-сервера Nginx

Если вам нужно что-то сделать при запуске приложения в AWS Beanstalk, вам необходимо предоставить свою конфигурацию как часть серии файлов конфигурации YAML в папке .ebextensions/

Следуя замечательному сообщению Сары Кэссиди и ответу @ nerdinand в SO, я создал следующий файл конфигурации:

# .ebextensions/01-http_basic_auth.config
files:
  /etc/nginx/.htpasswd:
    mode: "000755"
    owner: root
    group: root
    content: |
      username:$apr1$k5WkOMBL$0FZNIWOLQMsHJAOREjemC/
/etc/nginx/conf.d/mlflow.conf:
    mode: "000755"
    owner: root
    group: root
    content: |
      server {
        listen       80;
        server_name  localhost;
        location / {
          proxy_pass        http://docker;
          proxy_set_header  Host $host;
          proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        }
      }
/tmp/deployment/nginx_auth.sh:
    mode: "000755"
    content: |
       sed -i 's/$proxy_add_x_forwarded_for;/$proxy_add_x_forwarded_for;\n   auth_basic "Restricted";\n    auth_basic_user_file \/etc\/nginx\/.htpasswd;\n/' /etc/nginx/conf.d/mlflow.conf
container_commands:
  01nginx_auth:
    command: "/tmp/deployment/nginx_auth.sh"
  02restart_nginx:
    command: "service nginx restart"

Вкратце, это 1) помещает файл htpasswd в нужное место, 2) настраивает хост в nginx, который служит обратным прокси для веб-приложения Docker с HTTP Basic Auth 3) создает сценарий sh для добавления базовая аутентификация для Nginx, 4) Указывает AWS EB запустить сценарий включения аутентификации и перезапустить веб-сервер.

Чтобы добавить HTTP-аутентификацию в свой MLflow, вам просто нужно отредактировать содержимое файла .htpasswd, указав свое имя пользователя и пароль. Для его создания вы можете использовать инструмент Apache htpasswd:

$ htpasswd -nb username password
username:$apr1$k5WkOMBL$0FZNIWOLQMsHJAOREjemC/

или любой из доступных онлайн-инструментов, подобных this.

ОБНОВЛЕНИЕ, февраль 2019 г.: конфигурация AWS Elastic Beanstalk по умолчанию для веб-сервера с одним контейнером помещает запись на /etc/nginx/sites-enabled, которая реализует конфигурацию обратного прокси-сервера для Nginx, а в новых версиях Elastic Beanstalk использует docker имя восходящего потока. Поэтому ваше развертывание не будет работать, потому что шаг 02restart_nginx завершится ошибкой, если обнаружится, что восходящий docker дублируется. Вот обновленная конфигурация, которую я использую:

Сначала я реализую базовую аутентификацию HTTP на сервере mlflow, но на последнем этапе я удаляю конфигурацию по умолчанию вместо перезапуска сервера nginx:

# .ebextensions/01-http_basic_auth_mlflow.config
files:
  /etc/nginx/.htpasswd:
    mode: "000755"
    owner: root
    group: root
    content: |
      username:$apr1$k5WkOMBL$0FZNIWOLQMsHJAOREjemC/
/etc/nginx/conf.d/mlflow.conf:
    mode: "000755"
    owner: root
    group: root
    content: |
      server {
        listen       80;
        server_name  localhost;
        location / {
          proxy_pass        http://docker;
          proxy_http_version    1.1;
          proxy_set_header  Upgrade         $http_upgrade;
          proxy_set_header  Host $host;
          proxy_set_header  X-Real-IP       $remote_addr;
          proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        }
      }
/tmp/deployment/nginx_auth.sh:
    mode: "000755"
    content: |
       sed -i 's/$proxy_add_x_forwarded_for;/$proxy_add_x_forwarded_for;\n   auth_basic "Restricted";\n    auth_basic_user_file \/etc\/nginx\/.htpasswd;\n/' /etc/nginx/conf.d/mlflow.conf
container_commands:
  01nginx_auth:
    command: "/tmp/deployment/nginx_auth.sh"
  02remove_config:
    command: "rm -f /etc/nginx/sites-enabled/elasticbeanstalk-nginx-docker-proxy.conf"

Во-вторых, я создаю ловушку пост-развертывания, которая проверяет, удален ли сайт, включенный по умолчанию, и перезапускаю nginx:

# .ebextensions/91-mlflow_after_deployment.config
files:
  /opt/elasticbeanstalk/hooks/appdeploy/post/91_restart_nginx_after_deployment.sh:
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash -xe
      rm -f /etc/nginx/sites-enabled/elasticbeanstalk-nginx-docker-proxy.conf
      service nginx restart

Это гарантирует, что наш пользовательский mlflow сервер будет обслуживаться обратным проксиnginx.

Шаг № 3: создайте приложение на AWS EB:

Для этого вам необходимо перейти в консоль AWS EB и выполнить следующие действия:

  • Создать новое приложение
  • Создать среду
  • Среда веб-сервера
  • Введите имя, домен (вы можете позже связать его со своим DNS, если необходимо) и описание.
  • Выберите Docker в качестве предварительно настроенного приложения
  • Нажмите «настроить дополнительные параметры».
  • Если вам нужны HTTP, такие как я, выберите Пользовательская конфигурация и в балансировщике нагрузки:
  • Добавьте правило прослушивателя со следующей конфигурацией

  • Настало время выбрать сертификат, созданный ACM.
  • Заполните остальные варианты в соответствии с вашими потребностями.

Разверните шаг №4: загрузите в AWS EB и разверните!

Создайте архив выпуска:

zip -r mlflow-release.zip Dockerrun.aws.json .ebextensions

и в консоли Elastic Beanstalk нажмите «Загрузить и развернуть», загрузите свой mlflow-release.zip файл и назовите свою версию. Щелкните «Развернуть».

Разверните шаг № 5: Создайте корзину S3 для ваших артефактов и настройте доступ к ней.

Приложение может быть развернуто, но MLflow требуется корзина S3, в которой будут храниться артефакты моделирования. Для этого нам необходимо:

  1. Создайте корзину S3
  2. Создайте профиль экземпляра IAM, чтобы позволить экземпляру MLflow EC2 получить доступ к этому сегменту и писать в него.
  3. На консоли AWS EB щелкните MLflow ›Конфигурация.
  4. В программном обеспечении добавьте переменную среды BUCKET с именем недавно созданной корзины S3.
  5. В разделе «Безопасность» прикрепите недавно созданную роль IAM в качестве профиля экземпляра.

А теперь… пользуйся!

Вот как выглядит MLflow, развернутый в облаке с помощью AWS EB…

… После того, как я запустил этот пример MLflow. Чтобы запустить его, мне сначала пришлось экспортировать некоторые переменные среды для удаленного сервера отслеживания + HTTP Basic Auth:

export MLFLOW_TRACKING_URI=https://mlflow.lprpredict.com
export MLFLOW_TRACKING_USERNAME=username
export MLFLOW_TRACKING_PASSWORD=password

Создайте эксперимент:

mlflow experiments create my_first_experiment

он должен вернуть идентификатор:

Created experiment 'my_first_experiment' with id 1

Теперь мы можем запустить моделирование train.py, полученного из репо MLflow:

MLFLOW_EXPERIMENT_ID=1 python examples/train.py

И вы должны увидеть запись в консоли MLflow.

Наслаждайтесь надежной воспроизводимой и совместной наукой о данных!