От “стартапа” до тысяч серверов в десятке ЦОД. Как мы гнались за ростом Linux инфраструктуры

Если ваша IT инфраструктура растёт слишком быстро, вы рано или поздно столкнётесь с выбором – линейно увеличивать людские ресурсы на её поддержку или начинать автоматизацию. До какого-то момента мы жили в первой парадигме, а потом начался долгий путь к Infrastructure-as-Code.



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

В целом, можно сказать, что наша команда поставляет для компании 2 продукта. Первый – это инфраструктура. Почта должна ходить, DNS работать, а контроллеры домена – пускать вас на сервера, которые не должны падать. IT ландшафт компании огромен! Это business&mission critical системы, требования по доступности некоторых – 99,999. Второй продукт – сами сервера, физические и виртуальные. За существующими нужно следить, а новые регулярно поставлять заказчикам из множества подразделений. В этой статье я хочу сделать акцент на том, как мы развивали инфраструктуру, которая отвечает за жизненный цикл серверов.

Начало пути

В начале пути наш стек технологий выглядел так:
ОС CentOS 7
Контроллеры домена FreeIPA
Автоматизация — Ansible(+Tower), Cobbler


Всё это располагалось в 3х доменах, размазанных на нескольких ЦОДах. В одном ЦОД –офисные системы и тестовые полигоны, в остальных ПРОД.

Создание серверов в какой-то момент выглядело так:



В шаблоне VM CentOS minimal и необходимый минимум вроде корректного /etc/resolv.conf, остальное приезжает через Ansible.

CMDB – Excel.

Если сервер физический, то вместо копирования виртуальной машины на него устанавливалась ОС с помощью Cobbler – в конфиг Cobbler добавляются MAC адреса целевого сервера, сервер по DHCP получает IP адрес, а дальше наливается ОС.

Поначалу мы даже пытались делать какой-то configuration management в Cobbler. Но со временем это стало приносить проблемы с переносимостью конфигураций как в другие ЦОД, так и в Ansible код для подготовки VM.

Ansible в то время многие из нас воспринимали как удобное расширение Bash и не скупились на конструкции с использованием shell, sed. В общем Bashsible. Это в итоге приводило к тому, что, если плейбук по какой-либо причине не отрабатывал на сервере, проще было удалить сервер, поправить плейбук и прокатить заново. Никакого версионирования скриптов по сути не было, переносимости конфигураций тоже.

Например, мы захотели изменить какой-то конфиг на всех серверах:

  1. Изменяем конфигурацию на существующих серверах в логическом сегменте/ЦОД. Иногда не за один день – требования к доступности и закон больших чисел не позволяет применять все изменения разом. А некоторые изменения потенциально деструктивны и требуют перезапуск чего-либо – от служб до самой ОС.
  2. Исправляем в Ansible
  3. Исправляем в Cobbler
  4. Повторяем N раз для каждого логического сегмента/ЦОД

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

  • Рефакторинг ansible кода, конфигурационных файлов
  • Изменение внутренних best practice
  • Изменения по итогам разбора инцидентов/аварий
  • Изменение стандартов безопасности, как внутренних, так и внешних. Например, PCI DSS каждый год дополняется новыми требованиями

Рост инфраструктуры и начало пути

Количество серверов/логических доменов/ЦОД росло, а с ними количество ошибок в конфигурациях. В какой-то момент мы пришли к трём направлениям, в сторону которых нужно развивать configuration management:

  1. Автоматизация. Насколько возможно, нужно избегать человеческого фактора в повторяющихся операциях.
  2. Повторяемость. Управлять инфраструктурой намного проще, когда она предсказуема. Конфигурация серверов и инструментов для их подготовки должна быть везде одинаковой. Это так же важно для продуктовых команд – приложение должно гарантированно после тестирования попадать в продуктивную среду, настроенную аналогично тестовой.
  3. Простота и прозрачность внесения изменений в configuration management.

Осталось добавить пару инструментов.

В качестве хранилища кода мы выбрали GitLab CE, не в последнюю очередь за наличие встроенных модулей CI/CD.

Хранилище секретов — Hashicorp Vault, в т.ч. за прекрасное API.

Тестирование конфигураций и ansible ролей – Molecule+Testinfra. Тесты идут намного быстрее, если подключаете к ansible mitogen. Параллельно мы начали писать собственную CMDB и оркестратор для автоматического деплоя (на картинке над Cobbler), но это уже совсем другая история, о которой в будущем расскажет мой коллега и главный разработчик этих систем.

Наш выбор:

