Наборы с отслеживанием состояния Kubernetes - сопоставление существующих идентификаторов с постоянными модулями / модулями с отслеживанием состояния

Заранее спасибо всем, кто помогает.

Здравствуйте, у меня есть несколько уникальная проблема, ее довольно долго объяснять, но я думаю, что если она будет решена, мы сможем расширить варианты использования Kubernetes. Думаю, я знаю, как это решить, но не уверен, поддерживает ли Kubernetes Stateful Sets это решение. Позвольте мне подробнее рассказать о проблеме, самой проблеме, а затем о некоторых из моих примеров решений и, возможно, кто-то может помочь заполнить пробелы.

Доменное пространство:

  • У меня есть набор учетных записей (внешних по отношению к kubernetes) {Account_A, Account_B, Account_C и т. Д.}
  • Учетные записи могут быть активными или неактивными в любое время (Важно: НИ В КОНКРЕТНОМ ПОРЯДКЕ).
  • Если эта функция активирована, развертывается модуль, который обслуживает эту учетную запись и хранит постоянный том со всеми этими учетными записями, рабочим пространством / данными. Эта учетная запись взаимодействует с ее уникальным идентификатором модуля и IP-адресом.
  • Если этот параметр отключен, модуль удаляется, но данные сохраняются, так что в следующий раз, когда он будет активирован, он будет привязан к тому же требованию постоянного тома и, следовательно, получит доступ к своим предыдущим данным.
  • При повторной активации модуль развертывается повторно, который использует предыдущее требование постоянного тома для возобновления работы с данными из предыдущих сеансов.

Очевидно, что, глядя на доступные инструменты / объекты Kubernetes, набор с отслеживанием состояния с headless-service - идеальный способ приблизиться к этому. Он поддерживает уникальные поды, которым назначаются уникальные IP-адреса, и поддерживает постоянные тома. Он также поддерживает динамическое предоставление постоянных томов через

Проблема:

Как упоминалось в домене, учетные записи могут быть активны в любом порядке, но модули с установленным состоянием являются порядковыми, то есть модуль pod_1 должен быть активен, чтобы модуль pod_2 был активен, чтобы модуль pod_3 был активен, и т. Д. Мы не можем иметь модули pod_1 active и pod_3. активен, пока pod_2 неактивен. Это означает, что если я включу Account_A, затем Account_C, будет создан модуль с именем pod_1, а затем будет создан модуль с именем pod_2.

Теперь вы можете сказать, что это не проблема. Мы просто храним карту, которая сопоставляет каждую учетную запись с относительным номером pod_number. Например, Account_A -> pod_1 и Account_C -> pod_2.

Почему это проблема? Поскольку при указании volumeClaimTemplate в наборе с отслеживанием состояния постоянные-тома-утверждения используют имя модуля в качестве идентификатора при создании. Это означает, что только модуль с таким же именем может получить доступ к одним и тем же данным. Данные (тома) привязываются на основе имени модуля, а не учетной записи. Это создает разрыв между учетными записями и их постоянными томами. Любой модуль с именем pod_2 всегда будет иметь те же данные, что и модуль pod_2, независимо от того, какая учетная запись была «сопоставлена» с модулем pod_2.

Позвольте мне проиллюстрировать это на примере:

1. Account_A=disabled, Account_B=disabled, Account_C=disabled (Start state, all accs disabled)
2. Account_A=enabled, Account_B=enabled, Account_C=enabled -> (All accounts are enabled)
    pod_1 is created (with volume_1) and mapped to Account_A
    pod_2 is created (with volume_2) and mapped to Account_B
    pod_3 is created (with volume_3) and mapped to Account_C
3. Account_A=disabled, Account_B=disabled, Account_C=disabled (All Accounts are disabled)
    pod_1 is deleted, volume_1 persists
    pod_2 is deleted, volume_2 persists
    pod_3 is deleted, volume_3 persists
4. Account_A=enabled, Account_B=disabled, Account_C=enabled (re-enable A and C but leave B disabled)
    pod_1 is created (with volume_1) and mapped to Account_A (THIS IS FINE)
    pod_2 is created (with **volume_2**) and mapped to Account_C (THIS IS **NOT** FINE)

Вы видите проблему? Account_C теперь использует хранилище данных, которое должно принадлежать Account_B (volume_2 был создан и использовался account_b, а не Account_C) из-за того, что тома / заявки сопоставляются по имени с именами модулей, а модули должны быть порядковыми, то есть pod_1 тогда pod_2.

