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

Consul

Перевод Практическое руководство по HashiCorp Consul Часть 1

07.12.2020 10:20:40 | Автор: admin


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


Как насчет настройки обнаруживаемого, настраиваемого и безопасного service mesh с помощью одного инструмента?


Что, если мы скажем вам, что этот инструмент не зависит от платформы и готов к работе в облаке?


И поставляется в виде одного бинарного файла.


Все это правда. Инструмент, о котором мы говорим, это HashiCorp Consul.


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


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


Содержание:


Вступление


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



Монолитное приложение ("типовое") с различными подсистемами A, B, C и D



Распределенное приложение ("типовое") с различными сервисами A, B, C и D


HashiCorp Consul это инструмент с открытым исходным кодом, который решает эти новые сложности, предоставляя обнаружение сервисов, проверку работоспособности, балансировку нагрузки, график сервисов, взаимное применение идентификации TLS и хранилище конфигурационных ключей. Эти особенности делают Consul идеальным control plane для service mesh.



HashiCorp Consul поддерживает обнаружение сервисов, конфигурацию сервисов и сегментацию сервисов


HashiCorp объявил Consul в апреле 2014 года, и с тех пор он получила хорошее признание сообщества.


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


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


Краткая справка о Монолитных и Сервис-ориентированных архитектурах (SOA)


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


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


Один из примеров, который технический директор HashiCorp Армон Дадгар привел во время своего вступительного видео для Consul, был о поставке настольного банковского приложения. Он имеет дискретный набор субкомпонентов-например, аутентификацию (скажем, подсистема A), управление счетами (подсистема B), перевод средств (подсистема С) и обмен валюты (подсистема D).


Теперь, хотя это независимые функции аутентификация системы А против перевода средств системы С, мы развертываем его как единое монолитное приложение.


За последние несколько лет мы наблюдаем тенденцию отхода от такого рода архитектуры. Есть несколько причин для этого сдвига.


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



Типовая ошибка в подсистеме А в нашем монолитном приложении


Мы не можем просто исправить его в системе А и обновить его в production.



Исправление типовой ошибки в подсистеме А в нашем монолитном приложении


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



Исправление ошибок в одной подсистеме приводит к передеплою всего монолитного приложения


Этот передеплой не идеален. Вместо этого мы хотели бы сделать передеплой отдельных сервисов.


Одно и то же монолитное приложение поставляется в виде набора отдельных, дискретных сервисов.



Разделение монолитного приложения на отдельные сервисы


Итак, если есть исправление ошибки в одном из наших сервисов:



Типовая ошибка в одном из сервисов, в данном случае сервисе А нашего SOA-приложения


И мы исправляем эту ошибку:



Исправление типовой ошибки в сервисе A нашего SOA-приложения


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



Исправление ошибки приведет к передеплою только сервиса А во всем нашем приложении


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


Но такого понятия, как бесплатный обед, не существует.


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


Обнаружение сервиса в монолитной архитектуре, его проблемы в распределенной системе и решение Consul


Монолитные приложения


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



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


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


Распределенные системы


В распределенном мире сервис A больше не поставляется как то же приложение, что и сервис B. Итак, как сервис A находит сервис B, если он хочет взаимодействовать с B?



Сервис A пытается найти сервис В для установления связи


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


Проблемы в распределенных системах


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



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


Балансировщики нагрузки будут сидеть перед каждым сервисом со статическим IP-адресом, известным всем другим сервисам.



Балансировщик нагрузки между двумя сервисами позволяет осуществлять двусторонний трафик


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



Балансировщики нагрузки позволяют осуществлять связь между несколькими экземплярами одного и того же сервиса


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


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


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



Поддержание записи экземпляров сервисов в балансировщике нагрузки для всего приложения.


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


Решения Consul


Решение Consul для решения проблемы обнаружения сервисов в распределенных системах это центральный реестр сервисов.


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



Реестр сервисов Consul помогает сервису A найти сервис Б и установить связь


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


Consul также обеспечивает проверку работоспособности (health-checks) этих экземпляров сервисов. Если один из экземпляров сервисов или сам сервисов не работает или не проходит проверку работоспособности (health-check), реестр будет знать об этом и будет избегать возврата адреса сервиса. Работа, которую будет выполнять балансировщик нагрузки, в этом случае выполняется реестром.


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


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


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


Это помогает с легкостью масштабировать сервисы.


Управление конфигурацией в монолите, его проблемы в распределенной среде и решение Consul


Монолитные Приложения


Когда мы смотрим на конфигурацию для монолитного приложения, они, как правило, находятся где-то на уровне гигантских файлов YAML, XML или JSON. Предполагается, что эта конфигурация настроит все приложение.



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


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


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


Распределенные системы


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



Копия конфигурации приложения распределяется между различными сервисами


Проблемы в распределенных системах


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


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



Решения Консула


Решение Consul для управления конфигурацией в распределенной среде это центральное хранилище ключей и значений.



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


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


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


Сегментация сети в монолите, ее проблемы в распределенных системах и решения Consul


Монолитные приложения


При рассмотрении классической монолитной архитектуры, сеть обычно делится на три различные зоны.


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


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


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



Различные сетевые зоны в типичном приложении


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


Распределенные системы


Для распределенных сервисов картина кардинально меняется.



Сложная структура сетевого трафика и маршрутов между различными сервисами


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


Проблемы в распределенных системах


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


  • В зависимости от модели доступа, которую мы хотим поддерживать, трафик может поступать с разных конечных точек и достигать разных сервисов.



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




SOA требует контроля над надежными и ненадежными источниками трафика


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

Решения консула


Решение Consul общей проблемы сегментации сети в распределенных системах заключается в реализации сервисных графов и взаимного TLS.



Применение политик уровня обслуживания для описания модели трафика и сегментации с помощью Consul


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


Consul Connect регистрирует эти политики межсервисного взаимодействия, которые мы желаем зарегистрировать, и реализует его в рамках графика обслуживания. Таким образом, политика может сказать, что сервис A может взаимодействовать со сервисом B, но B не может взаимодействовать с C.


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


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


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


Consul применяет TLS с помощью прокси на основе агента, подключенного к каждому экземпляру сервиса. Этот прокси действует как Sidecar. Использование прокси-сервера в этом случае позволяет нам не вносить какие-либо изменения в код исходного сервиса.


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


Базовая архитектура Consul


Consul это распределенная и высокодоступная система.


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


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



Агент Consul отвечает за проверку работоспособности сервисов на узле, как и за проверку работоспособности самого узла. Он не несет ответственности за обнаружение сервисов или поддержание данных ключ/значение.


Серверы Consul это место, где хранятся и реплицируются данные.


Consul может работать с одним сервером, но HashiCorp рекомендует запускать набор из 3-5 серверов, чтобы избежать сбоев. Поскольку все данные хранятся на стороне сервера Consul. С одним сервером, сбой может привести к потере данных.


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


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



Агент Consul сидит на узле и общается с другими агентами в сети, синхронизируя всю информацию об уровне обслуживания


Если запрос является перекрестным центром обработки данных, то запросы пересылаются сервером Consul на удаленные серверы Consul. Результаты с удаленных серверов Consul возвращаются на исходный сервер Consul.


Начало работы с Consul


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


Скачивание и Установка


Как обсуждалось выше, Consul поставляется в виде одного двоичного файла, загруженного с веб-сайта HashiCorps или из раздела релизов Consul на GitHub.


Один бинарный файл может работать как сервер Consul или даже как агент клиента Консула.


Вы можете скачать Consul отсюда Страница загрузки Consul.



Различные варианты загрузки Consul на разных операционных системах


Мы скачаем Consul в командной строке по ссылке со страницы загрузки.


$ wget https://releases.hashicorp.com/consul/1.4.3/consul_1.4.3_linux_amd64.zip -O consul.zip--2019-03-10 00:14:07--  https://releases.hashicorp.com/consul/1.4.3/consul_1.4.3_linux_amd64.zipResolving releases.hashicorp.com (releases.hashicorp.com)... 151.101.37.183, 2a04:4e42:9::439Connecting to releases.hashicorp.com (releases.hashicorp.com)|151.101.37.183|:443... connected.HTTP request sent, awaiting response... 200 OKLength: 34777003 (33M) [application/zip]Saving to: consul.zipconsul.zip             100%[============================>]  33.17M  4.46MB/s    in 9.2s    2019-03-10 00:14:17 (3.60 MB/s) - consul.zip saved [34777003/34777003]

Распакуйте загруженный zip-файл.


$ unzip consul.zipArchive:  consul.zip  inflating: consul

Добавьте его в PATH.


$ export PATH="$PATH:/path/to/consul"

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


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


$ consul agent -dev==> Starting Consul agent...==> Consul agent running!           Version: 'v1.4.2'           Node ID: 'ef46ebb7-3496-346f-f67a-30117cfec0ad'         Node name: 'devcube'        Datacenter: 'dc1' (Segment: '<all>')            Server: true (Bootstrap: false)       Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)      Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)           Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false==> Log data will now stream in as it occurs:    2019/03/04 00:38:01 [DEBUG] agent: Using random ID "ef46ebb7-3496-346f-f67a-30117cfec0ad" as node ID    2019/03/04 00:38:01 [INFO] raft: Initial configuration (index=1): [{Suffrage:Voter ID:ef46ebb7-3496-346f-f67a-30117cfec0ad Address:127.0.0.1:8300}]    2019/03/04 00:38:01 [INFO] raft: Node at 127.0.0.1:8300 [Follower] entering Follower state (Leader: "")    2019/03/04 00:38:01 [INFO] serf: EventMemberJoin: devcube.dc1 127.0.0.1    2019/03/04 00:38:01 [INFO] serf: EventMemberJoin: devcube 127.0.0.1    2019/03/04 00:38:01 [INFO] consul: Adding LAN server devcube (Addr: tcp/127.0.0.1:8300) (DC: dc1)    2019/03/04 00:38:01 [INFO] consul: Handled member-join event for server "devcube.dc1" in area "wan"    2019/03/04 00:38:01 [DEBUG] agent/proxy: managed Connect proxy manager started    2019/03/04 00:38:01 [WARN] raft: Heartbeat timeout from "" reached, starting election    2019/03/04 00:38:01 [INFO] raft: Node at 127.0.0.1:8300 [Candidate] entering Candidate state in term 2    2019/03/04 00:38:01 [DEBUG] raft: Votes needed: 1    2019/03/04 00:38:01 [DEBUG] raft: Vote granted from ef46ebb7-3496-346f-f67a-30117cfec0ad in term 2. Tally: 1    2019/03/04 00:38:01 [INFO] raft: Election won. Tally: 1    2019/03/04 00:38:01 [INFO] raft: Node at 127.0.0.1:8300 [Leader] entering Leader state    2019/03/04 00:38:01 [INFO] consul: cluster leadership acquired    2019/03/04 00:38:01 [INFO] consul: New leader elected: devcube    2019/03/04 00:38:01 [INFO] agent: Started DNS server 127.0.0.1:8600 (tcp)    2019/03/04 00:38:01 [INFO] agent: Started DNS server 127.0.0.1:8600 (udp)    2019/03/04 00:38:01 [INFO] agent: Started HTTP server on 127.0.0.1:8500 (tcp)    2019/03/04 00:38:01 [INFO] agent: Started gRPC server on 127.0.0.1:8502 (tcp)    2019/03/04 00:38:01 [INFO] agent: started state syncer    2019/03/04 00:38:01 [INFO] connect: initialized primary datacenter CA with provider "consul"    2019/03/04 00:38:01 [DEBUG] consul: Skipping self join check for "devcube" since the cluster is too small    2019/03/04 00:38:01 [INFO] consul: member 'devcube' joined, marking health alive    2019/03/04 00:38:01 [DEBUG] agent: Skipping remote check "serfHealth" since it is managed automatically    2019/03/04 00:38:01 [INFO] agent: Synced node info    2019/03/04 00:38:01 [DEBUG] agent: Node info in sync    2019/03/04 00:38:01 [DEBUG] agent: Skipping remote check "serfHealth" since it is managed automatically    2019/03/04 00:38:01 [DEBUG] agent: Node info in sync

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


