MLOps меняет процесс разработки моделей машинного обучения

Промышленные решения, основанные на машинном обучении — это гораздо больше, чем просто модель. Три ключевые концепции, охватывающие управление версиями, тестирование и конвейеры, являются основой для операций машинного обучения (MLOps), которые помогают группам по анализу данных быстрее и увереннее выпускать модели.

Фото Келли Сиккема на Unsplash.

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

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

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

Контроль версий нужен не только для кода

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

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

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

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

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

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

Развиваются не только данные, которые мы используем для построения моделей, но и метаданные. Метаданные относятся к собранной информации о базовых данных и обучении модели — они рассказывают нам, как прошел процесс обучения вашей модели. Данные использовались как ожидалось? Какой точности достигла модель?

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

Наконец, для самой модели тоже должен быть надлежащий контроль версий. Как у каждого специалист по данным, ваша цель — постоянно повышать точность и надежность моделей машинного обучения, поэтому развивающийся алгоритм должен иметь собственное управление версиями. Это часто называют реестром моделей.

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

Встраивайте предохранители в код

Когда дело доходит до обеспечения безопасности в процессе машинного обучения, она должна быть в коде, а не в вашей голове!

Стремитесь любой ценой избегать ручных или непоследовательных процессов. Все процедуры для сбора данных, тестирования данных и развертывания модели должны быть записаны в коде, а не в документации процесса, чтобы вы могли быть уверены, что каждая итерация модели будет соответствовать требуемым стандартам.

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

Тестирование данных часто проводится ручным способом, но должно быть программным.

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

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

Продукт — это конвейер, а не модель

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

Конечная цель конвейера машинного обучения — создать самовосстанавливающуюся систему.

Модель машинного обучения важна для решения бизнес-задач и удовлетворения насущных потребностей организации. Однако необходимо признать, что модель носит временный характер, в отличие от системы, которая ее производит.

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

В результате конвейер, который производит точные и эффективные модели машинного обучения, должен быть продуктом, на создание которого специалисты по данным должны сосредоточить все свое внимание. Итак, что же такое конвейер машинного обучения?

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

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

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

Подводя итог, можно сказать, что есть три основных концепции MLOps, которые должен понимать каждый.

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

  2. Защитные меры должны работать автоматически — не рискуйте результатами своих моделей машинного обучения, полагаясь на ручные или непоследовательные процессы.

  3. Наконец, продукт — это конвейер, а не модель машинного обучения. Развитый конвейер — единственный способ поддерживать машинное обучение продуктового уровня в долгосрочной перспективе.

Об авторе: Хенрик Скогстрём возглавляет внедрение платформы Valohai MLOpsсреде и подробно пишет о передовых методах машинного обучения в производственной. До Валохая Хенрик работал менеджером по продукту в Quest Analytics, чтобы улучшить доступность здравоохранения в США. Запущенный в 2017 году, Valohai является пионером в области MLOps и помогает таким компаниям, как Twitter, LEGO Group и JFrog, быстрее запускать свои модели в производство.


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

Установка Shadowsocks с обходом блокировок на Keenetic

Предыстория

Не претендую на открытие Америки в этой публикации, т.к. она является компиляцией различных комментариев и статей, в т.ч. на Habr. Не судите строго, надеюсь на помощь в развитии этого направления. Делал эту инструкцию для себя и специально с нуля, чтобы каждый новичок смог повторить те же действия.

Необходимо

  • Любой Keenetic с поддержкой USB. Можно установить и на внутреннюю память, но не рекомендуется

  • Актуальная версия KeeneticOs (на данный момент 3.7.4)

  • Flash-накопитель любого размера (хватит даже 256Мб, но в 2022 году таких уже не найдёшь)

Раздел 1. Установка Entware

  1. Форматирование флешки в ext4. Я использовал MiniTool Partition Wizard Free, можно использовать любую другую программу

  1. Воспользуемся инструкцией на официальном сайте Keenetic

  • Скачиваем mipsel

  • Вставляем отформатированную флешку в роутер

  • Заходим в раздел Управление – Приложения и выбираем нашу флешку

    В настройках роутера предварительно должно быть включено приложение «Сервер SMB» для доступа к подключаемым USB-дискам по сети.

  • Создаём папку install

  • Ставим курсор на новую папку и импортируем туда файл mipsel с компьютера

  • В настройках роутера заходим в раздел Управление – OPKG, выбираем нашу флешку и удаляем сценарий, если он есть и нажимаем кнопку Сохранить

  • Примерно спустя минуту заходим обратно в Управление – Приложения и выбираем нашу флешку. Видим, что у нас установился entware по наличию некоторого количества папок.

  • Скачиваем Putty (на данный момент актуально putty-64bit-0.76-installer.msi) и запускаем её. Простенькие настроечки (если что их можно сохранить кнопкой Save)

При возможных предупреждениях соглашаемся (кнопка Accept)

  • Вводим логин «root» (без кавычек), нажимаем Enter, пароль «keenetic» (также без кавычек) (при вводе пароля курсор не двигается – это нормально), также Enter. Должно отобразиться:

вводим команду

passwd

и дважды вводим пароль. Курсор при вводе пароля также не двигается

  • Обновим opkg

P.S. здесь и далее — для копирование команды в командную строку необходимо скопировать текст на этом сайте и вставить в командную строку с помощью правой кнопкой мыши

opkg update

Раздел 2. Установка Shadowsocks и необходимых пакетов

За основу данного раздела взята вот эта инструкция

  1. Устанавливаем необходимые компоненты с помощью настроек роутера: Общие настройки > Изменить набор компонентов

  • Протокол IPv6

  • Затем, после обновления и перезагрузки роутера, «Модули ядра подсистемы Netfilter» и, на всякий случай «Пакет расширения Xtables-addons для Netfilter» ещё раз перезагружаем роутер

  1. Начинаем настраивать наш Entware

  • Для этого подключаемся к Putty (см предыдущий раздел)

  • Вводим логин и пароль (если логин и пароль не меняли то root-keenetic)

  • Вводим команду

opkg install mc bind-dig cron dnsmasq-full ipset iptables shadowsocks-libev-ss-redir shadowsocks-libev-config
  1. Инициализация ipset, создание множества IP-адресов unblock (100-ipset.sh)

  • Проверьте, что в системе вашего маршрутизатора есть поддержка множества hash:net (как оказалась, не во всех маршрутизаторах Keenetic она есть):

ipset create test hash:net
  • Если команда никаких ошибок и сообщений не выдала, значит поддержка есть, и просто следуйте инструкции дальше. В противном случае (есть ошибка) в следующем скрипте вам нужно заменить hash:net на hash:ip. При этом вы потеряете возможность разблокировки по диапазону и CIDR.
    Скорее всего ошибок не будет у Вас

  • Создайте пустое множество адресов с именем unblock при загрузке маршрутизатора. Для этого создайте файл /opt/etc/ndm/fs.d/100-ipset.sh:

mcedit /opt/etc/ndm/fs.d/100-ipset.sh

Вставляем содержимое с помощью сочетания клавиш Shift+Insert. Далее в этой инструкции мы также будем использовать это сочетания клавиш

#!/bin/sh [ "$1" != "start" ] && exit 0 ipset create unblock hash:net -exist exit 0 

После этого нажимаем сохранить (клавиша F2), соглашаемся (Enter) и выход (клавиша F10). Эти сочетания также будут использоваться далее

  • Дайте права на исполнение:

chmod +x /opt/etc/ndm/fs.d/100-ipset.sh
  1. Настройка Shadowsocks на примере Highload-VPN. Не является рекламой. Пока там всё бесплатно, они обещают бесплатный доступ с небольшими ограничениями, а вскоре появится информация о платном доступе, но, говорят, не слишком дорогой. Вы можете использовать любой другой сервис, либо настроить самостоятельно Shadowsocks на своём сервере, например по этой инструкции. Только теперь я не знаю как оплатить свой сервер за рубежом)))). За основу этого пункта взята эта инструкция.

  • После регистрации авторизуемся на сайте и заходим в панель управления

  • У меня автоматически создался ключ. Нажимаем на кнопку «Показать»

  • Синюю и зелёную часть мы также будем использовать, но позже. Пока нас интересует часть, выделенная красным цветом (от начала до «собачки»). Копируем её в буфер обмена. Она закодирована в кодировке base64, поэтому нам нужно её раскодировать. Можем использовать этот сайт

  • В верхнее поле вставляем нашу ссылку и нажимаем кнопку Decode. Появится декодированная строка. Нас будет интересовать пароль, который находится после двоеточия

  • Возвращаемся в Putty и выполняем команду

mcedit /opt/etc/shadowsocks.json
  • Редактируем наш файл. Изменяем строку server (в моём случае 5.5.5.5) на ip адрес (или доменное имя) из ключа, который мы получили на сайте (см вторую картинку наверх). Это «синяя» часть нашего ключа. «Зелёную» часть нашего ключа копируем в server_port (в моём случае 666). В поле password мы копируем пароль из декодированной строки (предыдущая картинка, текст выделенный красным, но после двоеточия). local_port изменяем на любой свободный порт. Можно оставить этот

{     "server":["5.5.5.5"],     "mode":"tcp_and_udp",     "server_port":666,     "password":"8888888",     "timeout":86400,     "method":"chacha20-ietf-poly1305",     "local_address": "::",     "local_port": 1082,     "timeout": 300,     "fast_open": false,     "ipv6_first": true }

Сохраняем и выходим (напомню F2,F10)

  • Редактируем исполняемый файл Shadowsocks

mcedit /opt/etc/init.d/S22shadowsocks
  • Меняем ss-local на ss-redir

Сохраняем и выходим

  1. Список доменов (и не только) для обхода блокировки (unblock.txt)

  • Создадим файл /opt/etc/unblock.txt

mcedit /opt/etc/unblock.txt

Каждая строка может содержать доменное имя, IP-адрес, диапазон или CIDR. Можно использовать символ # для комментирования строк.

###Торрент-трекеры rutracker.org kinozal.tv ###Каталоги медиаконтента для программ filmix.cc ###Книги lib.rus.ec ###Разное 2ip.ru  #facebooktwitterinstagram facebook.com twitter.com instagram.com  ###Пример разблокировки по IP (убрать # в начале строки) #195.82.146.214 ###Пример разблокировки по CIDR (убрать # в начале строки) #103.21.244.0/22 ###Пример разблокировки по диапазону (убрать # в начале строки) #100.100.100.200-100.100.100.210 

С помощью данного файла на twitter, facebook и instagram у меня через роутер теперь спокойно заходит. Сайт 2ip будет использоваться для проверки ip

Сохраняем и выходим

  1. Скрипт для заполнения множества unblock IP-адресами заданного списка доменов (unblock_ipset.sh) и дополнительного конфигурационного файла dnsmasq из заданного списка доменов (unblock_dnsmasq.sh)

  • Создадим скрипт /opt/bin/unblock_ipset.sh:

mcedit /opt/bin/unblock_ipset.sh
  • Вставляем содержимое, затем сохраняем и закрываем

#!/bin/sh until ADDRS=$(dig +short google.com @localhost) && [ -n "$ADDRS" ] > /dev/null 2>&1; do sleep 5; done while read line || [ -n "$line" ]; do   [ -z "$line" ] && continue   [ "${line:0:1}" = "#" ] && continue   cidr=$(echo $line | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}')   if [ ! -z "$cidr" ]; then     ipset -exist add unblock $cidr     continue   fi   range=$(echo $line | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}-[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')   if [ ! -z "$range" ]; then     ipset -exist add unblock $range     continue   fi   addr=$(echo $line | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')   if [ ! -z "$addr" ]; then     ipset -exist add unblock $addr     continue   fi   dig +short $line @localhost | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | awk '{system("ipset -exist add unblock "$1)}' done < /opt/etc/unblock.txt 
  • Даём права на использование

chmod +x /opt/bin/unblock_ipset.sh
  • Создадим скрипт /opt/bin/unblock_dnsmasq.sh:

mcedit /opt/bin/unblock_dnsmasq.sh
  • Вставляем содержимое. Затем сохраняем и выходим

#!/bin/sh cat /dev/null > /opt/etc/unblock.dnsmasq while read line || [ -n "$line" ]; do   [ -z "$line" ] && continue   [ "${line:0:1}" = "#" ] && continue   echo $line | grep -Eq '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' && continue   echo "ipset=/$line/unblock" >> /opt/etc/unblock.dnsmasq done < /opt/etc/unblock.txt
  • Даём права на использование

chmod +x /opt/bin/unblock_dnsmasq.sh
  • Запускаем скрипт и затем проверяем создался ли файл. Здесь 2 команды, вводим последовательно

unblock_dnsmasq.sh cat /opt/etc/unblock.dnsmasq

Картина будет примерно такая

  1. Скрипт ручного принудительного обновления системы после редактирования списка доменов (unblock_update.sh)

  • Создаём его

mcedit /opt/bin/unblock_update.sh
  • Записываем содержимое, сохраняем и закрываем

#!/bin/sh ipset flush unblock /opt/bin/unblock_dnsmasq.sh /opt/etc/init.d/S56dnsmasq restart /opt/bin/unblock_ipset.sh &
  • Даём права на использование

chmod +x /opt/bin/unblock_update.sh
  1. Скрипт автоматического заполнения множества unblock при загрузке маршрутизатора (S99unblock)

  • Создаём скрипт

mcedit /opt/etc/init.d/S99unblock
  • Записываем содержимое, сохраняем и закрываем

#!/bin/sh [ "$1" != "start" ] && exit 0 /opt/bin/unblock_ipset.sh &
  • Даём права на использование

chmod +x /opt/etc/init.d/S99unblock
  1. Перенаправление пакетов с адресатами из unblock в Shadowsocks

  • Создаём скрипт

mcedit /opt/etc/ndm/netfilter.d/100-redirect.sh
  • Записываем содержимое. Если необходимо – меняем ip адрес роутера и наш порт. Сохраняем и закрываем

#!/bin/sh [ "$type" == "ip6tables" ] && exit 0 if [ -z "$(iptables-save 2>/dev/null | grep unblock)" ]; then     ipset create unblock hash:net family inet -exist     iptables -I PREROUTING -w -t nat -i br0 -p tcp -m set --match-set unblock dst -j REDIRECT --to-port 1082     iptables -I PREROUTING -w -t nat -i br0 -p udp -m set --match-set unblock dst -j REDIRECT --to-port 1082 fi if [ -z "$(iptables-save 2>/dev/null | grep "udp \-\-dport 53 \-j DNAT")" ]; then     iptables -w -t nat -I PREROUTING -i br0 -p udp --dport 53 -j DNAT --to 192.168.1.1 fi if [ -z "$(iptables-save 2>/dev/null | grep "tcp \-\-dport 53 \-j DNAT")" ]; then     iptables -w -t nat -I PREROUTING -i br0 -p tcp --dport 53 -j DNAT --to 192.168.1.1 fi exit 0
  • Даём права на использование