Возможные решения

  1. Уметь поддерживать настраиваемые не порядковые имена для модулей в наборе с отслеживанием состояния. (Самый простой и эффективный)

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

    (p.s.) Я знаю, что наборы с отслеживанием состояния должны быть порядковыми для гарантии заказа, но вы можете отключить это с помощью "podManagementPolicy: Parallel"

  2. Какой способ сделать это с помощью меток и селекторов?

    Я новичок в Kubernetes и до сих пор не совсем понимаю все движущиеся части. Может быть, есть способ использовать метки в моем шаблоне volumeClaimtemplate, чтобы требования тома прикреплялись к томам с определенной меткой. то есть Account_C, сопоставленный с pod_2, может запрашивать volume_3, потому что volume_3 имеет метку с: account = Account_C. Я сейчас занимаюсь этим. Если это помогает, мои постоянные тома предоставляются динамически с помощью этого инструмента: https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client Может быть, я могу как-то изменить его, чтобы он добавлял определенные метки к создаваемым постоянным томам.

  3. Откажитесь от наборов состояний и развертываний и просто добавьте модули вручную в кластер

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

  4. Создайте собственный объект Kubernetes, чтобы сделать это за меня

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

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

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


person user2896438    schedule 21.02.2020    source источник
comment
Разве вы не можете просто записать все постоянные данные модуля в {directory} / {pod_name}, когда модуль деактивирован, он экспортирует архив {directory} / pod_name в место хранения, и когда учетная запись, сопоставленная с этим модулем, повторно активировал скачивает архивированные данные и восстанавливает их?   -  person Alexandre Daubricourt    schedule 22.02.2020
comment
Какой бой с использованием отдельных наборов состояний для каждой учетной записи?   -  person Patrick W    schedule 22.02.2020
comment
@AlexandreDaubricourt: да, но мне кажется, что это неправильный подход. Что произойдет, если модуль выйдет из строя из-за ошибки. Правильного выключения не происходит, и данные теряются. В потенциальном решении № 5 я упоминаю, что модуль обрабатывает собственное хранилище, но я хочу максимально использовать Kubernetes и его встроенные функции. Nfs не хватает безопасности, и я должен использовать nfs, поэтому я бы предпочел, чтобы Kubernetes обрабатывал монтирование данных, чтобы пользователи не могли произвольно получить доступ к другим данным из своего модуля, так сказать.   -  person user2896438    schedule 22.02.2020
comment
@PatrickW Да, я думал об этом, но разве это не много накладных расходов на каждую капсулу? Я имею в виду, что каждый модуль имеет свой собственный полнофункциональный контроллер репликации, набор репликации и т. Д. Цель этого проекта - иметь возможность максимально масштабироваться. Вы знаете, сколько дополнительных накладных расходов это вызовет? Может быть, это ничтожно и я слишком много думаю?   -  person user2896438    schedule 22.02.2020
comment
Это дополнительные накладные расходы, но, опять же, добавление CRD. Поскольку нет готового решения, любое исправление будет иметь дополнительные накладные расходы.   -  person Patrick W    schedule 22.02.2020
comment
Да, это просто кажется такой очевидной функцией, которая применима ко многим сценариям использования, что я чувствую, что должно быть готовое решение. Хотелось надеяться, что кто-то прочитает это и укажет на то, чего мне явно не хватало (я выучил весь Kubernonsense примерно за день, поэтому мне все еще не хватает знаний). Я пойду и запрошу функцию, я думаю. Спасибо за ответы.   -  person user2896438    schedule 22.02.2020


Ответы (2)


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

StatefulSets имеют ординальность по двум причинам:

  • Создание упорядоченного PersistentVolumeClaims
  • Возможность создавать конечные точки FQDN для отдельных модулей (с помощью безголовой службы)

В вашем случае ни то, ни другое не кажется правдой. Вам просто нужно стабильное хранилище для каждой учетной записи. Хотя вы думаете, что №4 из ваших потенциальных решений является самым неидеальным, это наиболее «нативный для Kubernetes» способ сделать это.

Решение

Вам нужно написать компонент, который управляет StatefulSet или даже Deployment для каждой учетной записи. Я говорю о развертывании, потому что вам не нужны стабильные сетевые идентификаторы для каждого модуля. Для связи достаточно ClusterIP услуг на аккаунт.

В мире Kubernetes эти компоненты называются контроллерами (без настраиваемых объектов) и операторами (с настраиваемыми объектами / управляющими приложениями).

Вы можете начать с просмотра operator-sdk и среда выполнения контроллера. SDK оператора объединяет часто используемые функции поверх controller-runtime в качестве платформы. Это также упрощает жизнь разработчикам за счет включения kubebuilder, который используется для генерации кода CRD и K8S API. для нестандартных объектов. Все, что вам нужно определить, - это structs для вашего настраиваемого объекта и контроллера.

Взгляните на Operator SDK, вы обнаружите, что создание и управление настраиваемыми объектами не так уж и сложно.

Пользовательский поток на основе объекта для вашей проблемы

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

  • Один Account объект соответствует одной учетной записи. Каждый объект имеет уникальные метаданные, которые сопоставляют его с его учетной записью. В его спецификации также должно быть указано active: boolean.
  • Следите за нестандартными Account объектами
  • Всякий раз, когда вам нужно создать новую учетную запись, используйте API Kubernetes для создания нового объекта Account (вызовет событие Add в контроллере), а затем ваш контроллер должен

    • Create/Update a PersistentVolumeClaim for the account
    • Создайте / обновите Deployment томом из созданного PVC, указанного в шаблоне Pod
    • Catch: события добавления также принимаются для старых объектов при перезапуске контроллера. Таким образом, действие должно быть «Создать или обновить».
  • Установите поле active в вашем настраиваемом объекте на false для деактивации учетной записи (событие Modify в контроллере), а затем ваш контроллер должен

    • Delete the deployment without touching the volume at all.
  • Set the active field to true for reactivating the account. (modify event again)
    • Recreate the deployment with the same volume specified in the Pod template
  • Удалите объект Account, чтобы очистить базовые ресурсы.

Хотя все это может не сразу иметь смысл, я все же предлагаю вам просмотреть документацию и примеры operator-sdk. ИМО, это было бы шагом в правильном направлении.

Ура!

person ashu    schedule 22.02.2020
comment
Спасибо, что помогли мне указать правильное направление. Это имело большой смысл и было хорошо объяснено. Также очень полезно предоставление инструментов для правильной разработки пользовательских объектов, иначе я бы, вероятно, заблудился в поисках правильных инструментов / отправной точки. Я обязательно буду реализовывать настраиваемый контроллер / оператор для автоматизации правильного рабочего процесса, а также настраиваемые объекты для работы. - person user2896438; 22.02.2020
comment
И последний вопрос: что вы думаете об использовании заданий вместо развертываний в качестве родительского модуля? Поскольку обычно эти учетные записи будут запускаться только в течение нескольких часов в день, и мы могли бы смоделировать отправку заданий, когда учетные записи установлены как активные, а завершение задания - это учетная запись, отключенная (или выходящая из системы). Это будет поддерживать требование репликации с использованием собственных процессов (перезапуск задания). Все они могут запустить безголовый сервис, чтобы раскрыть и предоставить уникальный доступ. Я бы все равно создал настраиваемый контроллер, как вы предложили, для правильного выделения ресурсов (томов), разборки и т. Д. - person user2896438; 22.02.2020
comment
Кроме того, событие выхода / отключения в любом случае генерируется внутри контейнера / модуля, поэтому простой выход из процесса контейнера может сигнализировать о завершении задания, а затем мой контроллер может следить за завершением задания и устанавливать статус учетной записи в отключенное состояние. - person user2896438; 22.02.2020
comment
Наконец, вопрос: вы думаете, что это преувеличение / злоупотребление тем, чем должна быть работа? На мой взгляд, это устраняет необходимость в накладных расходах на все развертывание для каждой учетной записи, а также на службу Nodeport для каждого развертывания. Быстрый простой ответ «да» или «нет» сделает мой день лучше, не нужно вдаваться в подробности - person user2896438; 22.02.2020
comment
@ user2896438 Вы определенно можете выбрать использование Jobs вместо Deployments, но вам нужно будет убедиться, что основной процесс Pod не завершится раньше, чем вы этого захотите, чтобы предотвратить удаление Pod. Что касается служебной части, то и задания, и развертывание должны быть развернуты как объект, поэтому накладные расходы аналогичны. Это полностью зависит от вас. Что касается бита NodePort, вы можете использовать ClusterIP с Ingress. Так будет легче управлять, ИМО. Опять же, я не уверен в сценарии использования, поэтому NodePort также может быть более подходящим. - person ashu; 22.02.2020
comment
Для всех, кто следил за этим обсуждением и хотел изучить операторов, это были самые полезные ресурсы в настройке и запуске оператора: youtube.com/watch?v=8_DaCcRMp5I learn.openshift .com / operatorframework / go-operator-podset. - person user2896438; 24.02.2020

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

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

youtube.com/watch?v=8_DaCcRMp5I learn.openshift.com/operatorframework/go-operator-podset https://itnext.io/a-practical-kubernetes-operator-using-ansible-an-example-d3a9d3674d5b

Я настоятельно рекомендую полностью изучить оба этих ресурса (и кодировать вместе), прежде чем пытаться создать своего собственного оператора. Кроме того, если вы «новичок» в golang, обязательно воспользуйтесь подходом ansible, ДАЖЕ ЕСЛИ вы хотите создать свой собственный оператор golang. Подход Ansible более интуитивно понятен, и концепции очень быстро «щелкнули», когда играли с этим.

Что касается Голанга против Ансибла

Голанг: немного больше контроля, но гораздо больше сложности, утомительности и нюансов.

Ansible: очень интуитивно понятный, решает операторы на высоком уровне Kubernetes, модульный / многоразовый

Также бесценен Slack-канал # kubernetes-Operator

person user2896438    schedule 26.02.2020