Как мы создали Plural — мультиоблачную платформу доставки приложений на базе Kubernetes
7 апреля 2022 г.Введение
Во-первых, я думаю, что важно обсудить мотивы создания Plural, поскольку именно они в конечном итоге определяют большинство наших технических решений. Первоначально множественное число возникло из моего энтузиазма по поводу Kubernetes, особенно из осознания того, что уникальное сочетание богатого расширяемого API и сильного сообщества может в конечном итоге предоставить платформу для создания самоуправляемых приложений.
Но когда я начал исследовать развертывание Kubernetes многих популярных приложений с открытым исходным кодом, стало ясно, что существует большая пропасть между даже хорошим развертыванием Kubernetes и полностью размещенным предложением, предлагаемым облачным провайдером или поставщиком зрелого программного обеспечения.
Это означало, что, хотя у Kubernetes есть большой технический потенциал, пока этот пробел в пользовательском опыте не будет устранен, в целом он не является коммерчески жизнеспособным. Тем не менее, я думал, что разрыв можно закрыть; учитывая, насколько зрелыми на самом деле являются многие инструменты, большой нерешенной проблемой является предоставление рабочего процесса, который позволяет последовательно сочетать стандартную цепочку инструментов для развертывания, что мы и создаем в Plural.
Стоит точно перечислить, что это за ограничения, по крайней мере, поскольку я постоянно их видел:
- Приложения должны быть адаптированы к каждому конкретному облаку. Обычно это сводится к вводу учетных данных и настройке объектного хранилища/базы данных. Тем не менее, каждое облако имеет свои собственные службы, API и соглашения, что быстро означает, что вы просматриваете n наборов документов, где n — количество поддерживаемых поставщиков.
- Большим преимуществом работы непосредственно в Kubernetes является глубокая настраиваемость, но это препятствует функциональному готовому опыту, и большинство инструментов не решают ни того, ни другого.
- Жизненный цикл приложения необходимо решить, поскольку неуправляемое, но простое в установке приложение по-прежнему является кучей технического долга. Это требует действительно сильного администрирования UX.
Кроме того, нам нужен был набор абстракций и принципов, которые можно масштабировать практически для любого приложения, развертывать практически в любом облаке и использовать практически любой разработчик.
Стало ясно, что решение проблемы настраиваемости облака и приложения так же сложно, как и проблема управления кодом.
Вы можете думать об этом как об управлении графом зависимостей для приложения между другими приложениями и подмодулями, необходимыми для создания различных облачных ресурсов, необходимых приложению.
Возьмите Apache Airflow в качестве примера; обычно необходимо развернуть следующие вещи:
- корзина хранения объектов журнала (которая отличается в зависимости от облака, а Azure уникальна тем, что вообще не совместима с s3)
- сервер Redis для очереди сельдерея
- постгрес
- веб-сервер / рабочий / планировщик воздушного потока
Практически при любом развертывании airflow потребуется управлять последовательной установкой всех этих компонентов, и при любом обновлении также потребуется выполнять некоторую проверку совместимости версий, чтобы убедиться, что все компоненты могут работать вместе.
Архитектура
Итак, как мы ее решили? В общем, мы выбрали архитектуру с 3 основными компонентами:
- основной множественный API — API-интерфейс graphql, который эффективно служит менеджером пакетов для всех поддерживаемых нами модулей развертывания, например, terraform и helm, и их зависимостей для управления созданием произвольных приложений, подобных описанным выше. Думайте об этом как о npm для devops, но с подсистемой развертывания.
- интерфейс командной строки — отвечает за получение информации, хранящейся в API, и создание стандартизированного рабочего пространства в репозитории git на основе того, что установил пользователь. Он также выполняет работу по выполнению команд terraform и helm, используя это рабочее пространство.
- Консоль администратора — веб-служба, которую можно развернуть в вашем собственном кластере Kubernetes, чтобы взять на себя все 2+ дневные операционные обязанности по управлению приложениями. В частности, его самая большая ответственность заключается в принятии и применении обновлений по мере их прохождения через API.
Стоит покопаться в некоторых технических решениях, которые мы сделали в каждой из этих систем.
Эликсир
Мы приняли несколько необычное решение использовать Elixir для нашего серверного кода как в API, так и в консоли администратора. У меня был предыдущий опыт создания очень большой кодовой базы elixir на Frame.io, и я научился любить этот язык, но были некоторые уникальные причины, которые сделали его, а на самом деле всю экосистему BEAM (виртуальная машина elixir), хорошо подходящей для Plural:
- Потребность в большом количестве UX на основе WebSocket в реальном времени, особенно в отношении отображения изменений состояния в кластере Kubernetes, естественным образом поддается реализации модели акторов BEAM VM, и Elixir/Phoenix делают это очень доступным.
- Наша консоль администратора должна быть пуленепробиваемой, так как это интерфейс для управления всем другим набором приложений в Plural. Если он падает, пользователи фактически летают вслепую. Elixir/erlang печально известен своей чрезвычайной надежностью. Он также должен быть эффективным, поскольку мы хотим, чтобы «множественный налог» был как можно меньше. BEAM прекрасно масштабируется по вертикали и обеспечивает надежность на уровне сетевого коммутатора.
- Потребление памяти для эликсира удивительно стабильно для управляемой среды выполнения. Это также связано с реализацией модели акторов: каждому «процессу» выделяется собственная куча и стек, поэтому, если вы программируете в соответствии со стандартными практиками BEAM, используя эфемерные процессы, организованные вместе для управления вашим приложением, смерть этих процессов может направить виртуальную машину. эффективно использовать неиспользуемую память. Подробнее о том, как все это работает, можно прочитать здесь.
- Динамическая типизация значительно упрощает быструю разработку, в то время как мощное сопоставление шаблонов в elixir позволяет масштабировать кодовую базу аналогично статическому языку, поскольку он может предоставлять еще более мощные контракты типизации для статической типизированной сигнатуры функции (за исключением того, что в конечном итоге принудительно применяется во время выполнения).
Как и в случае с graphql, использование elixir требует компромиссов. Наиболее значимым из них является сообщество. Elixir — нишевый язык, и у вас не так много исходных разработчиков, из которых можно было бы исходить для него; тем не менее, существующие разработчики эликсира любят продолжать работать над эликсиром и часто имеют высокое качество.
В языке также происходит интересный процесс наращивания, поскольку это значительный сдвиг парадигмы от императивных и объектно-ориентированных языков к полностью функциональному языку с сильными гарантиями неизменности. Частью того, как я справлялся с этим в прошлом, было очень активное парное программирование с новыми разработчиками в рамках процесса адаптации в кодовой базе.
Наконец, динамическая типизация является значимым ударом по производительности по сравнению со статической типизацией, наряду с накладными расходами, вызванными неизменностью, особенно для работы, связанной с процессором, которую наша серверная сторона будет выполнять изрядно (особенно сериализация JSON). Я думаю, что некоторые недавние изменения в BEAM должны улучшить прямолинейную производительность elixir/erlang, но это все же стоит отметить.
GraphQl
При создании API доступны два основных шаблона: REST и GraphQl. Я создавал REST API на многих предыдущих должностях, но было две основные причины, по которым я действительно предпочитал GraphQl.
Во-первых, в настоящее время он гораздо лучше поддерживается в браузере. Apollo Client делает разработку React намного проще, чем Redux, а также кажется более производительным, и я ожидал много сложного пользовательского интерфейса для решения действительно сложной проблемы UX при обеспечении работоспособности большого количества приложений.
Во-вторых, я знал, что нам понадобится много функций в реальном времени в различных продуктах, и не так много протоколов сплошной сети, которые можно было бы добавить поверх веб-сокетов... за исключением подписки на GraphQl. Возможность иметь автоматически типизированные, самодокументирующиеся клиенты веб-сокетов была огромной победой, и я чувствовал, что небольшая новинка GraphQl стоит того.
Тем не менее, был один недостаток. Создание программных клиентов GraphQl на языках, отличных от javascript, — это своего рода кривая обучения, особенно на строго типизированных языках, таких как Golang. Поддержка библиотек часто довольно минимальна или не выглядит функциональной. После того, как вы оплатите первоначальную стоимость установки, преимущества GraphQL действительно начнут проявляться.
Голанг
Значительная часть нашего продукта связана с дистрибутивом CLI. Двумя распространенными языками, которые мы могли бы использовать для сборки, были python и golang. Я думаю, что golang является очевидным победителем благодаря способности создавать легко распространяемые кроссплатформенные двоичные файлы самостоятельно, но также он дает нам возможность статически связывать исходный код для многих инструментов, которые нам понадобятся, а также в экосистеме Kubernetes. . Мы также написали достаточное количество кода оператора Kubernetes для управления средой выполнения нескольких приложений, и хорошо бы выбрать язык, который позволяет нашим командам разработчиков легко переключаться между обеими этими кодовыми базами.
Заключение
Все эти решения бесконечно более детализированы, но мы подумали, что могут быть некоторые идеи, которые люди могут найти полезными, или, может быть, просто пища для размышлений. Если вам интересно узнать больше, все, что мы создаем, является открытым исходным кодом, поэтому не стесняйтесь проверить их, которые вы можете найти по этим ссылкам (поставьте нам звезду, если вам нравится то, что мы делаем):
Или попробуйте сами: https://app.plural.sh
Оригинал