chmod +x /opt/etc/ndm/netfilter.d/100-redirect.sh
  1. Настройка dnsmasq и подключение дополнительного конфигурационного файла к dnsmasq

  • Удалим содержимое конфигурационного файла dnsmasq:

cat /dev/null > /opt/etc/dnsmasq.conf
  • Откроем файл конфигурации dnsmasq:

mcedit /opt/etc/dnsmasq.conf
  • Записываем содержимое. При необходимости меняем ip роутера. Сохраняем и закрываем

user=nobody bogus-priv no-negcache clear-on-reload bind-dynamic listen-address=192.168.1.1 listen-address=127.0.0.1 min-port=4096 cache-size=1536 expand-hosts log-async conf-file=/opt/etc/unblock.dnsmasq server=8.8.8.8
  1. Добавление задачи в cron для периодического обновления содержимого множества unblock

  • Откроем файл:

mcedit /opt/etc/crontab
  • В конец добавляем строку

00 06 * * * root /opt/bin/unblock_ipset.sh
  • При желании остальные строчки можно закомментировать, поставив решётку в начале. Затем сохраняем и закрываем

] SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin:/opt/bin:/opt/sbin MAILTO="" HOME=/ # ---------- ---------- Default is Empty ---------- ---------- # #*/1 * * * * root /opt/bin/run-parts /opt/etc/cron.1min #*/5 * * * * root /opt/bin/run-parts /opt/etc/cron.5mins #01 * * * * root /opt/bin/run-parts /opt/etc/cron.hourly #02 4 * * * root /opt/bin/run-parts /opt/etc/cron.daily #22 4 * * 0 root /opt/bin/run-parts /opt/etc/cron.weekly #42 4 1 * * root /opt/bin/run-parts /opt/etc/cron.monthly 00 06 * * * root /opt/bin/unblock_ipset.sh
  1. Отключение штатного DNS-сервера и перезагрузка маршрутизатора

  • ·Запускаем командную строку в Windows (открываем пуск и начинаем писать «Командная строка»)

  • Пишем (ip роутера поменяете если другой)

telnet 192.168.1.1
  • Логин с паролем вводим от роутера, а не entware (скорее всего admin, а пароль лично Ваш)

  • Вписываем поочерёдно 3 команды

opkg dns-override system configuration save system reboot
  • Роутер перезагрузится и Вы сможете пользоваться нужными Вам сайтами

    1. После перезагрузки роутера у меня почему-то пропал доступ по 222 порту через putty по ssh. В итоге я подключаюсь по 22 порту через тот же putty, ввожу логин с паролем от роутера, пишу команду:

exec sh

а затем

su - root

и можно использовать любые команды Entware по типу тех, которые мы вводили в данной инструкции.

Заключение

Жду отзывов и улучшения инструкции.


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

Изящное шестистраничное доказательство. Как возникают случайные структуры

Результирует ли случайный граф в треугольник (справа), гамильтонов цикл (в центре) или проявит какие-либо иные интересующие нас свойства?
Результирует ли случайный граф в треугольник (справа), гамильтонов цикл (в центре) или проявит какие-либо иные интересующие нас свойства?

Двое молодых математиков ошеломили коллег, представив полное доказательство гипотезы Кана-Калаи — обобщающее утверждение о том, как возникает структура в случайных множествах и графах.

Когда математики Джефф Кан и Гиль Калаи в 2006 году впервые выдвинули свою гипотезу о «пороге ожидания», они сами в нее не поверили. Их тезис – широкое утверждение о природе математических объектов, именуемых «случайными графами» — казался слишком категоричным, слишком всеобъемлющим, слишком смелым, чтобы претендовать на истинность. Казалось, что он скорее выдает желаемое за действительное, чем отражает математическую истину. Даже с такими оговорками, никто не смог опровергнуть эту гипотезу, и она быстро стала одной из важнейших нерешенных задач в своей области.

Теперь, более 15 лет спустя, двое молодых математиков из Стэнфордского университета сделали то, что, по мнению Кана и Калаи, граничит с невозможным. В на удивление кратком препринте, выложенном в онлайне всего несколько недель назад, Джинён Пак и Гью Туан Фам дали полное доказательство этой гипотезы.

«Оно получилось поразительно простым и изобретательным», —  сказал Калаи, —  «Завораживающим. Чудесным».

Полученный результат автоматически доказывает сотни более специфичных утверждений, каждое из которых с большим трудом поддавалось бы доказательству само по себе — и влечет с собой еще более глубокие следствия для нашего понимания случайных графов и математических множеств в более широком смысле.   

«Я бы назвал их доказательство волшебным», — сказал Джейкоб Фокс, стэнфордский математик, а также научный руководитель Фама, — «оно продвинет вперед значительную часть всей дисциплины».

Замораживаем граф

Гипотеза Кана-Калаи очень обширна и сформулирована на абстрактном языке множеств и их элементов – но, понять ее можно на достаточно простом примере. Для начала представьте граф: множество точек (вершин), соединенных линиями (ребрами). Чтобы сделать случайный граф, возьмем несимметричную монету – такую, что выпадает решкой в 1% случаев, или 30%, или с любым иным процентным соотношением от 0% до 100% — и подбросим ее единожды для каждой пары вершин. Если монета упадет решкой, соединим эти вершины ребром, если упадет орлом – не соединим. Повторим этот процесс для любых возможных пар вершин.

Джинён Пак, математик из Стэнфордского университета, говорит, что «смогла ощутить красоту и силу этой гипотезы, но и представить не могла бы, что мне удастся ее доказать».   Фото: Род Сирси
Джинён Пак, математик из Стэнфордского университета, говорит, что «смогла ощутить красоту и силу этой гипотезы, но и представить не могла бы, что мне удастся ее доказать». Фото: Род Сирси

Математики заинтересовались, когда такой граф, вероятно, может обладать той или иной интересной структурой. Может быть, в нем образуется треугольник, а может быть — гамильтонов цикл; цепочка ребер, проходящая через каждую из вершин ровно один раз. Можно подумать о любом свойстве, до тех пор, пока оно идет с «нарастанием» — то есть, если при добавлении ребер в граф, уже обладающий данным свойством, данное свойство сохраняется.

Если вероятность падения монеты решкой невелика, то и ребра будут редки, а такие структуры как гамильтонов цикл, вряд ли возникнуть. Но, если удастся настроить вероятность, то произойдет нечто странное. Каждое свойство обладает так называемым «порогом»: уровень вероятности, при котором возникает структура, зачастую – совершенно внезапно.

Точно как ледяные кристаллы начинают формироваться, как только температура упадет ниже нуля по Цельсию, вероятность возникновения некоторого свойства вдруг становится очень высокой по мере того, как все больше ребер добавляется в граф. Когда ребра добавляются в случайный граф с N вершин, с вероятностью, например, менее log(N)/N, в таком графе вряд ли возникнет гамильтонов цикл. Но, стоит откорректировать вероятность так, чтобы она была хотя бы чуточку выше log(N)/N, вероятность возникновения гамильтонова цикла становится крайне высокой.