Участники Consul


Пока выполняется приведенная выше команда, вы можете проверить наличие всех участников в Сети Consul.


$ consul membersNode     Address         Status  Type    Build  Protocol  DC   Segmentdevcube  127.0.0.1:8301  alive   server  1.4.0  2         dc1  <all>

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


Выходные данные приведенной выше команды основаны на протоколе gossip и в конечном итоге согласованы.


Consul HTTP API


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


$ curl localhost:8500/v1/catalog/nodes[    {        "ID": "ef46ebb7-3496-346f-f67a-30117cfec0ad",        "Node": "devcube",        "Address": "127.0.0.1",        "Datacenter": "dc1",        "TaggedAddresses": {            "lan": "127.0.0.1",            "wan": "127.0.0.1"        },        "Meta": {            "consul-network-segment": ""        },        "CreateIndex": 9,        "ModifyIndex": 10    }]

Интерфейс DNS Consul


Consul также предоставляет DNS-интерфейс для запросов узлов. По умолчанию он обслуживает DNS на порту 8600. Этот порт настраивается.


$ dig @127.0.0.1 -p 8600 devcube.node.consul; <<>> DiG 9.11.3-1ubuntu1.5-Ubuntu <<>> @127.0.0.1 -p 8600 devcube.node.consul; (1 server found);; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42215;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;devcube.node.consul.       IN  A;; ANSWER SECTION:devcube.node.consul.    0   IN  A   127.0.0.1;; ADDITIONAL SECTION:devcube.node.consul.    0   IN  TXT "consul-network-segment=";; Query time: 19 msec;; SERVER: 127.0.0.1#8600(127.0.0.1);; WHEN: Mon Mar 04 00:45:44 IST 2019;; MSG SIZE  rcvd: 100

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


Описание (регистрация) сервиса Consul


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


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


$ mkdir ./consul.d

Напишите описание сервиса для фиктивного веб-приложения Django, работающего на порту 80 на локальном хосте.


$ echo '{"service": {"name": "web", "tags": ["django"], "port": 80}}' \    > ./consul.d/web.json

Чтобы наш агент-консул знал об этом описании сервиса, мы можем предоставить ему каталог конфигурации.


$ consul agent -dev -config-dir=./consul.d==> Starting Consul agent...==> Consul agent running!           Version: 'v1.4.2'           Node ID: '810f4804-dbce-03b1-056a-a81269ca90c1'         Node name: 'devcube'        Datacenter: 'dc1' (Segment: '<all>')            Server: true (Bootstrap: false)       Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)      Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)           Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false==> Log data will now stream in as it occurs:    2019/03/04 00:55:28 [DEBUG] agent: Using random ID "810f4804-dbce-03b1-056a-a81269ca90c1" as node ID    2019/03/04 00:55:28 [INFO] raft: Initial configuration (index=1): [{Suffrage:Voter ID:810f4804-dbce-03b1-056a-a81269ca90c1 Address:127.0.0.1:8300}]    2019/03/04 00:55:28 [INFO] raft: Node at 127.0.0.1:8300 [Follower] entering Follower state (Leader: "")    2019/03/04 00:55:28 [INFO] serf: EventMemberJoin: devcube.dc1 127.0.0.1    2019/03/04 00:55:28 [INFO] serf: EventMemberJoin: devcube 127.0.0.1    2019/03/04 00:55:28 [INFO] consul: Adding LAN server devcube (Addr: tcp/127.0.0.1:8300) (DC: dc1)    2019/03/04 00:55:28 [DEBUG] agent/proxy: managed Connect proxy manager started    2019/03/04 00:55:28 [INFO] consul: Handled member-join event for server "devcube.dc1" in area "wan"    2019/03/04 00:55:28 [INFO] agent: Started DNS server 127.0.0.1:8600 (udp)    2019/03/04 00:55:28 [INFO] agent: Started DNS server 127.0.0.1:8600 (tcp)    2019/03/04 00:55:28 [INFO] agent: Started HTTP server on 127.0.0.1:8500 (tcp)    2019/03/04 00:55:28 [INFO] agent: started state syncer    2019/03/04 00:55:28 [INFO] agent: Started gRPC server on 127.0.0.1:8502 (tcp)    2019/03/04 00:55:28 [WARN] raft: Heartbeat timeout from "" reached, starting election    2019/03/04 00:55:28 [INFO] raft: Node at 127.0.0.1:8300 [Candidate] entering Candidate state in term 2    2019/03/04 00:55:28 [DEBUG] raft: Votes needed: 1    2019/03/04 00:55:28 [DEBUG] raft: Vote granted from 810f4804-dbce-03b1-056a-a81269ca90c1 in term 2. Tally: 1    2019/03/04 00:55:28 [INFO] raft: Election won. Tally: 1    2019/03/04 00:55:28 [INFO] raft: Node at 127.0.0.1:8300 [Leader] entering Leader state    2019/03/04 00:55:28 [INFO] consul: cluster leadership acquired    2019/03/04 00:55:28 [INFO] consul: New leader elected: devcube    2019/03/04 00:55:28 [INFO] connect: initialized primary datacenter CA with provider "consul"    2019/03/04 00:55:28 [DEBUG] consul: Skipping self join check for "devcube" since the cluster is too small    2019/03/04 00:55:28 [INFO] consul: member 'devcube' joined, marking health alive    2019/03/04 00:55:28 [DEBUG] agent: Skipping remote check "serfHealth" since it is managed automatically    2019/03/04 00:55:28 [INFO] agent: Synced service "web"    2019/03/04 00:55:28 [DEBUG] agent: Node info in sync    2019/03/04 00:55:29 [DEBUG] agent: Skipping remote check "serfHealth" since it is managed automatically    2019/03/04 00:55:29 [DEBUG] agent: Service "web" in sync    2019/03/04 00:55:29 [DEBUG] agent: Node info in sync

Соответствующая информация в журнале здесь это инструкции синхронизации, относящиеся к сервису web. Агент Consul принял нашу конфигурацию и синхронизировал ее по всем узлам. В данном случае один узел.


Запрос сервиса DNS Consul


Мы можем запросить сервис с помощью DNS, как это было сделано с узлом. Вот так:


$ dig @127.0.0.1 -p 8600 web.service.consul; <<>> DiG 9.11.3-1ubuntu1.5-Ubuntu <<>> @127.0.0.1 -p 8600 web.service.consul; (1 server found);; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51488;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;web.service.consul.        IN  A;; ANSWER SECTION:web.service.consul. 0   IN  A   127.0.0.1;; ADDITIONAL SECTION:web.service.consul. 0   IN  TXT "consul-network-segment=";; Query time: 0 msec;; SERVER: 127.0.0.1#8600(127.0.0.1);; WHEN: Mon Mar 04 00:59:32 IST 2019;; MSG SIZE  rcvd: 99

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


$ dig @127.0.0.1 -p 8600 web.service.consul SRV; <<>> DiG 9.11.3-1ubuntu1.5-Ubuntu <<>> @127.0.0.1 -p 8600 web.service.consul SRV; (1 server found);; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 712;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 3;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;web.service.consul.        IN  SRV;; ANSWER SECTION:web.service.consul. 0   IN  SRV 1 1 80 devcube.node.dc1.consul.;; ADDITIONAL SECTION:devcube.node.dc1.consul. 0  IN  A   127.0.0.1devcube.node.dc1.consul. 0  IN  TXT "consul-network-segment=";; Query time: 0 msec;; SERVER: 127.0.0.1#8600(127.0.0.1);; WHEN: Mon Mar 04 00:59:43 IST 2019;; MSG SIZE  rcvd: 142

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


$ dig @127.0.0.1 -p 8600 django.web.service.consul; <<>> DiG 9.11.3-1ubuntu1.5-Ubuntu <<>> @127.0.0.1 -p 8600 django.web.service.consul; (1 server found);; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12278;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;django.web.service.consul. IN  A;; ANSWER SECTION:django.web.service.consul. 0    IN  A   127.0.0.1;; ADDITIONAL SECTION:django.web.service.consul. 0    IN  TXT "consul-network-segment=";; Query time: 0 msec;; SERVER: 127.0.0.1#8600(127.0.0.1);; WHEN: Mon Mar 04 01:01:17 IST 2019;; MSG SIZE  rcvd: 106

Каталог сервисов Consul через HTTP API


Сервис также может быть запрошен с помощью HTTP API:


$ curl http://localhost:8500/v1/catalog/service/web[    {        "ID": "810f4804-dbce-03b1-056a-a81269ca90c1",        "Node": "devcube",        "Address": "127.0.0.1",        "Datacenter": "dc1",        "TaggedAddresses": {            "lan": "127.0.0.1",            "wan": "127.0.0.1"        },        "NodeMeta": {            "consul-network-segment": ""        },        "ServiceKind": "",        "ServiceID": "web",        "ServiceName": "web",        "ServiceTags": [            "django"        ],        "ServiceAddress": "",        "ServiceWeights": {            "Passing": 1,            "Warning": 1        },        "ServiceMeta": {},        "ServicePort": 80,        "ServiceEnableTagOverride": false,        "ServiceProxyDestination": "",        "ServiceProxy": {},        "ServiceConnect": {},        "CreateIndex": 10,        "ModifyIndex": 10    }]

Мы можем фильтровать сервисы на основе проверок работоспособности по HTTP API:


$ curl http://localhost:8500/v1/catalog/service/web?passing[    {        "ID": "810f4804-dbce-03b1-056a-a81269ca90c1",        "Node": "devcube",        "Address": "127.0.0.1",        "Datacenter": "dc1",        "TaggedAddresses": {            "lan": "127.0.0.1",            "wan": "127.0.0.1"        },        "NodeMeta": {            "consul-network-segment": ""        },        "ServiceKind": "",        "ServiceID": "web",        "ServiceName": "web",        "ServiceTags": [            "django"        ],        "ServiceAddress": "",        "ServiceWeights": {            "Passing": 1,            "Warning": 1        },        "ServiceMeta": {},        "ServicePort": 80,        "ServiceEnableTagOverride": false,        "ServiceProxyDestination": "",        "ServiceProxy": {},        "ServiceConnect": {},        "CreateIndex": 10,        "ModifyIndex": 10    }]

Обновление описания сервиса Consul


Если вы хотите обновить описание сервиса на работающем агенте Consul, это очень просто.


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


$ ps aux | grep [c]onsulpranav   21289  2.4  0.3 177012 54924 pts/2    Sl+  00:55   0:22 consul agent -dev -config-dir=./consul.d

Отправляем SIGHUP на номер 21289


$ kill -SIGHUP 21289

Или Перезагружаем Consul


$ consul reload

Конфигурация перезагрузки срабатывает.


Вы должны увидеть это в своем журнале Consul.


...    2019/03/04 01:10:46 [INFO] agent: Caught signal:  hangup    2019/03/04 01:10:46 [INFO] agent: Reloading configuration...    2019/03/04 01:10:46 [DEBUG] agent: removed service "web"    2019/03/04 01:10:46 [INFO] agent: Synced service "web"    2019/03/04 01:10:46 [DEBUG] agent: Node info in sync...

Веб-интерфейс Consul.


Consul предоставляет красивый веб-пользовательский интерфейс из коробки. Вы можете получить доступ к нему через порт 8500.


В этом случае http://localhost:8500. Давайте посмотрим на некоторые скриншоты.


Домашняя страница для сервисов пользовательского интерфейса Consul со всей соответствующей информацией, связанной с агентом Consul и проверкой веб-сервисов.



Изучение (Exploring) определенных сервисов в веб-интерфейсе Consul


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



Изучение (Exploring) информации на уровне узлов для каждого сервиса в веб-интерфейсе Consul


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



Изучение информации о проверке работоспособности конкретного узла, информации об сервисах и сессиях в веб-интерфейсе Consul.


В целом, Consul Web UI действительно впечатляет и является отличным компаньоном для инструментов командной строки, которые предоставляет Consul.


Чем Consul отличается от Zookeeper, doozerd и etcd?


Consul имеет первоклассную поддержку для обнаружения сервисов, проверки работоспособности (health-check), хранения ключ-значение, нескольких дата-центров.


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


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


Более или менее, все они имеют сходную семантику для управления хранилищем ключей/значений.


Эта семантика привлекательна для построения систем обнаружения сервисов. Consul имеет готовую поддержку для обнаружения сервисов, которой нет в других системах.


Система обнаружения сервисов также требует способа выполнения проверок работоспособности. Так же важно проверить работоспособность сервиса, прежде чем позволить другим обнаружить его. Некоторые системы используют heartbeats с периодическими обновлениями и TTL. Работа по этим health checks растет с масштабом и требует фиксированной инфра-информации. Окно обнаружения сбоев имеет длину не менее длинны TTL.


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


Кроме того, Consul предоставляет встроенную поддержку интерфейсов HTTP или DNS для выполнения общесистемных, узловых или сервисных операций. Другие системы нуждаются в тех, которые разрабатываются вокруг открытых примитивов.


Веб-сайт Consul дает хороший комментарий о сравнении между Consul и другими инструментами.


Инструменты С Открытым Исходным Кодом для HashiCorp Consul


HashiCorp и сообщество построили несколько инструментов вокруг Consul.


Эти инструменты Consul создаются и управляются инженерами HashiCorp:


Consul Template стандартный рендеринг шаблона и уведомления с Consul. Рендеринг шаблонов, уведомитель и супервизор для данных HashiCorp Consul и Vault. Он обеспечивает удобный способ заполнения значений из Consul в файловую систему с помощью демона consul-template.


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


Consul Replicate Демон Consul cross-DC KV репликации. Этот проект предоставляет удобный способ репликации значений из одного центра обработки данных Consul в другой с помощью демона consul-replicate.


Consul Migrate средство переноса данных для обработки обновления Consul в Consul 0.5.1+.


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


Confd управление локальными конфигурационными файлами приложений с помощью шаблонов и данных из etcd или consul.


Fabio Fabio это быстрый, современный маршрутизатор HTTP(S) и TCP с нулевой конфигурацией балансировки для развертывания приложений, управляемых Consul. Зарегистрируйте свои сервисы в consul, проведите проверку работоспособности, и Fabio начнет направлять на них трафик. Никакой конфигурации не требуется.


Registrator Мост реестра сервисов для Docker с подключаемыми адаптерами. Регистратор автоматически регистрирует и отменяет регистрацию сервисов для любого контейнера Docker, проверяя контейнеры по мере их поступления в сеть.


Hashi-UI современный пользовательский интерфейс для HashiCorp Consul & Nomad.


Git2consul отражает содержимое репозитория git в Consul KVs. git2consul берет один или несколько репозиториев git и отражает их в Consul KVs. Цель состоит в том, чтобы организации любого размера использовали git в качестве резервного хранилища, контрольного журнала и механизма контроля доступа для изменений конфигурации, а Consul-в качестве механизма доставки.


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


Crypt храните и извлекайте зашифрованные конфигурации из etcd или consul.


Mesos-Consul Mesos to Consul bridge для открытия сервиса. Mesos-Consul автоматически регистрирует / отменяет регистрацию сервисов, запускаемых как задачи Mesos.


Consul-cli Интерфейс командной строки для Consul HTTP API.


Вывод


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


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


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


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


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


Ссылки


HashiCorp Consul и его РЕПО на GitHub.


HashiCorp Consul Guides and Code


Микросервисы, как объяснил Мартин Фаулер и др.


Статьи в блоге HashiCorp о компании Consul

Подробнее..

Интеграция Росплатформы с grafanaprometheus через consul

18.12.2020 02:10:01 | Автор: admin


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

Былой опыт


Ранее несколько лет назад был 5 летний опыт работы с СУБД Oracle в среде RISC-овой архитектуры на базе IBM, c их очень хорошей юникс подобной ОС AIX c своим прекрасным инструментом smitty, и все это еще разворачивалось на аппаратной виртуализации PowerVM, где можно настраивать балансировку на базе двух VIOS и т.д.



За всем этим набором как-то надо было следить, особенно за БД, и у всех этих программ были свои средства мониторинга, но вдохновлял меня на тот момент самый красивый и имеющий дашборды для всех этих компонентов, инструмент под названием spotlight от компании Quest.


Дашборд Spotlight

Прошло время пришлось работать с другими технологиями, как и многие попал в течение тенденций в сторону открытого ПО, где проприетарный spotlight конечно не очень котируется. Избалованный всякими простыми, платными удобностями, сквозь негативные эмоции, пользовался средствами от разработчиков свободного ПО и иногда ностальгировал по spotlight. Например Zabbix как-то не особо привлекал к себе внимание, но как только услышал про Grafana с Prometheus, само название меня уже заинтересовало, а когда увидел дашборды то, вспомнил про Spotlight. Хотя наверно и в Zabbix можно добиться такого же эффекта или даже использовать его через тот же Grafana, но изначально как я понял без особой персонализации красивых дашбордов там нет, с таким же наборов возможностей, впрочем как и в простом Prometheus.

Соблазнительно-таинственный grafana+prometheus



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



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



На самом деле для Grafana и Prometheus уже есть много разработанных готовых дашбордов и экспортеров метрик от различных систем, что делает его простым и удобным для использования, но когда идет речь о чем-то своеобразном то, необходимо немного заморачиваться и хорошо если разработчики постарались, написали метрики к своим сервисам, а бывает что приходится самому варганить эти метрики. Тогда уже может невольно прийти желание использовать другие средства мониторинга, например как в Росплатформе если недостаточно встроенных предлагается Zabbix, это лучше чем возится с разработкой метрик каждого сервиса под Prometheus.

Мониторинг Росплатформы



В Росплатформе конечно есть еще и свои встроенные средства мониторинга, например в веб UI для SDS vstorage или для гипервизора с виртуальными средами или для таких сервисов на экспорт как s3, iscsi.


Главный дашборд SDS-а(Р-хранилище) Росплатформы


Дашборд одной из нод кластера Росплатформы(в Р-хранилище)


Дашборд Росплатфомы для s3 в Р-хранилище


Мониторинг виртуальной машины Росплатформы(В Р-управлении виртуализации)

Есть даже CLI мониторинг SDS(Р-хранилища) сердце Росплатформы #vstorage c имякластера top

Мониторинг SDS(Р-хранилища) Росплатформы через CLI

Но когда необходим более детальный мониторинг по каждому сервису/службе то, тут уже необходимо что-то другое, а в Росплатформе как в инфраструктурной экосистеме, сервисов немало. И разработчики как оказалось работают в этом направлении и можно даже увидеть результат их деятельности, если в развернутом кластере Росплатформы посмотреть на сервисы SDS через команду #netstat tunap | grep имясервиса, где имя сервиса например cs служба чанк сервера.
И мы можем увидеть вывод:



Где есть адрес 0.0.0.0 и порт 37548 который можно прослушать через команду
#curl localhost: 37548/metrics




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



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



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


Веб ui от Prometheus


Дашборд Grafana

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

Service Discovery



Изначально мне показалось, что всего этого будет достаточно чтобы замутить свой мониторинг на базе этих прекрасных инструментов, но не тут-то было. Дело в том, что например для микросервисов SDS-а нет готовых экспортеров, для каждой его службы, да и вряд ли появятся, так как сервис работающий для одного диска может появляться и исчезать, если этот диск например заменить или добавить новые диски, или сервисы s3/iscsi при масштабировании могут плодится и т.д. И что получается каждый новый сервис прописывать в экспортере или в конфиге Prometheus, где для каждого свой уникальный порт?

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



Насмотревшись про него видео и изучив его возможности оказалось, что в нем можно просто зарегистрировать/ отрегистрировать сервисы с их портами для последующей передачи Prometheus, но сам он конечно ничего не ищет, как это описывают на первый взгляд в многих статьях и документации этого инструмента. То есть искать он может разными способами (DNS, HTTP API, RPC) уже у себя внутри среди зарегистрированных в нем сервисах.