Molecule + Testinfra
Ansible + Tower + AWX
Мир Серверов + DITNET(Собственная разработка)
Cobbler
Gitlab + GitLab runner
Hashicorp Vault




Кстати про ansible роли. Сначала она была одна, после нескольких рефакторингов их стало 17. Категорически рекомендую разбивать монолит на идемпотентные роли, которые можно потом запускать отдельно, дополнительно можно добавить теги. Мы роли разбили по функционалу – network, logging, packages, hardware, molecule etc. А вообще, придерживались стратегии ниже. Не настаиваю на том, что это истина в единственной инстанции, но у нас сработало.

  • Копирование серверов из “золотого образа” – зло!

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

    1. Оставьте /etc/sysctl.conf пустым, настройки должны лежать только в /etc/sysctl.d/. Ваш дефолт в один файл, кастом для приложения в другой.
    2. Используйте override файлы для редактирования systemd юнитов.
  • Шаблонизируйте все конфиги и подкладывайте целиком, по возможности никаких sed и его аналогов в плейбуках
  • Рефакторя код системы управления конфигурациями:

    1. Разбейте задачи на логические сущности и перепишите монолит на роли
    2. Используйте линтеры! Ansible-lint, yaml-lint, etc
    3. Меняйте подход! Никакого bashsible. Нужно описывать состояние системы
  • Под все Ansible роли нужно написать тесты в molecule и раз в день генерировать отчёты.
  • В нашем случае, после подготовки тестов (которых больше 100) нашлось около 70000 ошибок. Исправляли несколько месяцев.


Наша реализация

Итак, ansible роли были готовы, шаблонизированы и проверены линтерами. И даже гиты везде подняты. Но вопрос надежной доставки кода в разные сегменты остался открытым. Решили синхронизировать скриптами. Выглядит так:



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

Вариантов создания серверов тоже много. Мы в итоге выбрали кастомные скрипты на питоне. А для CI ansible:

- name: create1.yml - Create a VM from a template
  vmware_guest:
    hostname: "{{datacenter}}".domain.ru
    username: "{{ username_vc }}"
    password: "{{ password_vc }}"
    validate_certs: no
    cluster: "{{cluster}}"
    datacenter: "{{datacenter}}"
    name: "{{ name }}"
    state: poweredon
    folder: "/{{folder}}"
    template: "{{template}}"
    customization:
      hostname: "{{ name }}"
      domain: domain.ru
      dns_servers:
        - "{{ ipa1_dns }}"
        - "{{ ipa2_dns }}"
    networks:
      - name: "{{ network }}"
        type: static
        ip: "{{ip}}"
        netmask: "{{netmask}}"
        gateway: "{{gateway}}"
        wake_on_lan: True
        start_connected: True
        allow_guest_control: True
    wait_for_ip_address: yes
    disk:
      - size_gb: 1
        type: thin
        datastore: "{{datastore}}"
      - size_gb: 20
        type: thin
        datastore: "{{datastore}}"

Вот к чему мы пришли, система продолжает жить и развиваться.

  • 17 ansible-ролей для настройки сервера. Каждая из ролей предназначена для решения отдельной логической задачи (логирование, аудит, авторизация пользователей, мониторинг и т.д.).
  • Тестирование ролей. Molecule + TestInfra.
  • Собственная разработка: CMDB + Оркестратор.
  • Время создания сервера ~30 минут, автоматизировано и практически не зависит от очереди задач.
  • Одинаковое состояние/именование инфраструктуры во всех сегментах – плейбуки, репозитории, элементы виртуализации.
  • Ежедневная проверка состояния серверов с генерацией отчётов о расхождениях с эталоном.

Надеюсь мой рассказ будет полезен тем, кто в начале пути. А какой стек автоматизации используете вы?

Комментарии 7

    +1

    Планируется ли открыть исходный код вашей CMDB ?

      +2
      Не планировали. На мой взгляд, если нужен именно учёт, — можно поискать готовые решения, а если хочется под себя, то рано или поздно нужно будет делать своё. Мы пошли в собственную разработку ради кастомных интеграций, которые вряд ли будут интересны широкому кругу.
      0
      Актуальная статья. Решаю похожие задачи и любой опыт полезен.
      Благодарю.
      Из личного опыта: несмотря на исторически преобладающий C# код, управление и тестирование инфраструктуры тоже на Python — больше доступных библиотек, проще вносить изменения и тестировать.
        0

        Выглядит огненно, вопросы из зала


        1. оркестрацию используете (условная задача "выполнить действие ХХ на подмножестве серверов YY")
        2. есть ли изменения конфигурации серверов в процессе их жизни? Т.е. что я имею в виду — как выглядит процесс изменения конфигурации — через переналивку-пересоздание сервера? Или по ходу жизни? Нет ли configuration drift, как с ним боретесь?
        3. почему ansible + awx, а не, скажем, puppet/chef/salt? Просто я себе вижу, что последние более интересны именно в ключе создания "живой" инфраструктуры ) т.к. недостаточно просто применять плейбуки в нужном порядке, а реально нужно реагировать на события в инфре.

        Копирование серверов из “золотого образа” – зло!

        Эм, тема нераскрыта, вообще же у нас это работает


        Шаблонизируйте все конфиги и подкладывайте целиком, по возможности никаких sed и его аналогов в плейбуках

        очень верный совет!


        Используйте override файлы для редактирования systemd юнитов.

        жму руку!

          +2
          оркестрацию используете (условная задача «выполнить действие ХХ на подмножестве серверов YY»)

          Оркестрацию используем — тут чистый ansible.

          есть ли изменения конфигурации серверов в процессе их жизни? Т.е. что я имею в виду — как выглядит процесс изменения конфигурации — через переналивку-пересоздание сервера? Или по ходу жизни? Нет ли configuration drift, как с ним боретесь?

          В процессе жизни на серверах может много чего меняться. Как я писал, после запуска движка тестирования было исправлено около 70000 мисконфигураций. Исправляли в процессе жизни — как правило делили изменения по уровню критичности и прокатывали соответственную роль на сервера группами.
          С configuration drift боремся тестированием конфигураций — ежедневно все сервера тестируются на соответствие с эталоном в гите и генерируются отчёты с расхождениями, которые мы берём в работу.

          почему ansible + awx, а не, скажем, puppet/chef/salt?

          И не только ansible + AWX, ещё и Tower! Нам больше подошёл ansible, т.к. он стал единым выбором всей компании — как прикладные администраторы, так и DevOps команды в последнее время пишут деплои именно на нём. И не только для nix, но и для Windows. Без агентов, с низким порогом вхождения и Push стратегией. Плюс скорость развития и размер сообщества. А ещё мы любим python :)

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

            кмк, зависит от количества вариаций. Условно, если у Вас инфра состоит из 5 вида кирпичиков — поддержка 5 "золотых" образов с разными конфигами не выглядит большой проблемой. Зато релизный цикл понятный. Вышло обновление — пересоздали образ, перекатили сервер (с сохранением данных, ес-но) — все круто, прям как с контейнерами докер. Если же вариацией сильно больше — действительно проще лить пустой образ, а далее его доконфигурировать


            И не только для nix, но и для Windows. Без агентов, с низким порогом вхождения и Push стратегией.

            очень спорно плюсы это или минусы — смотря как повернуть )
            без агентов — а варианта с агентом нет (минус)
            низкий пород вхождения — провоцирует "башсибл"
            push стратегия — нет пулла, а он может быть нужен (ansible-pull не вспоминайте)


            В любом случае рад, что Вам удалось достичь взаимопонимания с другими отделами — это существенно более важно, чем та технология, которая была выбрана ) Люди — они важнее этих… технологий )


            А ещё мы любим python :)

            мы тоже, поэтому "топим" за salt — он тоже на пайтоне ))))


            С configuration drift боремся тестированием конфигураций — ежедневно все сервера тестируются на соответствие с эталоном в гите и генерируются отчёты с расхождениями, которые мы берём в работу.

            тестирование это круто. Но вот что делать с таким — мы применили какую-то роль, она что-то насоздавала, потом в следующей версии роли мы уже эти файлы не создаем, и поэтому мы их и не очищаем (!) — в результате — заканчиваем с мусором в системе, который мы не можем увидеть (потому что он не под управлением конфигурацией) и который мы не вычищаем (потому что в следующей версии роли мы его не чистим, хотя это было бы логично) — это реальный пример из ролей в open-source.

              +2
              кмк, зависит от количества вариаций

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

              В любом случае рад, что Вам удалось достичь взаимопонимания с другими отделами — это существенно более важно, чем та технология, которая была выбрана ) Люди — они важнее этих… технологий )

              Полностью согласен, у инструментов есть преимущества и недостатки, но главное всё же люди и единые рельсы.

              Но вот что делать с таким — мы применили какую-то роль, она что-то насоздавала, потом в следующей версии роли мы уже эти файлы не создаем, и поэтому мы их и не очищаем

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

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

        Самое читаемое