DevOps инженер; Автоматизатор; Архитектор.
0,0
рейтинг
4 апреля 2014 в 11:36

Администрирование → SaltStack: управление произвольным количеством файлов конфигураций из песочницы tutorial

Что здесь интересного?


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

SaltStack (underfloor): что это и как с ним быть?


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

SaltStack (lobby): типичное применение на простом примере


Итак, предположим, у Вас есть задача автоматизировать установку, внедрение конфигурационных файлов и мониторинг их изменений, перезагрузку в случае необходимости такого популярного сервиса как nginx. Для упрощения системы, сделаем предположение что обслуживаемые сервера построены на базе Debian Wheezy. (Для всех остальных, — читаем про grains систему, — она поможет определить на какой системе мы применяем стейт и соответствующим образом поменять его поведение).
Итак:

nginx-repo-key-install:
  cmd.run:    
    - name: 'apt-key adv --keyserver keys.gnupg.net --recv-keys ABF5BD827BD9BF62'
    - unless: 'apt-key list | grep -q 7BD9BF62'

nginx-repo:
  pkgrepo.managed:
    - humanname: nginx-repo
    - name: deb http://nginx.org/packages/mainline/debian/ wheezy nginx
    - require_in:
      - pkg: nginx-pkg
    - required:
      - cmd: nginx-repo-key-install

nginx-pkg:
  pkg.installed:
    - name: nginx
    - refresh: True
    - require:
      - pkgrepo: nginx-repo

nginx-service:
  service.running:
    - name: nginx
    - full_restart: True
    - require:
      - pkg: nginx-pkg
    - watch:
      - file: nginx-config-vhost

nginx-config-vhost:
  file.managed:
    - name: /etc/nginx/conf.d/vhost.conf
    - source: salt://__CONFIGS/vhost.conf
    - user: root
    - group: root
    - mode: 644


Тут все, как «книжка пишет», но рассмотрим подробнее (очень важно как бэкграунд для последующих выкладок):
  • nginx-repo-key-install: импортируем в систему ключ официального репозитория
  • nginx-repo: вносим в apt официальный репозиторий
  • nginx-pkg: ставим свеженький пакет
  • nginx-service: берем под контроль сервис и заставляем следить за изменениями конфигурационного файла
  • nginx-config-vhost: собственно — конфигурационный файл и место откуда его брать

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

SaltStack (second floor): Много конфигурационных файлов