В результате можно вернутся к нашей команде #netstat, и выполнять эту команду через Ansible или написать скрипт под планировщик задач с помощью которого будут сканироваться наши сервисы netstat-ом. Далее каждый найденный сервис наш скрипт будет регистрировать в Сonsul командой
#curl --request PUT --data @services.json localhost:8500/v1/agent/service/register

Где файл services.json это описание сервиса в этом формате:
 {  "services":[{  "name":"cs",  "tags":["csid=1026"],  "address":"127.0.0.1",  "port":33074},{  "name":"mds",  "address":"127.0.0.1",  "tags":["mdsid=2"],  "port": 9100}]}

В данном примере описываются два сервиса это чанк сервер cs и служба метаданных SDS Росплатформы mds.
Отрегистрировать также можно устроить с помощью одного и того же скрипта, который будет проверять доступность метрик от этого сервиса по его порту и в случае пустого ответа выкидывать этот сервис из Consul по команде:
#curl --request PUT http://127.0.0.1:8500/v1/agent/service/deregister/my-service-id


Есть конечно еще путь эмулировать API Consul, чтобы Prometheus думал, что он обращается к Consul, а на самом деле к ngnix, где ему подкладывал бы в формате json список сервисов этот же скрипт. Но это уже опять другая история, близкая к разработке. Можно оставить сам консул, который идет в виде отдельно выполняемого файла, в связи с чем его можно расположить на SDS для отказоустойчивости вместо его кластерной настройки, которую также можно осуществить, но это усложняет инструкцию и выходит за рамки этого описания.

Далее после того как у нас запущен Consul с необходимыми зарегистрированными сервисами, надо установить и настроить Prometheus. Можно это сделать в виртуальной среде, а на каждой ноде только его экспортер. Например в Росплатформе он уже предустановлен в контейнере vstorage-ui управления SDS-ом(Р-хранилище), остается только установить экспортеры на ноды и прописать их в конфиге Prometheus.

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

Если пройти в раздел explore то, можно проверить нашу работу, нажав на кнопку метрики, где у вас появится меню/список с разделами метрик.



Установка настройка Consul





В выше описанной краткой инструкции я опустил настройку конфигурационного файла Prometheus,
но для начала установим и запустим сам Consul на одной из нод кластера Росплатформы(Р-виртуализации):
Можно скачать его следующей командой
#wget  https://releases.hashicorp.com/consul/1.9.1/сonsul_1.9.1_linux_amd64.zip

Распаковываем его
# unzip сonsul_1.9.1_linux_amd64.zip

B сразу можно запустить проверить
#./consul v

Для начала чтобы не заморачиваться со автоскриптом по поиску и регистрации сервисов служб SDS-а Росплатформы в Consul, описанным выше, попробуем просто создать папку с прописанными службами в файле json.
#mkdir consul.d

И внутри этой папки создадим файл
#vi services.json

Со следующим содержимом
{  "services":[{  "name":"cs",  "tags":["csid=1026"],  "address":"127.0.0.1",  "port":33074},{  "name":"mds",  "address":"127.0.0.1",  "tags":["mdsid=2"],  "port": 9100}]}

Где 1026 это id службы чанк сервера, которую можно увидеть по команде
#vstorage c имя_вашего_кластера list-services



По ней также можно увидеть mdsid

Порты можно посмотреть через #netstat tunap | grep cs или mds в строке с адресом 0.0.0.0 с протоколом tcp.
После этого можно проверить запустить наш Consul
#consul agent -dev -enable-script-checks -config-dir=./consul.d

На экран будут выводится сообщения, можно это окно закрыть consul продолжит работать в фоновом режиме, для его перезагрузки можно воспользоваться командой
#consul reload

Можно проверить работу Consul через команду
#curl localhost:8500/v1/catalog/services

Он должен вывести наши зарегистрированные сервисы



И можно еще проверить каждый сервис:


Установка настройка Prometheus





Теперь можно установить Prometheus прям на ноду чтобы пока не возится с Prometheus в vstorage-ui
#wget https://github.com/prometheus/prometheus/releases/download/v2.23.0/prometheus-2.23.0.linux-amd64.tar.gz#mkdir /etc/Prometheus#mkdir /var/lib/Prometheus#tar zxvf prometheus-2.23.0.linux-amd64.tar.gz#cd prometheus-*.linux-amd64#cp prometheus promtool /usr/local/bin/#cp -r console_libraries consoles prometheus.yml /etc/Prometheus#useradd --no-create-home --shell /bin/false Prometheus#chown -R prometheus:prometheus /etc/prometheus /var/lib/Prometheus#chown prometheus:prometheus /usr/local/bin/{prometheus,promtool}

Как запустить и прописать в автозапуск в виде сервиса смотрим здесь
Редактируем наш конфиг файл Prometheus:
#vi /etc/systemd/system/prometheus.service

global:  scrape_interval:     1m  evaluation_interval: 1malerting:  alertmanagers:  - static_configs:    - targets:      - localhost:9093rule_files:- /var/lib/prometheus/rules/*.rules- /var/lib/prometheus/alerts/*.rules  - job_name: consul    honor_labels: true    consul_sd_configs:    - server: '127.0.0.1:8500'  #адрес и порт Consul       datacenter: 'dc1'   # к какому датацентру Consul относится - опционально      scheme: http  # по какому протоколу/схеме взаимодействие    relabel_configs:    - source_labels: [__address__]      regex: (.*)[:].+      target_label: instance      replacement: '${1}'    - source_labels: [__meta_consul_service]      target_label: 'job'    - source_labels: [__meta_consul_node]      target_label: 'node'    - source_labels: [__meta_consul_tags]      regex: ',(?:[^,]+,){0}([^=]+)=([^,]+),.*'      target_label: '${1}'      replacement: '${2}' 

Здесь
Нам в помощь дока про конфиг, а в самом примере здесь некоторые строки с комментарием.
Теперь можно запустить Prometheus проверить его работоспособность
#systemctl start prometheus.service#systemctl status prometheus.service

Пройти через браузер по адресу адрес_ноды_где_установлен_Prometheus:9090


И потом пройти в меню status -> targets



И провалится например по ссылке 127.0.0.1:33074 /metrics где мы увидим наши метрики от службы чанк сервера


К каждой строке есть комментарий

Установка настройка Grafana





Далее устанавливаем grafana
Я установил у себя на ноутбуке на windows 10 и зашел через браузер по адресу localhost:3000
Далее подключился к серверу к ноде с установленным Prometheus


Теперь проходим в меню manage и создаем наш новый дашборд.


Выбираем добавить новую панель

Можно ее назвать например memory use, для того чтобы попробовать отобразить использование памяти сервера нашей выше описанной службы чанк сервер.
На вкладе query выбрать из выпадающего списка datasource Prometheus, который мы ранее настроили на наш сервер(Р-виртуализации) Росплатформы с прослушивающим портом 9090.
Далее в поле metrics мы должны вставить метрику, ее можно подобрать из списка всех метрик по описанию после слова HELP.



Находим process_swap_bytes использование swap в байтах. Еще можно взять process_resident_memory_bytes из комментария видно, что это использование памяти сервера.
И дополнительно взять process_swapin_delay_seconds задержка при передачи памяти swap в резидентную память.
В Grafana в дашборде можно создать переменную:



После этого редактируем панель


  • 1. Название панели memory use.
  • 2. Выбираем data sources в нашем случае это Prometheus.
  • 3. Добавляем описание например общий объем памяти и памяти подкачки, занятой CS, а также процент времени, затраченного на ожидание передачи памяти swap в резидентную память.
  • 4. Пишем первый запрос с именем метрики process_swap_bytes{job=cs,csid=$cs}, где указываем службу cs и переменную его id.
  • 5. Имя определения.
  • 6. Разрешение.




Добавляем еще query и прописываем туда аналогично как мы прописывали для swap,
Только в поле напротив metrics где B будет process_resident_memory_bytes{job=cs,csid="$cs"}, а в С будет instance:process_swapin_delay_seconds:rate5m{job=cs,csid="$cs"}


Здесь настраиваем цвет и шкалу графика


В результате должен получится вот такой график



На этом пока все, надеюсь это как-то поможет тем, кто интересуется настройкой своего мониторинга на базе Grafana и Prometheus плюс Consul для Росплатформы или других похожих систем.



Полезные ссылки:



Подробнее..

Run, config, run как мы ускорили деплой конфигов в Badoo

25.02.2021 18:11:56 | Автор: admin

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

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

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

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


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

Случай из жизни

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

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

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

Для отключения сервисов мы используем свою систему с говорящим названием Выключалка хостов (disable hosts). Принцип её работы довольно прост:

  • выбираем в веб-интерфейсе сервисы, которые нужно отключить (или, наоборот, включить);

  • нажимаем на кнопку Deploy;

  • изменения сохраняются в базе данных и затем доставляются на все машины, на которых выполняется PHP-код.

В коде при подключении к сервису стоит проверка вида:

if (\DownChecker\Host::isDisabled($host)) {   $this->errcode = self::ERROR_CONNECT_FAILED;   return false;}

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

Процесс деплоя разбит на несколько шагов:

  • упаковываем конфиги в tar-архив;

  • копируем архив на сервер через rsync или scp;

  • распаковываем архив в отдельную директорию;

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

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

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

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

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

В поисках альтернативного транспорта

Тут может возникнуть резонный вопрос: зачем изобретать велосипед, если можно использовать классическую схему с базой данных (БД) и кешированием?

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

  • использование БД и кеша это дополнительная завязка на внешний сервис, а значит, ещё одна потенциальная точка отказа;

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

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

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

Но в этой схеме нам не понравилась идея с запросами в цикле. У нас около 2000 серверов, на которых может выполняться PHP-код. Если мы будем делать запрос в базу/кеш хотя бы один раз в секунду, то это будет создавать довольно большой фон запросов (2k rps), а сами данные при этом обновляются не так часто. На этот случай есть решение событийная модель, например шаблон проектирования Publisher-Subscriber (PubSub). Из популярных решений можно было использовать Redis, но у нас он не прижился (для кеширования мы используем Memcache, а для очередей у нас есть своя отдельная система).

Зато прижился Consul, у которого есть механизм отслеживания изменений (watches) на базе блокирующих запросов. Это в целом похоже на PubSub и вписывается в нашу схему с обновлением конфига по событию. Мы решили сделать прототип нового транспорта на базе Consul, который со временем эволюционировал в отдельную систему под названием AutoConfig.

Как работает AutoConfig

Общая схема работы выглядит следующим образом:

  • разработчик вызывает специальный метод, который обновляет значение ключа в базе данных и добавляет ключ в очередь на деплой;

  • в облаке работает скрипт, который исключает пачку ключей из очереди и записывает их в Consul; помимо самих ключей, в Consul хранится специальная индексная карта со списком всех ключей (о ней я расскажу чуть позже);

  • на каждом сервере запущен Consul watch, который отслеживает изменения индексной карты и вызывает специальный скрипт-обработчик, когда она обновляется;

  • обработчик записывает изменения в файл.

Со стороны кода работа с системой выглядит довольно просто:

Обновление ключа

$record = \AutoConfig\AutoConfigRecord::initByKeyData('myKey', 'Hello, Habr!', 'Eugene Tupikov');$storage = new \AutoConfig\AutoConfigStorage();$storage->deployRecord($record);

Чтение ключа

$reader = new \AutoConfig\AutoConfigReader();$config = $reader->getFromCurrentSpace('myKey');

Удаление ключа

$storage = new \AutoConfig\AutoConfigStorage();$storage->removeKey('example');

Подробнее про Consul watch

Consul watch реализован с использованием блокирующих запросов в HTTP API, работу которых лучше продемонстрировать на примере отслеживания изменений ключа.

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

curl -X PUT --data 'hello, harb!' http://127.0.0.1:8500/v1/kv/habr-key

Затем отправляем запрос на чтение нашего ключа

curl -v http://127.0.0.1:8500/v1/kv/habr-key

API обрабатывает запрос и возвращает ответ, содержащий HTTP-заголовок X-Consul-Index с уникальным идентификатором, который соответствует текущему состоянию нашего ключа.

......< X-Consul-Index: 266834870< X-Consul-Knownleader: true......<[  {    "LockIndex": 0,    "Key": "habr-key",    "Flags": 0,    "Value": "dXBkYXRlZCAy",    "CreateIndex": 266833109,    "ModifyIndex": 266834870  }]

Мы отправляем новый запрос на чтение и дополнительно передаем значение из заголовка X-Consul-Index в параметре запроса index

curl http://127.0.0.1:8500/v1/kv/habr-key?index=266834870Ждем изменений ключа...

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

Затем открываем новую вкладку терминала и отправляем запрос на обновление ключа

curl -X PUT --data 'updated value' http://127.0.0.1:8500/v1/kv/habr-key

Возвращаемся на первую вкладку и видим, что запрос на чтение вернул обновленное значение (изменились ключи Value и ModifyIndex):

[  {    "LockIndex": 0,    "Key": "habr-key",    "Flags": 0,    "Value": "dXBkYXRlZA==",    "CreateIndex": 266833109,    "ModifyIndex": 266835734  }]

При вызове команды

consul watch -type=key -key=habr_key <handler>

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

Зачем нужна индексная карта

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

consul watch -type=keyprefix -prefix=auto_config/ <handler>

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

По этому поводу на GitHub уже довольно давно открыт Issue и, судя по комментариям, лёд тронулся. Разработчики Consul начали работу над улучшением подсистемы блокирующих запросов, что должно решить описанную выше проблему.

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

Она имеет следующий формат:

return [    'value' => [        'version' => 437036,        'keys' => [            'my/awesome/key' => '80003ff43027c2cc5862385fdf608a45',            ...            ...        ],        'created_at' => 1612687434    ]]

В случае если карта обновилась, обработчик:

  • считывает текущее состояние карты с диска;

  • находит изменившиеся ключи (для этого и нужен хеш значения);

  • вычитывает через HTTP API актуальные значения изменившихся ключей и обновляет нужные файлы на диске;

  • сохраняет новую индексную карту на диск.

И ещё немного про Consul

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

Ограничение размера значения ключа (и не только)

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

Для атомарной записи изменённых ключей и индексной карты мы используем механизм транзакций. Аналогичное ограничение в 512 Кб установлено и на размер одной транзакции. А, помимо него, есть ограничение на количество операций в рамках одной транзакции 64.

Чтобы обойти эти ограничения, мы сделали следующее:

  • разбили индексную карту на несколько частей (по 1000 ключей в каждой) и обновляем только части, содержащие изменённые ключи;

  • ограничили максимальный размер одного ключа AutoConfig 450 Кб, чтобы оставить место для шардов индексной карты (значение выбрано опытным путём);

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

    • сначала вычитывает N ключей из очереди и проверяет их суммарный размер;

    • если размер не превышает заданный предел, то деплоит все ключи разом, а в противном случае деплоит ключи по одному.

Отсутствие встроенной репликации

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

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

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

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

Если какой то сервер временно недоступен, система автоматически восстанавливает актуальное состояние конфига, как только он приходит в норму.

За последние пару лет система стала популярна у наших разработчиков и сегодня фактически является стандартом при работе с конфигами, для которых не требуется атомарная раскладка. Например, через AutoConfig у нас деплоятся параметры A/B-тестов, настройки промокампаний, на его базе реализован функционал Service Discovery и многое другое.

Общее количество ключей на данный момент порядка 16 000, а их суммарный размер примерно 120 Мб.

Спасибо за внимание!

Расскажите в комментариях, как вы деплоите конфиги в своих проектах.

Подробнее..

Перевод Практическое руководство по HashiCorp Consul Часть 2

08.01.2021 12:15:36 | Автор: admin


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


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


Что мы строим?


Мы собираемся создать веб-приложение Django, которое хранит свои постоянные данные в MongoDB. Мы поместим их в контейнер с помощью Docker. Скомпилируйте и запустите их с помощью Docker Compose.


Чтобы показать, как наше веб-приложение будет масштабироваться в этом контексте, мы собираемся запустить два экземпляра приложения Django. Кроме того, чтобы сделать это еще более интересным, мы запустим MongoDB как набор реплик с одним первичным узлом и двумя вторичными узлами.


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


Этот пример примерно поможет нам смоделировать реальное практическое приложение.



Примеры узлов приложений и развернутых на них служб


Полный исходный код этого приложения является открытым и доступен на GitHub pranavcode/consul-demo.


Примечание. Обсуждаемая здесь архитектура не накладывает особых ограничений на какие-либо технологии, используемые для создания уровней приложений или данных. Этот пример вполне может быть построен с использованием комбинации Ruby on Rails и Postgres, или Node.js и MongoDB, или Laravel и MySQL.


Какое место занимает Консул?


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


Таким образом, мы будем использовать Consul для Service Discovery. Это позволит серверам Django найти первичный узел MongoDB. В этом примере мы собираемся использовать Consul для разрешения служб через интерфейс Consul DNS.


Consul также поможет нам с автоматической настройкой Fabio в качестве балансировщика нагрузки для доступа к экземплярам нашего приложения Django.


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


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


Давайте начнем.


Настройка: MongoDB, Django, Consul, Fabio и Dockerization


Мы сделаем это настолько быстро и просто, насколько это возможно, чтобы продемонстрировать вам все возможности.


MongoDB


Мы нацелены на настройку MongoDB в форме набора реплик MongoDB. Один первичный узел и два вторичных узла.


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


Мы будем называть наш набор репликации consuldemo.


Мы запустим MongoDB на стандартном порту 27017 и укажем имя реплики, установленной в командной строке, с помощью параметра --replSet.


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


replication:    replSetName: "consuldemo"

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


var config = {    _id: "consuldemo",    version: 1,    members: [{        _id: 0,        host: "mongo_1:27017",    }, {        _id: 1,        host: "mongo_2:27017",    }, {        _id: 2,        host: "mongo_3:27017",    }],    settings: {         chainingAllowed: true     }};rs.initiate(config, { force: true });rs.slaveOk();db.getMongo().setReadPref("nearest");

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


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


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


Мы запустим MongoDB на всех узлах с помощью следующей команды:


mongod --bind_ip_all --port 27017 --dbpath /data/db --replSet "consuldemo"

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


Мы обсудим контейнеризацию службы MongoDB в последней части этой статьи.


Django


Мы создадим простой проект Django, представляющий приложение Blog, и контейнер его с помощью Docker.


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


Поскольку нам нужно, чтобы наше приложение Django взаимодействовало с MongoDB, мы будем использовать коннектор MongoDB для Django ORM, Djongo. Мы настроим наши настройки Django для использования Djongo и подключения к нашей MongoDB. Djongo довольно прост в настройке.


Для локальной установки MongoDB потребуется всего две строки кода:


...DATABASES = {    'default': {        'ENGINE': 'djongo',        'NAME': 'db',    }}...

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


...DATABASES = {    'default': {        'ENGINE': 'djongo',        'NAME': 'db',        'HOST': 'mongodb://mongo-primary.service.consul',        'PORT': 27017,    }}...@velotiotech

Детали:


ENGINE: Коннектор базы данных для использования в Django ORM.


NAME: Имя базы данных.


HOST: адрес хоста, на котором работает MongoDB.


PORT: какой порт MongoDB прослушивает запросы.


Djongo внутренне общается с PyMongo и использует MongoClient для выполнения запросов в Mongo. Мы также можем использовать другие коннекторы MongoDB, доступные для Django, чтобы достичь этого, например, django-mongodb-engine или pymongo напрямую, в зависимости от наших потребностей.


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


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


from djongo import modelsclass Blog(models.Model):    name = models.CharField(max_length=100)    tagline = models.TextField()    class Meta:        abstract = Trueclass Entry(models.Model):    blog = models.EmbeddedModelField(        model_container=Blog,    )    headline = models.CharField(max_length=255)

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


from django.contrib import adminfrom.models import Entryadmin.site.register(Entry)

В этом примере мы можем поиграть с CRUD-операциями модели Entry через Django Admin.


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


Наши настройки Django выглядят так:


from django.shortcuts import renderfrom pymongo import MongoClientdef home(request):    client = MongoClient("mongo-primary.service.consul")    replica_set = client.admin.command('ismaster')    return render(request, 'home.html', {         'mongo_hosts': replica_set['hosts'],        'mongo_primary_host': replica_set['primary'],        'mongo_connected_host': replica_set['me'],        'mongo_is_primary': replica_set['ismaster'],        'mongo_is_secondary': replica_set['secondary'],    })

Наша конфигурация URL-адресов или маршрутов для приложения выглядит так:


from django.urls import pathfrom tweetapp import viewsurlpatterns = [    path('', views.home, name='home'),]

А для проекта URL-адреса приложений включены так:


from django.contrib import adminfrom django.urls import path, includefrom django.conf import settingsfrom django.conf.urls.static import staticurlpatterns = [    path('admin/', admin.site.urls),    path('web', include('tweetapp.urls')),] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Наш шаблон Django, templates/home.html, выглядит так:


<!doctype html><html lang="en"><head>    <meta charset="utf-8">    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">    <link rel="stylesheet" href="http://personeltest.ru/aways/stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">    <link href="http://personeltest.ru/aways/fonts.googleapis.com/css?family=Armata" rel="stylesheet">    <title>Django-Mongo-Consul</title></head><body class="bg-dark text-white p-5" style="font-family: Armata">    <div class="p-4 border">        <div class="m-2">            <b>Django Database Connection</b>        </div>        <table class="table table-dark">            <thead>                <tr>                    <th scope="col">#</th>                    <th scope="col">Property</th>                    <th scope="col">Value</th>                </tr>            </thead>            <tbody>                <tr>                    <td>1</td>                    <td>Mongo Hosts</td>                    <td>{% for host in mongo_hosts %}{{ host }}<br/>{% endfor %}</td>                </tr>                <tr>                    <td>2</td>                    <td>Mongo Primary Address</td>                    <td>{{ mongo_primary_host }}</td>                </tr>                <tr>                    <td>3</td>                    <td>Mongo Connected Address</td>                    <td>{{ mongo_connected_host }}</td>                </tr>                <tr>                    <td>4</td>                    <td>Mongo - Is Primary?</td>                    <td>{{ mongo_is_primary }}</td>                </tr>                <tr>                    <td>5</td>                    <td>Mongo - Is Secondary?</td>                    <td>{{ mongo_is_secondary }}</td>                </tr>            </tbody>        </table>    </div>    <script src="http://personeltest.ru/aways/code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>    <script src="http://personeltest.ru/aways/cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>    <script src="http://personeltest.ru/aways/stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script></body></html>

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


python ./manage.py migrate

А также собрать все статические активы в статический каталог:


python ./manage.py collectstatic --noinput

Теперь запустите приложение Django с Gunicorn, HTTP-сервером WSGI, как показано ниже:


gunicorn --bind 0.0.0.0:8000 --access-logfile - tweeter.wsgi:application

Это дает нам базовое приложение Django, подобное блогу, которое подключается к бэкэнду MongoDB.


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


Consul


Мы размещаем агент Consul для каждой службы в рамках нашей установки Consul.


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


Consul на узлах, на которых работает MongoDB Replica Set


Сначала мы обсудим настройку Consul в контексте MongoDB Replica Set, поскольку она решает интересную проблему. В любой момент времени один из экземпляров MongoDB может быть первичным или вторичным.


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


Мы достигаем этого динамизма путем написания и запуска сценария оболочки после интервала, который переключает определение службы Consul для MongoDB Primary и MongoDB Secondary на Consul Agent узла экземпляра.


Определения сервисов для сервисов MongoDB хранятся в виде файлов JSON в каталоге конфигурации Consul /etc/config.d.


Определение службы для первичного экземпляра MongoDB:


{    "service": {        "name": "mongo-primary",        "port": 27017,        "tags": [            "nosql",            "database"        ],        "check": {            "id": "mongo_primary_status",            "name": "Mongo Primary Status",            "args": ["/etc/consul.d/check_scripts/mongo_primary_check.sh"],            "interval": "30s",            "timeout": "20s"        }    }}

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


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


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


{    "service": {        "name": "mongo-secondary",        "port": 27017,        "tags": [            "nosql",            "database"        ],        "check": {            "id": "mongo_secondary_status",            "name": "Mongo Secondary Status",            "args": ["/etc/consul.d/check_scripts/mongo_secondary_check.sh"],            "interval": "30s",            "timeout": "20s"        }    }}

Учитывая весь этот контекст, можете ли вы представить, как мы можем динамически переключать эти определения сервисов?


Мы можем определить, является ли данный экземпляр MongoDB основным или нет, запустив команду db.isMaster() в MongoDB shell.


Можно оформить проверку в виде скрипта оболочки следующим образом:


#!/bin/bashmongo_primary=$(mongo --quiet --eval 'JSON.stringify(db.isMaster())' | jq -r .ismaster 2> /dev/null)if [[ $mongo_primary == false ]]; then    exit 1fiecho "Mongo primary healthy and reachable"

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


#!/bin/bashmongo_secondary=$(mongo --quiet --eval 'JSON.stringify(db.isMaster())' | jq -r .secondary 2> /dev/null)if [[ $mongo_secondary == false ]]; then    exit 1fiecho "Mongo secondary healthy and reachable"

Примечание. Мы используем jq легкий и гибкий процессор JSON командной строки для обработки выходных данных команд оболочки MongoDB в кодировке JSON.


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


#!/bin/bash# Wait until Mongo startswhile [[ $(ps aux | grep [m]ongod | wc -l) -ne 1 ]]; do    sleep 5doneREGISTER_MASTER=0REGISTER_SECONDARY=0mongo_primary=$(mongo --quiet --eval 'JSON.stringify(db.isMaster())' | jq -r .ismaster 2> /dev/null)mongo_secondary=$(mongo --quiet --eval 'JSON.stringify(db.isMaster())' | jq -r .secondary 2> /dev/null)  if [[ $mongo_primary == false && $mongo_secondary == true ]]; then  # Deregister as Mongo Master  if [[ -a /etc/consul.d/check_scripts/mongo_primary_check.sh && -a /etc/consul.d/mongo_primary.json ]]; then    rm -f /etc/consul.d/check_scripts/mongo_primary_check.sh    rm -f /etc/consul.d/mongo_primary.json    REGISTER_MASTER=1  fi  # Register as Mongo Secondary  if [[ ! -a /etc/consul.d/check_scripts/mongo_secondary_check.sh && ! -a /etc/consul.d/mongo_secondary.json ]]; then    cp -u /opt/checks/check_scripts/mongo_secondary_check.sh /etc/consul.d/check_scripts/    cp -u /opt/checks/mongo_secondary.json /etc/consul.d/    REGISTER_SECONDARY=1  fielse  # Register as Mongo Master  if [[ ! -a /etc/consul.d/check_scripts/mongo_primary_check.sh && ! -a /etc/consul.d/mongo_primary.json ]]; then    cp -u /opt/checks/check_scripts/mongo_primary_check.sh /etc/consul.d/check_scripts/    cp -u /opt/checks/mongo_primary.json /etc/consul.d/    REGISTER_MASTER=2  fi  # Deregister as Mongo Secondary  if [[ -a /etc/consul.d/check_scripts/mongo_secondary_check.sh && -a /etc/consul.d/mongo_secondary.json ]]; then    rm -f /etc/consul.d/check_scripts/mongo_secondary_check.sh    rm -f /etc/consul.d/mongo_secondary.json    REGISTER_SECONDARY=2  fifiif [[ $REGISTER_MASTER -ne 0 && $REGISTER_SECONDARY -ne 0 ]]; then  consul reloadfi

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


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


consul agent -bind 33.10.0.3 \    -advertise 33.10.0.3 \    -join consul_server \    -node mongo_1 \    -dns-port 53 \    -data-dir /data \    -config-dir /etc/consul.d \    -enable-local-script-checks

Здесь consul_server представляет хост, на котором работает Consul Server. Точно так же мы можем запускать такие агенты на каждом из других узлов экземпляра MongoDB.


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


Consul на узлах, на которых запущено приложение Django


Для приложения Django настройка Consul будет очень простой. Нам нужно только отслеживать порт приложения Django, на котором Gunicorn прослушивает запросы.


Определение службы Consul будет выглядеть так:


{    "service": {        "name": "web",        "port": 8000,        "tags": [            "web",            "application",            "urlprefix-/web"        ],        "check": {            "id": "web_app_status",            "name": "Web Application Status",            "tcp": "localhost:8000",            "interval": "30s",            "timeout": "20s"        }    }}

Когда у нас есть определение службы Consul для приложения Django, мы можем запустить агента Consul, сидящего на узле, в котором приложение Django работает как служба. Чтобы запустить агента Consul, мы должны запустить следующую команду:


consul agent -bind 33.10.0.10 \    -advertise 33.10.0.10 \    -join consul_server \    -node web_1 \    -dns-port 53 \    -data-dir /data \    -config-dir /etc/consul.d \    -enable-local-script-checks

Consul Сервер


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


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


consul agent -server \    -bind 33.10.0.2 \    -advertise 33.10.0.2 \    -node consul_server \    -client 0.0.0.0 \    -dns-port 53 \    -data-dir /data \    -ui -bootstrap

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


Fabio


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


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


Чтобы позволить Fabio автоматически определять службы через Consul, одним из способов является добавление тега или обновление тега в определении сервиса с помощью префикса и идентификатора службы urlprefix-/<service>. Определение службы нашего Consul для приложения Django теперь будет выглядеть так:


{    "service": {        "name": "web",        "port": 8000,        "tags": [            "web",            "application",            "urlprefix-/web"        ],        "check": {            "id": "web_app_status",            "name": "Web Application Status",            "tcp": "localhost:8000",            "interval": "30s",            "timeout": "20s"        }    }}

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


Докеризация


Все наше приложение будет развернуто как набор контейнеров Docker. Давайте поговорим о том, как мы этого достигаем в контексте Consul.


Докеризация набора реплик MongoDB вместе с агентом Consul


Нам нужно запустить агент Consul, как описано выше, вместе с MongoDB в том же контейнере Docker, поэтому нам нужно будет запустить настраиваемый ENTRYPOINT в контейнере, чтобы разрешить запуск двух процессов.


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


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


Чтобы быть точным, мы будем использовать Golang, заимствованный у Foreman, Goreman. Он принимает конфигурацию в форме Procfile Heroku, чтобы понимать, какие процессы должны оставаться активными на хосте.


В нашем случае Procfile выглядит так:


# Mongomongo: /opt/mongo.sh# Consul Client Agentconsul: /opt/consul.sh# Consul Client Health Checksconsul_check: while true; do /opt/checks_toggler.sh && sleep 10; done

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


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


Наш Dockerfile с некоторыми дополнительными инструментами для отладки и диагностики будет выглядеть так:


FROM ubuntu:18.04RUN apt-get update && \    apt-get install -y \    bash curl nano net-tools zip unzip \    jq dnsutils iputils-ping# Install MongoDBRUN apt-get install -y mongodbRUN mkdir -p /data/dbVOLUME data:/data/db# Setup Consul and GoremanADD https://releases.hashicorp.com/consul/1.4.4/consul_1.4.4_linux_amd64.zip /tmp/consul.zipRUN cd /bin && unzip /tmp/consul.zip && chmod +x /bin/consul && rm /tmp/consul.zipADD https://github.com/mattn/goreman/releases/download/v0.0.10/goreman_linux_amd64.zip /tmp/goreman.zipRUN cd /bin && unzip /tmp/goreman.zip && chmod +x /bin/goreman && rm /tmp/goreman.zipRUN mkdir -p /etc/consul.d/check_scriptsADD ./config/mongod /etcRUN mkdir -p /etc/checksADD ./config/checks /opt/checksADD checks_toggler.sh /optADD mongo.sh /optADD consul.sh /optADD Procfile /root/ProcfileEXPOSE 27017# Launch both MongoDB server and ConsulENTRYPOINT [ "goreman" ]CMD [ "-f", "/root/Procfile", "start" ]

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


Докеризация веб-приложения Django вместе с Consul Agent


Нам также необходимо запустить агент Consul вместе с нашим приложением Django в том же контейнере Docker, что и у нас с контейнером MongoDB.


# Djangodjango: /web/tweeter.sh# Consul Client Agentconsul: /opt/consul.sh

Точно так же у нас будет Dockerfile для веб-приложения Django, как и для наших контейнеров MongoDB.


FROM python:3.7RUN apt-get update && \    apt-get install -y \    bash curl nano net-tools zip unzip \    jq dnsutils iputils-ping# Python Environment SetupENV PYTHONDONTWRITEBYTECODE 1ENV PYTHONUNBUFFERED 1# Setup Consul and GoremanRUN mkdir -p /data/db /etc/consul.dADD https://releases.hashicorp.com/consul/1.4.4/consul_1.4.4_linux_amd64.zip /tmp/consul.zipRUN cd /bin && unzip /tmp/consul.zip && chmod +x /bin/consul && rm /tmp/consul.zipADD https://github.com/mattn/goreman/releases/download/v0.0.10/goreman_linux_amd64.zip /tmp/goreman.zipRUN cd /bin && unzip /tmp/goreman.zip && chmod +x /bin/goreman && rm /tmp/goreman.zipADD ./consul /etc/consul.dADD Procfile /root/Procfile# Install pipenvRUN pip3 install --upgrade pipRUN pip3 install pipenv# Setting workdirADD consul.sh /optADD . /webWORKDIR /web/tweeter# Exposing appropriate portsEXPOSE 8000/tcp# Install dependenciesRUN pipenv install --system --deploy --ignore-pipfile# Migrates the database, uploads staticfiles, run API server and background tasksENTRYPOINT [ "goreman" ]CMD [ "-f", "/root/Procfile", "start" ]

Докеризация Consul Server


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


Кроме того, для демонстрации мы используем образ Ubuntu 18.04. Для этого вы можете использовать официальный образ Consul, которое принимает все пользовательские параметры, указанные здесь.


FROM ubuntu:18.04RUN apt-get update && \    apt-get install -y \    bash curl nano net-tools zip unzip \    jq dnsutils iputils-pingADD https://releases.hashicorp.com/consul/1.4.4/consul_1.4.4_linux_amd64.zip /tmp/consul.zipRUN cd /bin && unzip /tmp/consul.zip && chmod +x /bin/consul && rm /tmp/consul.zip# Consul portsEXPOSE 8300 8301 8302 8400 8500ADD consul_server.sh /optRUN mkdir -p /dataVOLUME /dataCMD ["/opt/consul_server.sh"]

Docker Compose


Мы используем Compose для запуска всех наших контейнеров Docker в желаемой, повторяемой форме.


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


Файл Docker Compose будет выглядеть так, как показано ниже:


version: "3.6"services:  consul_server:    build:      context: consul_server      dockerfile: Dockerfile    image: consul_server    ports:      - 8300:8300      - 8301:8301      - 8302:8302      - 8400:8400      - 8500:8500    environment:      - NODE=consul_server      - PRIVATE_IP_ADDRESS=33.10.0.2    networks:      consul_network:        ipv4_address: 33.10.0.2  load_balancer:    image: fabiolb/fabio    ports:      - 9998:9998      - 9999:9999    command: -registry.consul.addr="33.10.0.2:8500"    networks:      consul_network:        ipv4_address: 33.10.0.100  mongo_1:    build:      context: mongo      dockerfile: Dockerfile    image: mongo_consul    dns:      - 127.0.0.1      - 8.8.8.8      - 8.8.4.4    environment:      - NODE=mongo_1      - MONGO_PORT=27017      - PRIMARY_MONGO=33.10.0.3      - PRIVATE_IP_ADDRESS=33.10.0.3    restart: always    ports:      - 27017:27017      - 28017:28017    depends_on:      - consul_server      - mongo_2      - mongo_3    networks:      consul_network:        ipv4_address: 33.10.0.3  mongo_2:    build:      context: mongo      dockerfile: Dockerfile    image: mongo_consul    dns:      - 127.0.0.1      - 8.8.8.8      - 8.8.4.4    environment:      - NODE=mongo_2      - MONGO_PORT=27017      - PRIMARY_MONGO=33.10.0.3      - PRIVATE_IP_ADDRESS=33.10.0.4    restart: always    ports:      - 27018:27017      - 28018:28017    depends_on:      - consul_server    networks:      consul_network:        ipv4_address: 33.10.0.4  mongo_3:    build:      context: mongo      dockerfile: Dockerfile    image: mongo_consul    dns:      - 127.0.0.1      - 8.8.8.8      - 8.8.4.4    environment:      - NODE=mongo_3      - MONGO_PORT=27017      - PRIMARY_MONGO=33.10.0.3      - PRIVATE_IP_ADDRESS=33.10.0.5    restart: always    ports:      - 27019:27017      - 28019:28017    depends_on:      - consul_server    networks:      consul_network:        ipv4_address: 33.10.0.5  web_1:    build:      context: django      dockerfile: Dockerfile    image: web_consul    ports:      - 8080:8000    environment:      - NODE=web_1      - PRIMARY=1      - LOAD_BALANCER=33.10.0.100      - PRIVATE_IP_ADDRESS=33.10.0.10    dns:      - 127.0.0.1      - 8.8.8.8      - 8.8.4.4    depends_on:      - consul_server      - mongo_1    volumes:      - ./django:/web    cap_add:      - NET_ADMIN    networks:      consul_network:        ipv4_address: 33.10.0.10  web_2:    build:      context: django      dockerfile: Dockerfile    image: web_consul    ports:      - 8081:8000    environment:      - NODE=web_2      - LOAD_BALANCER=33.10.0.100      - PRIVATE_IP_ADDRESS=33.10.0.11    dns:      - 127.0.0.1      - 8.8.8.8      - 8.8.4.4    depends_on:      - consul_server      - mongo_1    volumes:      - ./django:/web    cap_add:      - NET_ADMIN    networks:      consul_network:        ipv4_address: 33.10.0.11networks:  consul_network:    driver: bridge    ipam:     config:       - subnet: 33.10.0.0/16

На этом мы подошли к концу настройки всей среды. Теперь мы можем запустить Docker Compose для сборки и запуска контейнеров.


Обнаружение сервисов с использованием Consul


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



Сервис MongoDB доступен для приложения Django для обнаружения с помощью интерфейса Consul DNS.


root@82857c424b15:/web/tweeter# dig @127.0.0.1 mongo-primary.service.consul; <<>> DiG 9.10.3-P4-Debian <<>> @127.0.0.1 mongo-primary.service.consul; (1 server found);; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8369;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;mongo-primary.service.consul.  IN  A;; ANSWER SECTION:mongo-primary.service.consul. 0 IN  A   33.10.0.3;; ADDITIONAL SECTION:mongo-primary.service.consul. 0 IN  TXT "consul-network-segment=";; Query time: 139 msec;; SERVER: 127.0.0.1#53(127.0.0.1);; WHEN: Mon Apr 01 11:50:45 UTC 2019;; MSG SIZE  rcvd: 109

Приложение Django теперь может подключить первичный экземпляр MongoDB и начать записывать в него данные.


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


Наш балансировщик нагрузки находится на 33.10.0.100, а /web настроен для перенаправления на один из наших экземпляров приложения Django, работающий за балансировщиком нагрузки.



Fabio автоматически определяет конечные точки веб-приложения Django


Как вы можете видеть из автоматического определения и настройки балансировщика нагрузки Fabio из его пользовательского интерфейса выше, он одинаково взвешивал конечные точки веб-приложения Django. Это поможет сбалансировать нагрузку запроса или трафика на экземпляры приложения Django.


Когда мы посещаем наш URL-адрес Fabio 33.10.0.100:9999 и используем исходный маршрут как /web, мы перенаправляемся на один из экземпляров Django. Итак, посещение 33.10.0.100:9999/web дает нам следующий результат.



Веб-приложение Django отображает статус подключения MongoDB на домашней странице


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


Это обнаружение первичного экземпляра MongoDB помогает приложению Django выполнять миграцию базы данных и развертывание приложения.


Можно изучить веб-интерфейс Consul, чтобы увидеть все экземпляры служб веб-приложений Django.



Сервисы веб-приложений Django в веб-интерфейсе Consul


Точно так же посмотрите, как устроены экземпляры набора реплик MongoDB.



MongoDB Replica Set Primary service видимый в веб-интерфейсе Consul



MongoDB Replica Set Secondary service видимый в веб-интерфейсе Consul


Давайте посмотрим, как Consul помогает с услугами проверки работоспособности и обнаружением только действующих служб.


Мы остановим текущий контейнер MongoDB Replica Set Primary (mongo_2), чтобы посмотреть, что произойдет.



Первичная служба MongoDB заменяется одним из вторичных экземпляров MongoDB



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


Consul перестал проходить проверку работоспособности для предыдущей основной службы MongoDB. Набор реплик MongoDB также обнаружил, что узел не работает и необходимо переизбрать основной узел. Таким образом, мы автоматически получаем новый MongoDB Primary (mongo_3).


Наш переключатель проверок сработал и заменил проверку mongo_3 со вторичной проверки MongoDB на первичную проверку MongoDB.


Когда мы смотрим на представление из приложения Django, мы видим, что теперь оно подключено к новой первичной службе MongoDB (mongo_3).



Отключение MongoDB Primary также отражается в веб-приложении Django.


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



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



Ранее отказавший экземпляр первичной службы MongoDB теперь повторно принят в качестве вторичного экземпляра службы MongoDB, поскольку он снова стал работоспособным


Точно так же, если мы остановим экземпляры службы приложения Django, Fabio теперь сможет обнаруживать только работоспособный экземпляр и направлять трафик только на этот экземпляр.



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


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


Настройка сервиса с помощью Consul


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


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


Мы можем использовать HTTP-интерфейс Consul для хранения пары ключ / значение и получения их в приложении, используя клиент Python с открытым исходным кодом для Consul, называемый python-consul. Вы также можете использовать любую другую библиотеку Python, которая может взаимодействовать с Consul KV, если хотите.


Давайте начнем с того, что посмотрим, как мы можем установить пару ключ / значение в Consul, используя его HTTP-интерфейс.


# Flag to run Django app in debug modecurl -X PUT -d 'True' consul_server:8500/v1/kv/web/debug# Dynamic entries into Django app configuration # to denote allowed set of hostscurl -X PUT -d 'localhost, 33.10.0.100' consul_server:8500/v1/kv/web/allowed_hosts# Dynamic entries into Django app configuration# to denote installed appscurl -X PUT -d 'tweetapp' consul_server:8500/v1/kv/web/installed_apps

После того, как мы установили хранилище KV, мы можем использовать его в экземплярах приложения Django, чтобы настроить его с этими значениями.


Давайте установим python-consul и добавим его как зависимость проекта.


$ pipenv shellLaunching subshell in virtual environment . /home/pranav/.local/share/virtualenvs/tweeter-PYSn2zRU/bin/activate$  . /home/pranav/.local/share/virtualenvs/tweeter-PYSn2zRU/bin/activate(tweeter) $ pipenv install python-consulInstalling python-consulAdding python-consul to Pipfile's [packages] Installation Succeeded Locking [dev-packages] dependenciesLocking [packages] dependencies Success! Updated Pipfile.lock (9590cc)!Installing dependencies from Pipfile.lock (9590cc)      14/14  00:00:20

Нам нужно будет подключить наше приложение к Consul с помощью python-consul.


import consulconsul_client = consul.Consul(    host='consul_server',    port=8500,)

Мы можем захватить и настроить наше приложение Django соответствующим образом с помощью библиотеки python-consul.


# Set DEBUG flag using Consul KV storeindex, data = consul_client.kv.get('web/debug')DEBUG = data.get('Value', True)# Set ALLOWED_HOSTS dynamically using Consul KV storeALLOWED_HOSTS = []index, hosts = consul_client.kv.get('web/allowed_hosts')ALLOWED_HOSTS.append(hosts.get('Value'))# Set INSTALLED_APPS dynamically using Consul KV storeINSTALLED_APPS = [    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',]index, apps = consul_client.kv.get('web/installed_apps')INSTALLED_APPS += (bytes(apps.get('Value')).decode('utf-8'),)

Эти пары ключ / значение из магазина Consul KV также можно просматривать и обновлять через его веб-интерфейс.



Consul KV store в интерфейсе Consul Web с параметрами конфигурации приложения Django


Код, используемый как часть этого руководства для раздела конфигурации службы Consul, доступен в ветви service-configuration проекта pranavcode/consul-demo.


Вот как можно использовать Consul KV и легко настраивать отдельные службы в их архитектуре.


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


В рамках сегментации сервисов Consul мы рассмотрим идею Consul Connect и распределенный дата-центр.


Connect обеспечивает авторизацию и шифрование соединений между сервисами с использованием взаимного TLS.


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


{    "connect": {        "enabled": true    }}

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


{    "service": {        "name": "web",        "port": 8000,        "tags": [            "web",            "application",            "urlprefix-/web"        ],        "connect": {            "sidecar_service": {                "proxy": {                    "upstreams": [{                        "destination_name": "mongo-primary",                        "local_bind_port": 5501                    }]                }            }        },        "check": {            "id": "web_app_status",            "name": "Web Application Status",            "tcp": "localhost:8000",            "interval": "30s",            "timeout": "20s"        }    }}

Наряду с настройкой Connect для бокового прокси нам также потребуется запустить прокси-сервер Connect для приложения Django. Этого можно добиться, выполнив следующую команду.


{    "service": {        "name": "web",        "port": 8000,        "tags": [            "web",            "application",            "urlprefix-/web"        ],        "connect": {            "sidecar_service": {                "proxy": {                    "upstreams": [{                        "destination_name": "mongo-primary",                        "local_bind_port": 5501                    }]                }            }        },        "check": {            "id": "web_app_status",            "name": "Web Application Status",            "tcp": "localhost:8000",            "interval": "30s",            "timeout": "20s"        }    }}

Мы можем добавить Consul Connect Intentions для создания графа сервисов для всех сервисов и определения шаблонов трафика. Мы можем создавать намерения, как показано ниже:


$ consul connect proxy -sidecar-for web

Намерениями для графа услуг также можно управлять из веб-интерфейса Consul.



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


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


Код, используемый как часть этого руководства для раздела сегментации услуг Consul, доступен в ветви service-segmentation проекта velotiotech/consul-demo.


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


Вывод


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


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


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


Ссылки


Подробнее..

Бэкапы для HashiCorp Vault с разными бэкендами

26.05.2021 10:15:20 | Автор: admin

Недавно мы публиковали статью про производительность Vault с разными бэкендами, а сегодня расскажем, как делать бэкапы и снова на разных бэкендах: Consul, GCS (Google Cloud Storage), PostgreSQL и Raft.

Как известно, HashiCorp предоставляет нативный метод бэкапа только для одного бэкенда Integrated Storage (Raft Cluster), представленного как GA в апреле прошлого года. В нем можно снять снапшот всего одним curlом и не беспокоиться о каких-либо нюансах. (Подробности смотрите в tutorial и документации по API.)

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

1. Consul

В Consul существует встроенный механизм для создания и восстановления снапшотов. Он поддерживает point-in-time backup, поэтому за консистентность данных можно не переживать. Однако есть существенный недостаток: на время снапшота происходит блокировка, из-за чего могут возникнуть проблемы с операциями на запись.

Для создания такого снимка необходимо:

1. Подключиться к инстансу с Consul и выполнить команду:

# consul snapshot save backup.snapSaved and verified snapshot to index 199605#

2. Забрать файл backup.snap (заархивировать и перенести в место для хранения бэкапов).

Для восстановления будет схожий алгоритм действий с выполнением другой команды на сервере с Consul:

# consul snapshot restore backup.snap

В HA Vault-кластере активный узел будет являться лидером во время экспорта данных или моментального снимка. После восстановления данных Vault в Consul необходимо вручную снять эту блокировку, чтобы кластер Vault мог выбрать нового лидера.

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

# consul kv delete vault/core/lock

Работа со снапшотами обычно происходит быстро (см. примеры в конце статьи) и обычно не вызывает трудностей.

2. Google Cloud Storage

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

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

Последовательность действий:

  1. Выключаем Vault.

  2. Заходим в Data Transfer (https://console.cloud.google.com/transfer/cloud).

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

  4. После успешного копирования запускаем Vault.

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

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

Скриншоты страницы при создании трансфера и после завершения:

3. PostgreSQL

Базу в PostgreSQL достаточно забэкапить любыми доступными для этой СУБД способами не сомневаюсь, что они хорошо известны инженерам, уже работающим с PgSQL. Инструкции по выполнению операций для настройки бэкапов и восстановления данных на нужный момент времени (PITR, Point-in-Time Recovery) описаны в официальной документации проекта. Также хорошую инструкцию можно найти в этой статье от Percona.

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

4. Integrated Storage (Raft)

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

Для создания снимка необходимо:

. Зайти на сервер/pod, где запущен Vault, и выполнить команду:

# vault operator raft snapshot save backup.snapshot
  1. Забрать файл backup.snapshot (заархивировать и перенести в место для хранения бэкапов).

Для восстановления команду на сервере с Vault надо заменить на:

# vault operator raft snapshot restore backup.snapshot

Как работать с Raft и со снапшотами, хорошо описано в официальной документации.

Простой бенчмарк

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

Загрузка данных в Vault

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

Протестируем на двух коллекциях: 100 тысяч и 1 млн ключей. Команды для первого теста:

export VAULT_ADDR=https://vault.service:8200export VAULT_TOKEN=YOUR_ROOT_TOKENvault secrets enable -path secret -version 1 kvnohup wrk -t1 -c16 -d50m -H "X-Vault-Token: $VAULT_TOKEN" -s write-random-secrets.lua $VAULT_ADDR -- 100000

Эту операцию проделаем для всех инсталляций Vault, а затем повторим её для другого количества ключей.

Результаты

После загрузки данных мы сделали бэкап для всех 4 бэкендов. Бэкап для каждого hosted-бэкенда снимался на однотипной машине (4 CPU, 8 GB RAM).

Результаты сравнения по бэкапу и восстановлению:

100k backup

100k restore

1kk backup

1kk restore

Consul

3.31s

2.50s

36.02s

27.58s

PosgreSQL

0.739s

1.820s

4.911s

24.837s

GCS*

1h

1h24m

12h

16h

Raft

1.96s

0.36s

22.66s

4.94s

* Восстановление бэкапа в GCS может происходить в нескольких вариантах:

  1. Мы просто переключаем Vault на бэкапный бакет. В таком случае достаточно перезапустить Vault с новым конфигом и все сразу же заработает.

  2. Загрузить файлы бэкапа в бакет через утилиту gsutil и уже после этого переключать. Результаты для такого варианта будут зависеть от количества файлов и их размера в таблице приведен результат именно для такого варианта.

NB. В этом мини-тестировании сравниваются решения разного рода: single-экземпляр PostgreSQL против кластеров Consul и Raft против сетевого распределённого хранилища (GCS). Это может показаться не совсем корректным, потому что у таких бэкендов и разные возможности/свойства (отказоустойчивость и т.п.). Однако данное сравнение приведено исключительно как примерный ориентир для того, чтобы дать понимание порядковой разницы в производительности. Ведь это зачастую является одним из факторов при выборе того или иного способа.

Выводы

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

Если сравнивать удобство, то Raft и Consul максимально простые: для выполнения бэкапа и восстановления достаточно выполнить буквально одну команду. GCS же предоставляет встроенный функционал в UI для копирования бакетов: на мой вкус, это немного сложнее, однако для других пользователей может быть плюсом, что все действия выполняются мышкой в браузере. Но в GCS есть существенная проблема с отсутствием гарантий по времени создания снапшотов: одинаковый набор данных может бэкапиться как за 1 час, так и за 3-4 часа.

Помимо производительности и удобства есть и другой критерий надежность. Вывод, казалось бы, довольно банален: чем менее надежен бэкенд, тем легче его бэкапить. Хотя Vault сам по себе позиционируется как приложение категории cloud native, его бэкап полностью зависит от выбранного бэкенда, и во многих случаях мы получим простой, что недопустимо для такого важного сервиса:

  • В Consul можно ожидать проблем с чтением и записью при бэкапе/восстановлении данных.

  • А у PostgreSQL при восстановлении.

  • У GCS проблема другого характера: нет гарантий на скорость копирования.

Получается, что все эти решения имеют серьёзные недостатки, которые могут быть недопустимы в production. Понимая это, в HashiCorp и создали своё оптимальное решение Integrated Storage (Raft). В нём получается делать бэкапы полностью беспростойно и при этом быстро.

В итоге: если вам важна максимальная скорость для снятия и восстановления бэкапов, то подойдут PostgreSQL и Raft. В первом случае, однако, надо повозиться с удобством: чтобы все правильно настроить и автоматизировать, придется потратить время (и иметь экспертизу). Наш текущий выбор пал на Integrated Storage (Raft) как самый простой в использовании и надежный бэкенд.

P.S.

Читайте также в нашем блоге:

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru