Очередная рассказка на тему SCM на питонятине. Ничего принципиально нового ребята не придумали, просто сделали то, что требуется рядовому системному администратору для управления зоопарком в 50+ машин.
По структуре в большинстве случаев Salt разделяется на два больших куска. Pillars - это статические данные, которые определяют всякие индивидуальные настройки для нод1) и States - эдакие “модули” (по аналогии с puppet), которые отвечают за непосредственную настройку ПО. Так же на стороне клиентов есть такое понятие, как Gains - это набор статической информации, которая собирается с сервера перед началом обработки стейтов. По ним можно определить всякие вещи, как то версия ОС, наличие или отсутствие тех или иных интерфейсов, а так же (как и в любой другой SCM) можно написать свои grains, которые после синхронизации на клиентах будут подмешиваться в общую структуру данных.
Если подходить к построению SCM с умом, то можно получить вполне себе логичную и удобную вещь, но у любой функции есть экстремумы, поэтому даже простой куб можно извратить до тэтраэдра, если очень постараться. Как я написал выше - я презираю использование import_yaml и вообще любой сложной динамики в пилларах, поскольку даже разработчиками заявлено, что это статическая информация. Кажется в версиях до 2016 были проблемы с вложением одних пилларов в другие (вроде нельзя было переопределять уже существующие поля), однако с версии 2017 это стало возможно, поэтому будучи как админом, так и программистом я нашёл для себя золотую середину в написании пилларов, а именно:
- pillars | - top.sls | - base/ | - pillars.sls | - common/ | - common.sls | - sysctl.sls | - dns.sls | - ntp.sls | - area/ | - in | - owlhost | - cloud | - msk2/ | - base/ | - pillars.sls | - common/ | - common.sls | - dns.sls | - network.sls | - nodes/ | - msk2-mgt1.cloud.owlhost.in.sls | - msk2-cmp1.cloud.owlhost.in.sls
Ну и конечно же чтобы не городить в top.sls кучу кода на jinja создаётся ещё маленький grains, который для каждого хоста добавляет нужные данные в grains
#!/usr/bin/env python import subprocess def extinfo(): grains = {} minion_id = open("/etc/salt/minion_id").read().replace("\n", "") # msk2-cmp1.cloud.owlhost.in parts = minion_id.split(".") parts.reverse() # ['in','owlhost','cloud','msk2-cmp1'] grains["nodename"] = parts.pop() # 'msk2-cmp1' grains["env"] = grains["nodename"].split("-")[0] # msk2 parts.append(grains["env"]) # ['in','owlhost','cloud','msk2'] grains["pillar_path"] = ".".join(parts) # in.owlhost.cloud.msk2 return grains # {'nodename': 'msk2-cmp1', 'pillar_path': 'in.owlhost.cloud.msk2', 'env': 'msk2'} if __name__ == "__main__": print(extinfo())
После чего синкаем grains на всех нодах
# salt \* saltutil.sync_grains
И можно писать top.sls
base: '*' - base.pillars - area.{{ grains['pillar_path'] }}.base.pillars - area.{{ grains['pillar_path'] }}.nodes.{{ grains['id'] }}
Вот собственно и весь top.sls. Работает он так - сначала загружает базовую структуру данных, которая общая для всех площадок, после чего подгружает структуру данных, которая уникальна в рамках площадки а следом уже накладывает изменения, которые уникальны в рамках одного хоста. Естественно в pillars.sls и common.sls должны быть другие include'ы, но в целом дальше salt развивается как обычно. Ах да, ещё один момент - hostname или minion_id должен быть специально офрмлен, как то - <площадка>-<любое количество информативных данных>.<top host> (например msk2-cmp1.cloud.owlhost.in)