В первом примере был показан сервис в котором есть один файл где описан какой-то виртуальный сервер nginx. При его изменении на Salt мастере (salt://__CONFIGS/vhost.conf) и перезапуске стейта, файл будет обновлен на машине и сервис nginx будет перезапущен (full_restart: True) автоматически.
Зачастую виртуальных хостов на машине с nginx будет несколько. Рассмотрим как организовать управление ими.
Допустим, что есть файлы vhost{1,2,3,4,5}.conf. В таком случае нижняя часть стейта будет выглядеть так:
......

nginx-service:
  service.running:
    - name: nginx
    - full_restart: True
    - require:
      - pkg: nginx-pkg
    - watch:
      {% for cnf in ['vhost1.conf', 'vhost2.conf', 'vhost3.conf', 'vhost4.conf', 'vhost5.conf'] %}
      - file: nginx-config-{{ cnf }}
      {% endfor %}

{% for cnf in ['vhost1.conf', 'vhost2.conf', 'vhost3.conf', 'vhost4.conf', 'vhost5.conf'] %}
nginx-config-{{ cnf }}:
  file.managed:
    - name: /etc/nginx/conf.d/{{ cnf }}
    - source: salt://__CONFIGS/{{ cnf }}
    - user: root
    - group: root
    - mode: 644
{% endfor %}


Тут начинается немного магии Salt, а именно: Jinja — шаблонизатор для Python (на котором и написан SaltStack). В стейте все очевидно, — делаем много объектов file с разными названиями и подвязываем все их к службе, чтобы при изменениях проводился её перезапуск. Для оптимизации можно использовать систему pillar-ов чтобы хранить имена файлов с конфигурациями. Но это — домашнее задание.

SaltStack (one floor upper): Много конфигурационных файлов — но сколько и каких — неизвестно.


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

nginx-service:
  service.running:
    - name: nginx
    - full_restart: True
    - require:
      - pkg: nginx-pkg
    - watch:
      {% for cnf in salt['cp.list_master'](prefix='__CONFIGS/') %}
      - file: nginx-config-{{ cnf }}
      {% endfor %}

{% for cnf in salt['cp.list_master'](prefix='__CONFIGS/') %}
{% set items = cnf.split('/') %}
nginx-config-{{ cnf }}:
  file.managed:
    - name: /etc/nginx/conf.d/{{ items|last }}
    - source: salt://{{ cnf }}
    - user: root
    - group: root
    - mode: 644
{% endfor %}


Собственно теперь о самых интересных местах:
{% for cnf in salt['cp.list_master'](prefix='__CONFIGS/') %}

вызываем ф-цию list_master из модуля cp с префиксом '__CONFIGS/' (имя папки на Salt мастере где лежат все конфигурационные файлы для этого сервиса) которая с выдает список файлов в этом каталоге и итерируем по списку циклом for.
{% set items = cnf.split('/') %}

Проблема cp.list_master заключается в том, что она выдает полный путь к файлу (вместе с префиксом), а нам нужно лишь имя файла для того, чтобы указать его в директиве "- name:". В связи с этим мы сплиттим полный путь по слешам и используем только последний элемент списка — т.е. имя файла:
- name: /etc/nginx/conf.d/{{ items|last }}

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

Заключение


Очень кратенько, но надеюсь поможет тем читателям Хабра, которые только начинают внедрять SaltStack и хотят пойти немного дальше чем книжные примеры с простым менеджментом пакетов. Успехов!
Евгений Чепурный @eugenechepurniy
карма
15,0
рейтинг 0,0
DevOps инженер; Автоматизатор; Архитектор.
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Администрирование

Комментарии (8)

  • 0
    Давно использую salt (чуть ли ни с его рождения), мне очень нравятся те идеи которые в нем заложены, простота и невероятная гибкость. Тем не менее есть и негатив от него. Сразу списком, а ниже подробнее:
    1) нестабильность версий и плохое их тестирование;
    2) часто ломают совместимость;
    3) ужасный стиль кода и плохая внутренняя согласованность.

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

    Так же несколько раз случалось, что новые версии minion'ов требовали также обновленного master'а, то есть нельзя было компоненты salt обновлять постепенно, а нужно было только сразу везде и до одинаковой версии. Для продакта это так же «неприятно».

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

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

    Так что, если вы думаете выбрать salt для продакта, то учтите есть ли у вас навыки и желание, что-то в нем исправлять и обслуживать как отдельную сущность (следить за обновлениями). Конечно, проект развивает (и очень быстро), поэтому есть вера, что будет становиться все лучше и лучше.
    • 0
      Почти во всем согласен с Вами, — все верно. Салт, как и любой другой молодой продукт не лишен недостатков. Будем надеяться, что сообщество работающее над его развитием будет пополняться более талантливыми программистами (от того, наверняка и проблемные места, что сообщество разнородное и многочисленное). Но, с другой стороны, его сумасшедшая гибкость и простота тянет как магнит.
      У меня уже тоже много конфигураций и своя модель представления компонентов с наследованием и прочими вкусностями. А статьи пишу и буду писать для таких же как я авантюрно настроенных людей, которым интересно взять все новое и внедрить его, как это уже было с салтом, докером и прочими «сырыми» технологиями.
  • 0
    Небольшое замечание: странно что вы используете параметр watch у nginx-service отдельно для каждого конфигурационного файла. На мой взгляд, гораздо более логично использовать watch_in: — service: nginx-service для каждого конфигурационного файла.
    Кстати, на мой взгляд, гораздо удобнее использовать состояние file.recurse для управления некоторой дирректорией конфигураций.
    • 0
      приветствую! да, действительно *_in реквизиты достаточно сильно упрощают жизнь, но, по сути, делают то же самое, что и собственно реквизиты описанные в самих зависимых стейтах, потому оба способа — приемлемы. По поводу file.recurse — этот стейт еще не входил в поставку salt stack на момент написания статьи :) (вышел только в 2014.7.0) В любом случае — советы правильные, спасибо.
      • 0
        По поводу file.recurse — этот стейт еще не входил в поставку salt stack на момент написания статьи :) (вышел только в 2014.7.0)

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

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

        require — используется в том стейте, которому необходим другой стейт, при этом другой стейт ничего не знает об этом.
        watch_in — используется так же, но при этом еще и вызывает перезагрузку службы (или что-то еще) если состояние текущего стейта изменилось.

        require_in и watch указывают на ровно противоположные отношения между стейтами.

        Т.е. если у нас есть некоторое дерево состояний, то require и watch_in используются в дочерних элементах и эти элементы очевидно знают своих родителей. А require_in и watch — в родительских, которые в свою очередь не обязательно знают всех своих детей.

        {% for cnf in ['vhost1.conf', 'vhost2.conf', 'vhost3.conf', 'vhost4.conf', 'vhost5.conf'] %}

        В вашем примере как раз и показано то, через что приходится проходить, чтобы заставить родителей знать своих детей (:
        • 0
          Абсолютно согласен с тем, что Вы описали по части реквизитов, — все верно. Каюсь: на момент написания статьи и сам Salt и автор были еще не столь глубоко знакомы. :) Но все меняется со временем и остальные статьи — тому пример.
          Но, на самом деле, соль статьи была как раз в описании мало документированного примера использования модуля cp. И стейты в статье описывались не как пример для «copy-paste» себе в дерево, а как рассмотрение шагов модернизации от самого простого проходя более комплексный (всегда рабочий, но не всегда элегантный!) до последнего, описывающего собственно то, что удалось выкопать автору и то, чем хотелось бы поделится.
          Естественно, как мне кажется, каждый должен применять голову к тому или иному материалу изложенному на Хабре.
          В любом случае — буду рад прочесть и обсудить Вашу статью на тему SaltStack, — вполне возможно, что мне будет чему поучится.
          • +1
            Естественно, как мне кажется, каждый должен применять голову к тому или иному материалу изложенному на Хабре.

            Согласен. И надеюсь, что все-таки мои комментарии будут служить не критикой вашего материала, а скорее дополнением.
            Например в документации на SaltStack есть, на мой взгляд, большой пробел в том, что *_in параметры вводятся как дополнительные, не смотря на их семантику (видимо, это исторически обусловлено)… Также сложно сразу раскопать список всех стейтов с описанием.

            Приведенный в этой статье подход прекрасно демонстрирует гибкость Salt, которая с лихвой окупает его недостатки. Также хотелось бы отметить вашу третью статью на эту тему, которая демонстрирует подход к управлению кластером.

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

            На тему Salt, наверное, сложно написать что-то большее чем уже существует. У меня скорее зреет мысль по поводу статьи о некоторых нетривиальных аспектах PHP, которые не всплывали из-за основного способа его использования, но становятся более актуальными в связи с переходом к более долгоживущим процессам. Надеюсь у меня получится оформить это в виде статьи. (:

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