Математики хотят определять такие пороговые уровни для различных свойств, представляющих интерес. «Возможно, пороги — самая фундаментальная вещь, которую мы пытаемся понять», — говорит Фокс, — «я рассматриваю случайный объект: обладает ли он интересующим меня свойством»? Но, тогда как такие пороговые значения уже вычислены для гамильтоновых циклов и некоторых других конкретных структур, в большинстве случаев по-прежнему очень затруднительно определить такой порог или даже уверенно оценить его.

Поэтому математики зачастую полагаются на более простое вычисление, дающее минимально возможное значение порога, то есть, его нижнюю границу. Этот «порог ожидания» в сущности, вычисляется взятием средневзвешенного значения. «Самое приятное с этим порогом ожидания — в том, что он очень легко выяисляется», — говорит Дэвид Конлон, математик из Калифорнийского технологического института, — «в принципе, всего в двух строках можно рассчитать порог ожидания практически для чего угодно».

Но средние значения бывают обманчивы. Так, для гамильтонова цикла порог ожидания равен 1/N, что гораздо ниже истинного значения log(N)/N, в log(N) раз.

Гиль Калай в Еврейском Университете Иерусалима.  Фото: Дэниэл Ваакнин для Quanta Magazine
Гиль Калай в Еврейском Университете Иерусалима. Фото: Дэниэл Ваакнин для Quanta Magazine

В 2006 году Кан и Калаи постулировали, что это, на самом деле, наихудший сценарий. Согласно гипотезе, названной в их честь, разрыв между ожидаемым и истинным пороговым значением никогда не может превышать логарифмического множителя. По Конлону, эта гипотеза «в сущности, берет за основу центральный вопрос, касающийся случайных графов, и предлагает на него общий ответ».

Но это был всего лишь простой случай. Данная гипотеза актуальна далеко не только для случайных графов. Если она верна, то справедлива и для последовательностей случайных чисел, и для обобщений графов — так называемых гиперграфов, и даже для еще более обширных категорий систем. Вот почему Кан и Калаи сформулировали свое утверждение в терминах абстрактных множеств. Случайные графы – это всего лишь частный случай — случайный граф можно трактовать как случайное подмножество от множества всех возможных ребер — но есть и многочисленные иные объекты, попадающие в область применения этой гипотезы. «Странно, но, работая с графами, доказать ее в таком контексте было бы очень сложно», — говорит Конлон, — «но, именно в такой абстрактной постановке задачи каким-то образом раскрывается суть всей проблемы».

Утверждение Кана-Калаи казалось столь невероятным именно из-за своей всеохватности. «Это была очень смелая гипотеза», — сказал Шахар Ловетт, специалист по теоретической информатике из Калифорнийского университета в Сан-Диего. Во-первых, она мгновенно спрямила огромный фронт работ в комбинаторике — попытки рассчитать пороговые значения для различных свойств. «Вопросы, требовавшие, казалось бы, очень длинных и сложных доказательств, вдруг просто исчезли», — говорит Алан Фриз, математик из университета Карнеги-Меллона. — «Доказательства превратились просто в тривиальные варианты применения этой гипотезы».

Тот факт, что столь многие, казалось бы, несвязанные проблемы, удавалось уладить при помощи такой широкой гипотезы, казался многим математикам натяжкой. «Честно говоря, это казалось полным безумием», — сказал Конлон. Кан и Калаи, сформулировав свою гипотезу, не пытались ее доказать. Они занялись поиском контрпримера. Существовало так много постановок задачи, которые они могли бы исследовать, что, заключили эти ученые, рано или поздно они на такой пример наткнутся.  

Но, как оказалось (это слова Калаи), «история стала развиваться по совсем иному сценарию», чем они ожидали.

Путеводный подсолнух

Методы, которые в итоге привели к новому доказательству гипотезы Кана-Калаи, начались с прорыва в решении, казалось бы, совсем иной задачи. Во многом эта история начинается с так называемой «гипотезы подсолнечника», сформулированной математиками Палом Эрдёшем и Рихардом Радо в 1960 году. В рамках этой гипотезы рассматривается, можно ли собирать совокупности множеств по принципу, напоминающему расположение лепестков подсолнуха.

В 2019 году Ловетт работал в составе команды, очень близко подобравшейся к полному решению задачи подсолнечника. На тот момент казалось, что эта работа никак не связана с гипотезой Кана-Калаи, которая оперирует вероятностными рассуждениями. «Я не вижу никакой связи с вашей гипотезой», — сказал Калаи. Не видел такой связи и Ловетт, признавший, что «мы не подозревали о том, что она касается иных вопросов. Нас интересовали подсолнечники».

Но Кан, Пак (на тот момент – докторантка Кана) и их коллеги в итоге смогли связать две эти задачи, когда, несколько месяцев спустя, попытались доказать облегченную версию гипотезы Кана-Калаи. (Их доказательство было опубликовано в журнале Annals of Mathematics в прошлом году). В этой облегченной версии, которую сформулировал французский математик Мишель Талагран, «порог ожидания» из гипотезы Кана-Калаи заменялся «дробным» порогом ожидания — в сущности, применялся иной способ взятия средневзвешенного значения. В пересмотренном определении «появляется больше пространства для маневра при работе», как выразился Ловетт.

Группа, в которой работали Кан и Пак, осознала: можно позаимствовать приемы, позволившие в 2019 году получить результат по гипотезе подсолнечника, скорректировать их и применить к гипотезе Талаграна. «Определенно, это послужило нам толчком», — сказал Кан.

Математики стали решать задачу итерационным методом. Они взялись показать, что, если выбрать случайное множество — скажем, случайный граф — то в нем будет структура, например, гамильтонов цикл. Но они решили выбирать такое случайное множество не сразу, а фрагмент за фрагментом, примерно так, как Ловетт и его коллеги подходили к гипотезе подсолнечника. «Мы итеративно выполняем своеобразный случайный процесс», — говорит Пак, — «пошагово выбираем ребро за ребром». И так, пока в них не соберется полный гамильтонов цикл.  

Чтобы добиться этого, команда обратилась к понятию «разброс», характеризующему степень случайности. Если гамильтоновы циклы обладают хорошим «разбросом», это значит, что не так много циклов содержат одно и то же ребро или подмножество ребер. «Каким-то образом набор ребер разбросан в пространстве», — говорит Фам, — «он не демонстрирует особой кластеризации или концентрации в какой-либо части». Если циклы хорошо распределены таким образом, то процесс случайного поэлементного включения гарантированно позволит захватить как минимум один гамильтонов цикл, даже, если многие другие циклы будут при этом упущены.

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

Занятно, что доказательства этой более слабой гипотезы хватило, чтобы решить целый вихрь задач, связанных с порогами. «Каждое следствие, которое, как нам известно, вытекает из полной гипотезы, также вытекает и из более слабой», — сказал Кан. Фактически, ему, Калаи и другим это подсказывало, что две гипотезы могут быть более или менее одинаковы, то есть, что значения дробных и исходных порогов ожидания были, в сущности, эквивалентны. Если бы кому-нибудь удалось доказать эту эквивалентность, то была бы доказана и гипотеза Кана-Калаи. «Я всегда думал, что единственный способ доказать нашу гипотезу — именно такой», — сказал Кан.

Но произошло нечто другое. Пока другие математики пытались придерживаться именно такого маршрута к полному доказательству гипотезы Калаи-Кана, Пак и Фам нашли совершенно новый подход. «Джинён и Гью нашли эту невероятно прямую, невероятно короткую линию доказательств, которая просто простреливает всю проблему», — сказал Конлон, — «и это экстраординарно. Я такого совершенно не ожидал».

Кан согласен. «Это одна из тех прелестных вещей, какие случаются в математике», — говорит он, — «вещи, казавшиеся нам безнадежными, оказываются не только небезнадежными, но даже несложными».

Удивительный подход

Поначалу ни Пак, ни Фам не планировали браться за исходную гипотезу. Пак, впервые узнавшая об этой задаче в аспирантуре, по ее словам, «смогла почувствовать красоту и силу этой гипотезы, но никогда и не думала, что сможет ее доказать».

«Мы этого совершенно не планировали», — добавляет Фам.

Напротив, они занимались другой гипотезой, сформулированной Талаграном, когда их, по словам Фама, «просто озарило». Они осознали, что «картина, которая здесь открывается перед нами, идеи, которые у нас есть, почему-то должны быть гораздо мощнее, чем кажутся». Эти идеи, рассудили они, вполне помогут пройти весь путь к доказательству гипотезы Кана-Калаи.

Гью Туан Фам Из личного архива
Гью Туан Фам Из личного архива

Всего за одну бессонную мартовскую ночь они сформулировали, как заставить это доказательство работать.

Нормальный порог ожидания, в отличие от дробного, никак не связан с разбросом. Разброс «дает отправную точку. И ты переходишь к исходной, недробной гипотезе, а та отправная точка просто исчезает»,— говорит Кан, — «так что все выглядело очень сурово».

«Что же делать в таком случае?», — сказал Фам, — «мы тогда просто взглянули на проблему под другим углом».

В частности, они стали размышлять над этой задачей в терминах математической сущности, именуемой «покрытием». Покрытие – это совокупность множеств, где каждый объект, обладающий определенным свойством, содержит одно из этих множеств. Например, одно из возможных покрытий всех гамильтоновых циклов — это совокупность всех ребер. Каждый гамильтонов цикл будет содержать одно из этих ребер.

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

Тут в игру и вступают покрытия: когда для подмножества структур можно собрать небольшое покрытие (скажем, таким подмножеством может быть небольшой набор гамильтоновых циклов), это означает, что вклад данного подмножества в порог ожидания невелик. (Напомню: порог ожидания рассчитывается взятием средневзвешенного значения для всех возможных структур заданного типа). Поэтому, теперь Пак и Фаму требовалось показать, что, если в случайном множестве невелика вероятность присутствия искомой структуры, то для всех таких искомых структур должно существовать небольшое покрытие. Основная часть их доказательства посвящена сборке такого небольшого покрытия.

Они решили задачу при помощи пофрагментного сбора образцов – процесса, уже применявшегося при получении более ранних результатов, а также введя, как выразился Фокс, «очень умный аргумент подсчета». Неделю спустя после той бессонной мартовской ночи, они выложили свою изящную шестистраничную статью в Интернете.

«Их доказательство суперпростое. Они берут базовую идею, разработанную нами, а также идеи из других статей – и добавляют в нее небольшой вираж», — говорит Ловетт, — «и с этим новым виражом все значительно, значительно упрощается».

Фриз того же мнения. «Не могу этого объяснить, но, поразительно, тут все верно», — говорит он.

Гипотеза Кана-Калаи, верность которой уже доказана, точно как и дробный результат, автоматически подразумевает доказательство целой кучи смежных гипотез. Но, более того, «это мощная доказательная техника, которая может привести нас к множеству других вещей», — говорит Нога Эйлон, математик из Принстонского университета, — «главное, что они смогли сделать это как следует».

Пак и Фам уже начали применять свой метод к решению других задач. В частности, они стремятся точнее понять разрыв, отделяющий порог ожидания и реальный порог. Доказав гипотезу Кана-Калаи, они продемонстрировали, что этот разрыв обычно сопоставим с логарифмическим коэффициентом – но иногда гораздо меньше, а бывает, что его и нет. В настоящее время не существует более широкого механизма, позволившего бы классифицировать, в каких случаях каждый из этих сценариев может быть верен; математикам придется проработать его пример за примером. На данный момент «мы считаем, что, при помощи такой эффективной техники, можно надеяться, что удастся с гораздо более высокой точностью локализовать эти пороги», — говорит Фам.

А еще это доказательство может привести к совершенно иным следствиям. «Ведь гипотеза Кана-Калаи – совершенно не конец истории», — говорит Пак.  


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

Микрооблако. Давайте знакомить машины друг с другом

В своей предыдущей статье я уже упоминал, что создаю своё микрооблако. Точнее, ну как своё, это будет облако как продукт, а не как услуга. Поэтому оно такое же моё, как и ваше. Как и всего мира. То есть каждый сможет его развернуть на своё железо, будь то датацентр или пара-тройка виртуальных машин и пользоваться им в своё удовольствие, запуская на нем свои потрясающие проекты. Можно даже найти какой-то готовый проект, который лежит где-нибудь на гитхабе и давно просится на старт, только автору исходного кода запускать его было негде, потому что хранение исходников у нас бесплатное, а вот поддержка работы своего сервиса к дешевому сегменту экономики на мой взгляд не относится. А я такой запустил облако, вкинул туда чужой проект и помог миру увидеть то, что так и могло остаться в глубинах гитхаба. Но это фантазии, до реализации которых еще далеко, но путешествие в тысячу миль начинается с первого шага, главное не прекращать перебирать ногами. Поэтому мы продолжаем…

Так вот в прошлом посте в рамках проекта kubos мы остановились на том, что объединили все машинки нашего будущего облака в общую виртуальную сеть. Теперь пора сделать так, чтобы машинки видели друг друга не только по IP-адресам, но и по именам. Для этого нужно запустить и настроить DNS сервер, чем мы сейчас и займемся. Для этого я отвел в гитлабе отдельную ветку, где и будет приведен полный код ansible и не только скриптов, о которых пойдет речь ниже.

Собираем инфу о хостах

Для начала нужно с каждой машины в нашей сети получить информацию о том, какой ip-адрес ей был выдан при подключении в виртуальную сеть. Вероятно, я сделал это несколько костыльно, но не нашел ничего лучше, как на каждой машине создавать json-файл с описанием того, как ее зовут и какой ip-адрес ей выдан. Код ниже был добавлен в ансибл скрипты создания openvpn сети тут и тут

# подготовка реестра какому хосту какой IP был выдан при подключении к сети OpenVPN - name: Create {{inventory_hostname}}.json file   shell: |     VPN_IP=$(ip route | grep tun0 | grep -v via | sed 's/.* src \([0-9.]*\).*/\1/');     REVERSE_VPN_IP=$(echo $VPN_IP | awk -F . '{print $4"."$3"."$2"."$1}');     echo "{ \"vpn_hosts\": [ { \"name\": \"{{ inventory_hostname }}\", \"ip\": \"$VPN_IP\", \"reverse_ip\": \"$REVERSE_VPN_IP\" } ] }" > {{inventory_hostname}}.json;                args:     chdir: $HOME     creates: "{{inventory_hostname}}.json"  - name: Fetch {{inventory_hostname}}.json   fetch:     src: "$HOME/{{inventory_hostname}}.json"     dest: "{{ playbook_dir }}/inventory/"     flat: yes

Такой же код запускается и в скрипте запуска ансибл скриптов, то есть в файле entrypoint.sh. Напоминаю, что скрипт запуска ансибл скриптов мы запускаем из докер контейнера и этот контейнер становится частью виртуальной сети

# подготовка реестра какому хосту какой IP был выдан при подключении к сети OpenVPN VPN_IP=$(ip route | grep tun0 | grep -v via | sed 's/.* src \([0-9.]*\).*/\1/'); REVERSE_VPN_IP=$(echo $VPN_IP | awk -F . '{print $4"."$3"."$2"."$1}'); echo "{ \"vpn_hosts\": [ { \"name\": \"docker\", \"ip\": \"$VPN_IP\", \"reverse_ip\": \"$REVERSE_VPN_IP\" } ] }" > openvpn/inventory/docker.json;     

Ниже приведен пример такого json-файла, который будет создан на каждой виртуальной машине и в докер-контейнере

{   "vpn_hosts": [     {        "name": "worker1",        "ip": "10.10.0.6",        "reverse_ip": "6.0.10.10"     }    ] }

В качестве имени хоста используется имя хоста с точки зрения ансибла, ip — это адрес выданный в openvpn сети (он получен скриптом выше из виртуального устройства tun0). Также в этот же файл добавляется реверсный ip-адрес, т.к. он понадобится в таком виде при настройке реверсной DNS-зоны (так называется зона DNS, которая нужна для поиска имени хоста по его ip-адресу). Реверсную зону настраивать необязательно, если это и правда не нужно. Но я все же решил сделать полноценную настройку DNS, чтоб уж до конца во всем разобраться. Также обращаю внимание, что я специально в json создаю массив из одного объекта, чтобы дальше, получив все такие файлы со всем машин, их проще было смержить в один общий массив при помощи замечательной консольной утилиты jq.

Давайте как раз перейдем к рассмотрению этого мержинга в скрипте запуска всех плейбуков entrypoint.sh

# https://e.printstacktrace.blog/merging-json-files-recursively-in-the-command-line/ jq -s '       def deepmerge(a;b):           reduce b[] as $item (a;               reduce ($item | keys_unsorted[]) as $key (.;                   $item[$key] as $val | ($val | type) as $type | .[$key] = if ($type == "object") then                             deepmerge({}; [if .[$key] == null then {} else .[$key] end, $val])                   elif ($type == "array") then                       (.[$key] + $val)                   else                       $val                   end               )           );       deepmerge({}; .)' openvpn/inventory/* > inventories.json;

Я тут не случайно указал ссылку над данным кодом, потому что для мержа json-ов мне пришлось воспользоваться помощью друга-интернета, потому что писать подобную функцию мне самому не хотелось, а задача, очевидно, уже была кем-то решена, что и подтвердилось после недолгой гуглежки. За данный код выражаю благодарность в адрес Szymon Stepniak. Я внес в этот код лишь небольшие почти косметические изменения, потому что код работал не совсем корректно.

По итогу отработки jq будет создан inventories.json файл вида

{   "vpn_hosts": [     {        "name": "master",        "ip": "10.10.0.1",        "reverse_ip": "1.0.10.10"     },     {        "name": "worker1",        "ip": "10.10.0.6",        "reverse_ip": "6.0.10.10"     },     {        "name": "worker2",        "ip": "10.10.0.8",        "reverse_ip": "8.0.10.10"     }    ] }

Пора уже запустить этот паспортный стол

Для разворачивания DNS-сервера BIND создаем отдельный ансибл playbook

--- - hosts: master   become: true   become_user: root   become_method: sudo   roles:     - dns-server  - hosts: all,!master   become: true   become_user: root   become_method: sudo   roles:     - dns-client

В данном плейбуке 2 роли: днс-сервер и днс-клиент. Этот плейбук как и ранее запускается из докера в скрипте entrypoint.sh при помощи следующего ряда команд

# подготовка файла инвентаризации хостов для настройки DNS {   echo "[servers]";   echo "master ansible_host=host.docker.internal ansible_port=${MASTER_PORT} ansible_user=${USER_NAME} ansible_password=${USER_PASSWORD} ansible_sudo_pass=${USER_PASSWORD}";   echo "";   echo "[clients]";   echo "worker1 ansible_host=host.docker.internal ansible_port=${WORKER1_PORT} ansible_user=${USER_NAME} ansible_password=${USER_PASSWORD} ansible_sudo_pass=${USER_PASSWORD}";   echo "worker2 ansible_host=host.docker.internal ansible_port=${WORKER2_PORT} ansible_user=${USER_NAME} ansible_password=${USER_PASSWORD} ansible_sudo_pass=${USER_PASSWORD}";   echo "worker3 ansible_host=host.docker.internal ansible_port=${WORKER3_PORT} ansible_user=${USER_NAME} ansible_password=${USER_PASSWORD} ansible_sudo_pass=${USER_PASSWORD}";   echo "worker4 ansible_host=host.docker.internal ansible_port=${WORKER4_PORT} ansible_user=${USER_NAME} ansible_password=${USER_PASSWORD} ansible_sudo_pass=${USER_PASSWORD}";       } > dns/hosts;  # установка DNS ansible-playbook -i dns/hosts dns/playbook.yml \   --extra-vars "dns_ip=$VIRTUAL_NETWORK_GATEWAY" \   --extra-vars "@inventories.json";

Сначала как обычно создается файл инвентаризации хостов для ансибла, а далее происходит самое главное: передача переменных в плейбук. Обратите внимание, что переменные передаются путем скармливания inventories.json файла, созданного выше после мержа.

Когда работает плейбук, то на днс-сервере сначала устанавливается сам bind, а потом происходит настройка его конфигов путем заполнения jinja2 шаблонов, которые так любят ансибл девопсы :). Сначала приведу эту часть скрипта ансибла, а потом разберем сами шаблоны

- name: Install bind9   apt:     update_cache: yes     name: [ 'bind9', 'bind9utils', 'bind9-doc' ]     state: present   register: bind9_installed  - name: Replace named.conf.options   template:     src: named.conf.options.j2     dest: /etc/bind/named.conf.options   when: bind9_installed.changed  - name: Replace named.conf.local   template:     src: named.conf.local.j2     dest: /etc/bind/named.conf.local   when: bind9_installed.changed  - name: Ensure /etc/bind/zones directory exists   file:     path: /etc/bind/zones     state: directory  - name: Create db.host.name files   template:     src: db.host.name.j2     dest: "/etc/bind/zones/db.{{ item.name }}"   with_items: "{{ vpn_hosts }}"   when: bind9_installed.changed  - name: Create db.host.ip files   template:     src: db.host.ip.j2     dest: "/etc/bind/zones/db.{{ item.ip }}"   with_items: "{{ vpn_hosts }}"   when: bind9_installed.changed

Тут всего 4 конфига, хотя не такое уж и «всего» :). Сначала создаются опции named.conf.options

acl trusted_clients { {% for vpn_host in vpn_hosts %}     {{ vpn_host.ip }}; # {{ vpn_host.name }} {% endfor %} };  options { directory "/var/cache/bind";  allow-query { trusted_clients; };  forwarders { 8.8.8.8; 8.8.4.4; };  //======================================================================== // If BIND logs error messages about the root key being expired, // you will need to update your keys.  See https://www.isc.org/bind-keys //======================================================================== dnssec-validation auto;  listen-on-v6 { any; }; };

Тут из важного, это настройка ip адресов тех машин, которым разрешено пользоваться DNS-сервером (trusted_clients). В блоке acl данного шаблона идет перечисление всех ip-адресов всех машин в виртуальной сети. В блоке options данный acl подключается, как разрешенный, при помощи директивы allow-query. Также в блоке options важно задать раздел forwarders, чтобы для имен, которые не относятся к нашей виртуальной сети, поиск ip-адресов выполнялся на DNS-серверах google. Все остальное оставлено без изменений в том виде, в котором данный файл поставляется с bind9.

Далее рассмотрим базовый конфиг named.conf.local

{% for vpn_host in vpn_hosts %} // For {{ vpn_host.name }}  zone "{{ vpn_host.name }}" {     type master;     file "/etc/bind/zones/db.{{ vpn_host.name }}"; # zone file path };  zone "{{ vpn_host.reverse_ip }}.in-addr.arpa" {     type master;     file "/etc/bind/zones/db.{{ vpn_host.ip }}";  # reverse zone file path for {{ vpn_host.name }}       };  {% endfor %}

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

Теперь рассмотрим конфиг зоны db.host.name

; ; BIND data file ; $TTL604800 @INSOAlocalhost. root.localhost. (       3; Serial  604800; Refresh   86400; Retry 2419200; Expire  604800 ); Negative Cache TTL ; ; name servers - NS records                         IN      NS      localhost.  ; name servers - A records localhost.              IN      A       {{ dns_ip }}  ; {{ item.name }} - A records {{ item.name }}.        IN      A       {{ item.ip }}

где важно в Serial поставить 3 вместо дефолтной 2-ки, чтобы bind при перезапуске увидел, что в файл внесены изменения. Также нужно заполнить 3 раздела:

  • NS-запись с локалхостом

  • A-запись, чтобы задать свой собственный ip, как ip DNS-сервера

  • A-запись, чтобы задать связь между именем и ip адресом конкретного хоста виртуальной сети

Такой файл будет создаваться для каждого виртуального хоста в сети.

И осталось рассмотреть конфиг реверсной зоны db.host.ip

; ; BIND reverse data file ; $TTL604800 @INSOAlocalhost. root.localhost. (       3; Serial  604800; Refresh   86400; Retry 2419200; Expire  604800 ); Negative Cache TTL ; ; name servers     IN  NS  localhost.  ; PTR Records     IN  PTR {{ item.name }}.  ; {{ item.ip }}

Тут с полем Serial и NS-записью все аналогично конфигу выше для не реверсивной зоны. Единственная разница, что вместо A-записи заполняется одна PTR-запись с именем привязанным к ip-адресу, для которого создается этот файл конфига.

Вернемся к ансибл скрипту с ролью днс-сервера. После того, как все шаблоны файлов конфигов заполнены, нужно проверить корректность конфигурации и рестартовать днс-сервер. Хорошо, что для проверки конфигов bind он поставляется вместе с такими утилитами, как named-checkconf и named-checkzone. Ими мы и воспользуемся

- name: Run named-checkconf   shell: |     named-checkconf;   when: bind9_installed.changed  - name: Run named-checkzone for zones   shell: |     named-checkzone {{ item.name }} /etc/bind/zones/db.{{ item.name }};   with_items: "{{ vpn_hosts }}"   when: bind9_installed.changed  - name: Run named-checkzone for reverse zones   shell: |     named-checkzone {{ item.reverse_ip }}.in-addr.arpa /etc/bind/zones/db.{{ item.ip }};         with_items: "{{ vpn_hosts }}"   when: bind9_installed.changed  - name: Restart named   service:     name: named     state: restarted   when: bind9_installed.changed

Проверять никогда не лишне

Теперь днс-сервер настроен верно и на этом можно заканчивать, но я предлагаю добавить в ансибл скрипты и скрипт запуска ансибл скриптов, который работает в докер контейнере, следующий код проверки корректности отработки всех настроек

- name: Check DNS working correct   shell: |     # проверить, что DNS настроен правильно     if [ $(nslookup google.com | grep -c "Address:\s\+{{ dns_ip }}#53") != 1 ]; then       echo "Using incorrect DNS server";       exit 1;     fi     if [ $(nslookup google.com | grep -c "** server can't find") != 0 ]; then       echo "DNS not working";       exit 1;     fi     for (( index=0; index<$(echo "{{ vpn_hosts }}" | jq length); index++ )); do       name=$(echo "{{ vpn_hosts }}" | jq -sr ".[0][$index].name");       ip=$(echo "{{ vpn_hosts }}" | jq -sr ".[0][$index].ip");       reverse_ip=$(echo "{{ vpn_hosts }}" | jq -sr ".[0][$index].reverse_ip");       echo "Check DNS for name=$name ip=$ip reverse_ip=$reverse_ip";       if [ $(nslookup $name | grep -c "Address: $ip") != 1 ]; then         echo "DNS server's zones configured incorrectly";         exit 1;       fi       if [ $(nslookup $ip | grep -c "$reverse_ip.in-addr.arpa\s\+name = $name.") != 1 ]; then              echo "DNS server's reverse zones configured incorrectly";         exit 1;       fi     done     echo "DNS - OK";      echo "" > $HOME/dns.checked;   args:     creates: $HOME/dns.checked     executable: /bin/bash # меняю, потому что /bin/sh не справится с for выше

В этом коде просто проверяется, что и интернет имена доступны на примере google.com, и что доступны имена всех наших машин. Для наших машин также проверяется и реверсивный днс-поиск.

Подводим итоги

Теперь у нас машины состоят в виртуальной сети и знают друг друга по именам.

Настало время устроить рок-н-ролл на этих машинах. На следующем этапе я планирую запустить на них кубер. Так шаг за шагом мы создадим что-то приличное в нашем микрооблаке.

И в завершении, как всегда, предлагаю присоединяться к нашему телеграмм каналу и чату. О всех крупных вехах развития проекта планируется создаваться публикации на хабре, но в канале будут публиковаться разные мысли по проекту, вызывающие трудности. Также могут быть уведомления о разных изменениях, например, если станет понятно, что кубер ставить еще рано, как уже бывало 🙂 И, разумеется, весь код публикуется на гитлабе. Код открыт, потому что наша задача — это создать облако как продукт и для каждого.


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

Как избежать бардака в работе арт-команды и наладить производственные пайплайны

Когда арт-команда разрастается, рабочие процессы могут начать путаться: стиль художников может постепенно меняться, визуальный облик игры — отдаляться от оригинальной задумки, и повсюду будут появляться небольшие ошибки, которые рано или поздно перерастут в крупную проблему.

Чтобы не допустить всего этого, в игровых студиях есть Art Design Document (ADD) — свод правил и рекомендаций по работе художников. Там перечислены арт-решения, которые формируют визуальный облик игры, позволяют добиться единообразия стиля, упрощают онбординг новых сотрудников и гарантируют сохранения оригинальной задумки даже через годы развития проекта.

Арт-директор в студии IT Territory (ITT) Игорь Архипов на конференции TBD Pro: Art рассказал, как в команде художников Rush Royale устроен рабочий процесс, а также поделился правилами формирования Art Design Document. Пересказываем его выступление.

Rush Royale — это PvP и PvE игра, которая объединяет в себе жанры tower defence и merge
Rush Royale — это PvP и PvE игра, которая объединяет в себе жанры tower defence и merge

Что такое Art Design Document

Первое, что делает каждый новый художник в ITT — читает Art Design Document. В ADD собрана вся основная информация, которая позволяет понять общее видение арт-команды. В документе обычно расписано несколько ключевых пунктов.

Все начинается со «Словаря проекта». Он важен в первую очередь для начинающих художников — там описаны основные термины и понятия, которые применяются в работе. При этом туда входят вещи, которые касаются не только арта, но и гейм-дизайна — это позволяем всем членам команды общаться на одном языке. Гейм-дизайнеры тоже читают ADD — это помогает им проще понимать художников.

Во «Введении» описан жанр проекта, главные особенности, а также другая информация, которая позволяет понять, что из себя представляет игра. Также в этом пункте описаны основные конкуренты на рынке.

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

В части «Цели и задачи» прописана целевая аудитория, а также перечислены все задачи, которые должен решить ADD.

Пункт «Пайплайны» содержит в себе описание рабочего процесса для всего арт-контента в игре: от небольших иконок до крупных промо-артов.

Следующий пункт — «Построение кадра». Обычно арт-лиды следят за тем, чтобы интерфейс не залезал на задний план, задний план на передний, чтобы не путались игровые сущности. Если же из команды уходят ключевые специалисты, то контроль над построением кадра может ослабиться. В этой части ADD написаны требования к построению кадра, которые позволяют избежать заметных ошибок.

ADD не обязательно должен быть полностью написан в самом начале работы. Зачастую достаточно прописать несколько первых пунктов, а остальные дополнить позже. Пункт «Примеры» появляется через некоторое время после старта разработки. Туда попадают эталонные изображения, на которые ориентируются все остальные члены арт-команды.

Когда новый художник ознакомился с ADD, он берется за Game Design Document (GDD). Каждый сотрудник должен понимать, как устроен игровой цикл в проекте — знать, какие там механики, что цепляет пользователей. В этом нужно разбираться, чтобы затем усилить ключевые особенности при помощи визуальных приемов.

Рабочий процесс создания арт-ассетов

С увеличением популярности Rush Royale разрослась и команда. Вместе с этим поменялись и рабочие процессы. В самом начале в команде было два художника, один аниматор и FX-художник, один UI-художник. Тогда арт-директор выполнял сразу множество обязанностей: был художником, VFX-художником, давал фидбек коллегам, контролировал, насколько гармонично арт сосуществует с гейм-дизайном, занимался постановкой задач, планированием и делал многое другое.

Когда проект набрал популярность, у арт-команды появился собственный проджект-менеджер, количество художников увеличилось до восьми, аниматоров и FX-художников — до трех, UI-художников — до четырех. В каждой из этих команд появился свой лид (а в команде художников кроме арт-директора появилось еще два лида).

Лиды занимаются тем, что формируют типовые задачи, а затем передают их проджект-менеджеру. Он же подробно расписывает таски и распределяет по членам команды. Преимущество такого подхода заключается в том, что арт-директору не приходится все держать у себя в голове — он делегирует выполнение менее важных задач, а сам занимается высокоуровневыми вещами, которые напрямую связаны с развитием проекта.

В ITT процесс создания арт-ассетов разделен на несколько этапов. На первом художник ознакамливается с задачей. Ошибка на этом этапе особенно критична, потому что недостаточно точное техническое задание может привести к тому, что весь ассет будет нарисован неправильно. И в итоге цепочку производства арта придется перезапускать с самого начала.

У задачи должно быть корректное описание: к нему нужно прикладывать все ссылки на GDD, UX-макет, референсы от гейм-дизайнеров и так далее. Если художнику не все понятно, он обязательно должен задать уточняющие вопросы.

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

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

Затем нужно открыть ADD и посмотреть основные проекты-референсы. Когда подготовительная работа сделана, можно зайти на специальные платформы — Pinterest, Behance, ArtStation, Sketchfab, Google, Huaban.

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

Затем идет этап создания эскиза (thumbnail) — это совсем небольшой набросок, в котором вы проверяете композицию. Здесь не нужны детали, а стиль рисунка может немного отличаться от такового в игре. Самое главное — выразить идею. Для этого вы можете сперва сформулировать ее в виде текстового предложения, а потом воплотить в виде рисунка. Thumbnail не обязательно должен быть цветным — достаточно черно-белой палитры.

После художник создает цветовой концепт. По словам Игоря, на этом этапе он старается не использовать лайн, так как это отнимает много времени, а рисует от цветового пятна. Также он уточняет композицию, набрасывает цвет.

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

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

Следующий шаг — отрисовка основных форм. Цель этого этапа — сделать изображение максимально аккуратным даже без лайна. В своей работе арт-команда Rush Royale применяет Pen Tool — это векторный инструмент, который позволяет подчеркнуть форму каждого элемента композиции. Если вы работаете над интерфейсом, то к таким формам можно легко применить эффекты в Photoshop: например, наложить аккуратный лайн на иконки или добавить объем.

Дальше — 2D-рендер: его качество напрямую зависит от навыков художника. Нет никаких простых способов сделать 2D-рендер хорошо: все зависит от опыта исполнителя. Тем не менее есть несколько советов, которые могут помочь улучшить итоговый результат.

В своей работе Игорь использует Clipping Mask (Обтравочную маску) — инструмент, с помощью которого можно прикреплять к формам дополнительные слои и редактировать картинки в изолированной среде.

Общий объем команда Rush Royale наносит мягкой круглой кистью, а акценты и падающие тени делает жесткой кистью или протирает ластиком. По словам Игоря, в конце можно добавить слой с шумом, высокой прозрачностью и наложением по режиму Soft Light — это сделает изображение немного зернистым и добавит интересные оттенки. Также можно сделать смещение по каналам, если это не навредит картинке — такой прием создает эффект кинематографичности.

Последний этап — интеграция. Сюда входит нарезка и добавление ассетов в проект. Нарезку делают с помощью инструмента Slice Tool: им можно разметить свои объекты, назначить каждому контейнеру имя и сохранить спрайты по-отдельности. Для заливки в проект каждый художник должен разбираться в навигации игровых движков.


Art Design Document и внутренние гайды обязательно нужны в работе любой команды — они позволяют сохранить изначальную задумку автора даже через много лет, когда ведущие сотрудники поменяются. Документация станет гарантом того, что стиль вашего проекта останется единым и будет соответствовать оригиналу. Если ADD грамотно и подробно написан, то это значительно упростит интеграцию новых арт-сотрудников в рабочий процесс.

Если художники следуют пайплайну, то это делает их работу более предсказуемой — благодаря этому команда может спланировать, сколько времени потребуется на создание контента. И от этого будет зависеть дата релиза. К тому же четкий пайплайн позволяет легче управлять командой из нескольких человек — с ним не обязательно контролировать каждый шаг художников.


ссылка на оригинал статьи https://habr.com/ru/company/mygames/blog/663810/