Как стать автором
Обновить
78.84

Как мы прокачали архитектуру, чтобы упростить эксплуатацию продукта

Уровень сложностиСредний
Время на прочтение9 мин
Количество просмотров2.3K
preview url image

Хабр, привет! С вами снова на связи команда ALD Pro, а за главного сегодня буду я, Илья, и мой коллега Михаил. Как вы помните, наш продукт создается на замену MS AD для возможности переезда на Linux-инфраструктуру, и одним из ключевых компонентов этой технологии являются групповые политики. Мы с Михаилом как раз и отвечаем за разработку и оптимизацию этого механизма, так что теперь вы знаете, к кому направлять свои пожелания и благодарности.

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

Учитывая, что в нашей команде работает очень много сильных системных администраторов и DevOps-инженеров, к мнению которых мы всегда прислушиваемся и на которое ориентируемся, можно без лишней скромности сказать, что ALD Pro – это продукт ОТ сисадминов и ДЛЯ сисадминов. Мы стремимся максимально упростить работу наших коллег на предприятиях, и в большинстве случаев это даже не требует разработки каких-то ракетных технологий «с нуля».

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

Постановка задачи

Вспомним, что изначально мы использовали Salt в классической архитектуре мастер-миньон, в соответствии с которой служба salt-minion устанавливалась на все хосты в домене, а служба salt-master — только на контроллеры. В этой архитектуре рабочие станции забирали параметры групповых политик через внешние (external) pillar, а salt-скрипты загружались через встроенный в Salt файловый сервер, поэтому при выходе новой версии продукта обновлять скрипты нужно было только на контроллерах домена. Такая схема была чудо как хороша за исключением того, что в больших инфраструктурах она не работала.

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

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

Наша автономная служба работает как сервис gpsvc в Windows и берет на себя следующие задачи:

  • Самостоятельно извлекает параметры групповых политик через LDAP по pull-модели и выполняет их суммирование на стороне рабочей станции, чтобы снизить нагрузку с контроллеров домена.

  • Обеспечивает безопасное взаимодействие с контроллерами, выполняя Kerberos-аутентификацию с использованием учетных данных компьютера из файла /etc/krb5.keytab.

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

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

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

Эх, такими бы устами да ложку дегтя. Не станем скрывать, что отказ от salt-master и переход на автономный клиент aldpro-salt-minion, который может работать совершенно независимо от мастера, не прошел для нас совсем безболезненно. Данное нововведение лишило возможности доставлять скрипты через встроенный файловый сервер Salt. Но не стоит унывать! У нас уже был положительный опыт решения похожей задачи с доставкой файлов через LDAP, который мы смогли применить и в этом случае, чтобы администраторам больше не приходилось каждый раз обновлять парк машин руками.

Как мы храним файлы в LDAP-каталоге

Записать файл в каталог не очень сложно, но и в этом есть свои нюансы. Важно учитывать, что при обновлении продукта изменяются не все скрипты сразу, поэтому желательно избежать дублирования записей в каталоге. Чтобы одни и те же записи файлов можно было повторно использовать в разных версиях клиентской части, мы решили хранить файлы всех версий в одном общем контейнере «cn=files,cn=policymanager,cn=vcsStorage,cn=aldpro,cn=etc» (см. рис. 1).

Рис. 1. Хранение файлов в контейнере «cn=files»
Рис. 1. Хранение файлов в контейнере «cn=files»

Для именования записей мы используем атрибут cn (Common Name — общее название), в который записываем уникальный идентификатор в формате entryUUID (Universally Unique Identifier), что позволяет нам хранить в одном контейнере файлы с одинаковыми именами, но разным содержимым. Через объектный класс rbta-ald-autoload-gp-files этим записям доступны следующие атрибуты:

  • filePath – имя файла и его адрес относительно корневой директории Salt, в которой он должен быть сохранен на рабочей станции, например, «roots/states/policies/host-policies/_modules/quotas_utils.py».

  • fileContent – содержимое файла в кодировке UTF-8.

  • fileContentHash – хеш от содержимого файла, по которому можно быстро сравнивать LDAP-записи с локальными файлами на диске, не загружая их контент из каталога. Используется простой алгоритм MD5, который генерирует 32-байтные значения. Поиск похожих записей выполняется по комбинации значений filePath и fileContentHash.

Все указанные атрибуты имеют тип данных DirectoryString без ограничения по длине строки, поэтому в работе с файлами мы лимитированы только значением параметра nsslapd-maxbersize, который устанавливает максимальный размер в байтах для входящих сообщений и LDAP-запросов. По умолчанию maxbersize равен 2 Мб, что с большим запасом перекрывает потребности в хранении небольших файлов.

Кстати, в далекие 2000-е разработчики MS рекомендовали записывать в LDAP-каталог атрибуты размером не более 100 Кб, но с того времени закон Мура сработал уже не менее 20 раз, поэтому сейчас можно действовать посмелее, но все же без фанатизма.

3. Как мы группируем файлы одной версии клиентской части

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

Чтобы быстро понять, какие файлы относятся к конкретной версии клиентской части, мы используем так называемые "версионные записи", которые можно найти в контейнере «cn=versions,cn=policymanager,cn=vcsStorage,cn=aldpro,cn=etc» (см. рис. 2).

Рис. 2. Хранение версионных записей в каталоге
Рис. 2. Хранение версионных записей в каталоге

В качестве имени версионной записи мы используем атрибут cn, в который записываем версию deb-пакета aldpro-policy-manager. Версионную запись можно посмотреть на контроллере домена, например, с помощью пакетного менеджера apt (см. атрибут Version):

admin@dc-1:~$ apt show aldpro-policy-manager
Package: aldpro-policy-manager
Version: 2.4.0-142
Priority: optional
Section: unknown
Maintainer: ALDPro Sales <aldpro@astralinux.ru>
Installed-Size: 2 793 kB
Depends: aldpro-salt-minion
Homepage: https://git.astralinux.ru/projects/AD/repos/policy-manager
Download-Size: 341 kB
APT-Manual-Installed: no
APT-Sources: https://dl.astralinux.ru/aldpro/frozen/01/2.4.0 1.7_x86-64/main amd64 Packages
Description: ALD Pro clients group policy manager

Через объектный класс rbta-ald-autoload-gp-versions этим записям доступны следующие атрибуты:

  • fileUID – множественный атрибут, который содержит ссылки на все файлы, относящиеся к данной версии пакета aldpro-policy-manager;

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

Рис. 3. Алгоритм загрузки файлов в LDAP-каталог
Рис. 3. Алгоритм загрузки файлов в LDAP-каталог

Рассмотрим порядок загрузки файлов в LDAP-каталог на контроллере домена (см. рис. 3). Сначала алгоритм проверяет, есть ли в каталоге версионная запись, соответствующая текущей версии установленного deb-пакета aldpro-policy-manager. Если версионной записи еще нет, то можно ее создать и приступить к загрузке файлов из папки /srv/salt/standalone/ за некоторым исключением, например, каталог pycache в LDAP не загружается. Если же версионная запись уже существует, то нужно сначала проверить ее целостность.

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

Чтобы избежать дупликации, скрипт загрузки хеширует файл и пытается найти в контейнере «cn=files» запись с таким же сочетанием атрибутов filePath и fileContentHash. Если похожая запись найдена, то можно воспользоваться ссылкой на эту запись и не загружать файл повторно. Таким образом гарантируется, что при повторной загрузке файлов в каталог результат не изменится, или, как еще говорят, будет обеспечена идемпотентность.

Как синхронизировать файлы на рабочих станциях

Осталась самая интересная часть: как скрипты групповых политик из LDAP-каталога попадают на рабочие станции (см. рис. 4).

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

Загрузку файлов из LDAP-каталога в локальный кэш на доменном компьютере выполняет функция run_update из модуля patch_gp, которую можно запустить вручную командой aldpro-salt-call patch_gp.run_update или с помощью специальной утилиты продукта aldpro-gpupdate --pm.

Модуль изначально устанавливается вместе с deb-пакетом aldpro-common и находится в папке /opt/rbta/venvs/aldpro-common/lib/python3.7/site-packages/salt/modules/patch_gp.py. Однако после первого обновления файлов система Salt переключится на те скрипты, которые будут загружены уже из LDAP-каталога. То есть мы можем обновлять даже скрипты самой системы обновления!

Рис. 4. Алгоритм загрузки файлов из LDAP-каталога в локальный кэш клиента
Рис. 4. Алгоритм загрузки файлов из LDAP-каталога в локальный кэш клиента

Учитывая риски, связанные с разработкой самообновляющихся систем, наша служба сначала формирует новый комплект файлов в папке /opt/rbta/aldpro-salt/minion/cache_gp_versions/ и только после проверки его целостности заменяет этим комплектом файлы из папки /srv/aldpro-salt/.

Для автономной службы aldpro-salt-minion указанная директория выступает в роли корневой папки встроенного в Salt файлового сервера (file_roots), которая в классической архитектуре «мастер-миньон» размещается на мастере. В автономный режим работы файловый сервер переключают параметры file_client и file_roots в настройках миньона:

cat /srv/aldpro-salt/config/minion
...
file_client: local
file_roots:
  base:
    - /srv/aldpro-salt/roots
    - /srv/aldpro-salt/roots/states
    - /srv/aldpro-salt/roots/states/policies/host-policies
    - /srv/aldpro-salt/roots/states/policies/user-policies
    - /srv/aldpro-salt/roots/states/policies/sw-policies
    - /srv/aldpro-salt/roots/states/policies/audit-policies
...

В классической архитектуре «мастер-миньон» с настройками по умолчанию служба миньона при загрузке файлов с мастер-сервера кэширует их в папке /var/cache/salt/minion/. Чтобы не пересекаться с обычным миньоном, для своей автономной службы мы переопределяем путь к этой папке с помощью параметра cachedir и добавляем еще параметр append_minionid_config_dirs['cachedir'], поэтому полный путь включает также идентификатор миньона /var/cache/aldpro-salt/minion/aldpro-standalone.minion/.

Осталось только добавить, что система Salt импортирует пользовательские модули не напрямую из директорий modules и states внутри cachedir, а синхронизирует их сначала с основными файлами в папке extension_modules. Синхронизация выполняется первый раз при запуске службы миньона, затем каждый час по расписанию, а принудительно выполнить ее можно командой aldpro-salt-call saltutil.sync_modules. Опять же, в классической архитектуре с настройками по умолчанию папка extension_modules находится по адресу /var/cache/salt/minion/extmods/, но, чтобы изолировать работу нашей автономной службы и не мешать работе обычного миньона, мы с помощью параметра append_minionid_config_dirs['extension_modules'] добавляем в путь идентификатор миньона и получаем /var/cache/salt/minion/extmods/aldpro-standalone.minion/. Механизм кэширования Salt-миньона при работе в автономном режиме мог бы, наверное, быть и попроще, но разработчики, видимо, обошлись минимальными изменениями в программном коде, чтобы повысить надежность его работы и упростить дальнейшую поддержку решения.

Учитывая все вышесказанное, для быстрой отладки работы модулей можно вносить изменения напрямую в файлы из папки /var/cache/salt/minion/extmods/aldpro-standalone.minion/, но следует помнить, что их содержимое будет перезаписываться каждый час, поэтому безопаснее работать с файлами из директорий file_roots (например, /srv/aldpro-salt/roots/_modules), запуская синхронизацию модулей вручную командой aldpro-salt-call saltutil.sync_modules. Что касается sls-файлов состояний, то они сохраняются в каталоге /srv/aldpro-salt/roots/states/ и не требуют какой-то дополнительной синхронизации, поэтому вы можете смело редактировать их напрямую в этой директории. Ваши изменения будут оставаться на рабочих станциях до тех пор, пока соответствующие файлы не будут изменены в LDAP-каталоге.

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

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


Теги:
Хабы:
Всего голосов 10: ↑8 и ↓2+9
Комментарии2

Публикации

Информация

Сайт
astra.ru
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия