Анонсируя второй поток, который стартует 11 октября, делимся историей Артёма Чекунова, Senior DevOps Engineer в Chartboost. Артём рассказывает, как познакомился с Python, и описывает несколько реальных кейсов его применения: для анализа потребления ресурсов в облаке и bare-metal, сборки тяжелого софта, мониторинга серверов Elasticsearch.
От офисного администратора к системному разработчику
Свой путь я начинал где-то в 2006-м как офисный администратор. Меня интересовал Linux, поэтому я ставил его для офиса, настраивал и так потихоньку переключился на Linux/Unix-администрирование. Первые скрипты начал писать, когда перешёл в компанию провайдера хостинга. Использовал Bash, AWK и Expect для автоматизации рутинных процессов, таких как конфигурирование и backup сетевого оборудования.
Затем работал как Linux/Unix-администратор в аутсорсинговых компаниях, делал виртуализацию на VMware/KVM/OpenVZ. Как раз в то время сильно прокачал скилы в Bash и даже сделал на нём клон DynDNS, чтобы бесплатно управлять корпоративными доменными адресами. Взял Bash, написал CGI script, uwsgi, Nginx, Bind9 — слепил всё вместе, посмотрел на этого монстра и подумал: «Доколе!». Монстр работал, но был сложночитаемым. Тогда я понял, что пора учить нормальный язык программирования, и стал осваивать Python.
В начале десятых я работал в Thumbtack, где на поддержке было много сервисов и требовалась автоматизация. Ansible и прочих подобных решений ещё не было или они только начинали появляться, поэтому автоматизацию мы писали на смеси Shell и Python с использованием таких библиотек, как Fabric.
После Thumbtack был хостинг-провайдер, и там я участвовал в создании внутреннего API выделения ресурсов для клиентов. Активно использовал Python и Ruby. Ruby — как основной DSL-язык для Chef. Python — как основной язык разработки. Так постепенно я зашёл в системную разработку.
Когда мне предложили стать системным разработчиком, я сказал: «Ребята, я не умею в C и не пишу Kernel-модули». Мне ответили: «Не, это Python». Оказалось, что термин системная разработка используется не только тогда, когда речь идёт о разработке ядер, но ещё и когда говорят о разработке системы связей компонентов инфраструктуры. Этим я и стал заниматься.
Расскажу о нескольких кейсах, когда умение программировать в целом и знание Python в частности помогло решить задачи эксплуатации или DevOps. В реальной практике их, конечно, было гораздо больше.
Кейс 1. Анализ затрат на инфраструктуру
После хостинг-провайдера я устроился в AdTech-проект уже как DevOps. Надо было не только заботиться об инфраструктуре, но ещё писать деплои, CI/CD-пайплайны и прочее. Часть конфигурации была на Ansible, в то время ещё зелёном, поэтому приходилось и туда что-то дописывать самому.
Тогда же я написал решение для анализа затрат на инфраструктуру. У нас было несколько команд, и каждая могла заказать ресурсы в AWS или Webazilla.
Проблема. Люди не помнили, сколько и на что ресурсов они запросили. Возникла идея проекта, под неё заказали серверы, пока серверы получили — проект делать передумали. От проекта отказались, а ресурсы высвободить забыли. Или другая история: проект логически закончился, инфраструктура пустует. Ещё бывало, что заказывали сервер размером со слона, когда хватило бы небольшой виртуальной машины.
Каждый такой случай обходился компании дорого. Одни сервер мог стоить 300 евро в месяц. Выделили с десяток и забыли — 3000 евро в месяц в никуда. Проанализировать расходы по биллингу AWS или Webazilla не получалось: они давали статистику по серверам, а нам надо было по проектам.
Решение. Я сделал такую систему: к каждому ресурсу (серверу или виртуальной машине) мы добавляли комментарий, где указывали ключ-значение (лейблы) — кто заказал, кто использует, технические детали. Затем я запрашивал API провайдеров, получал список item'ов и собирал данные в таблицу. Для этого я написал внутренний интерфейс на Python.
Парсилка возвращала готовые объекты, объект составлялся из запросов в Webazilla или AWS. Там были стандартные поля, и на их основе делались все группировки. Для отображения в веб-интерфейсе я использовал такие библиотеки, как Datatable и Google Chart’s. Сама библиотека не для Python, но в Python я делал JSON, отправлял в сторону браузера, и в браузере всё это рисовалось.
Кроме того, я использовал данные от Chef. Chef хранит всю информацию о каждом инстансе, на котором установлен: о дисках, материнской плате, MAC и IP адресах, ядрах, общей загрузке системы и т. д. Всё это может быть очень полезно, но удобного интерфейса для чтения нет. Я взял Python-библиотеку для работы с Chef, прикрутил, выскреб все данные и тоже представил в виде таблицы. Можно было искать и сортировать по любому полю — получилось удобно.
Всё это я писал примерно день в неделю в течение пары месяцев. Сложность была в том, что Webazilla не давала описания API. Фактически мне пришлось делать реверс-инжиниринг, чтобы понять, как вытаскивать данные.
Тогда же я с удивлением узнал, что некоторые разработчики API интерфейсов DNS-провайдеров делают деструктивные операции через get (при том, что Rest API как концепция существует много лет). Это небезопасно и очень неудобно для пользователей. Видимо, они вообще не задумывались, как их API будут эксплуатировать — наглядный пример из серии «программировать не равно разрабатывать». Я тогда просто сделал библиотеку, которая позволяла получать нужные данные, не задумываясь о странностях чужого API.
Результат. Когда появилась таблица с разбивкой ресурсов по проектам, мы стали видеть, что загрузка сервера низкая или совсем отсутствует. Тогда могли прийти в команду и сказать: «Хотите сэкономить половину вашего бюджета? Пожалуйста, освободите серверы, мы их вернём провайдеру». Это заметно сократило общие затраты компании на инфраструктуру.
А за счёт доступа к данным от Chef команда эксплуатации сэкономила время. Вместо того чтобы делать отчеты вручную, ходя ручками на каждый сервер по SSH, мы все нужные данные могли получить из таблицы в веб-интерфейсе. Нужно заменить серверы какой-то версии — пожалуйста: делаешь фильтр, и список оборудования на замену готов.
При желании эту систему можно было усовершенствовать. Chef позволяет не только писать, но и читать, и если основную версию приложения хранить в bucket, то через веб-интерфейс можно сказать: «Есть серверы с такой-то ролью, в этой роли есть версия. Поменяй версию a на версию b». В то время Kubernetes не было, не было и Spinnaker, поэтому подобное решение могло выручить.
Кейс 2. Разработка планировщика
Из AdTech-проекта я перешёл в компанию Bright Computing, и снова на позицию системного разработчика. Компания делала софт для построения облаков — Cluster Manager.
Проблема. Софт писали на C++ (мышки плакали, кололись, но продолжали жрать кактус). При этом дистрибутивов, которые надо было поддерживать, появлялось всё больше, и сборочная матрица оказалась достаточно обширной. К тому же собирать нужно было почти все версии продукта: софт продавался по lifetime-лицензии, она привязывалась к MAC-адресу сервера, и пока сервер был жив, мы его поддерживали.
Мне нужно было создать инструмент, который бы всю эту систему собирал вместе. До этого там был билдер, но он работал sequentially (последовательно) на одном сервере. Сборка занимала до нескольких дней и требовала несколько сборочных серверов.
Решение. Я написал новую систему сборки. Она состояла из API-сервера и планировщика сборки.
API-сервер хранит данные о пакете, а также о его build и install-зависимостях — для разных архитектур и операционных систем они разные. Я сделал матрицу из всех поддерживаемых версий, из всех поддерживаемых дистрибутивов, под все поддерживаемые архитектуры. В том числе старые версии Red Hat, Scientific Linux, OpenSUSE, Ubuntu. Причем не только под x86 и x64, но и ещё под две новые архитектуры — ppc64le/POWER8 от IBM и ARM64.
Отдельной интересной задачей было придумать структуру YAML-файла, который включал бы основную конфигурацию и специальные конфигурации для разных ОС и архитектур. Когда структура была продумана, очень много времени ушло на конвертацию build-листов из XML в YAML. Эта задача оказалась труднее, чем может показаться на первый взгляд, потому что XML был неконсистентен, а ещё зависимости приходилось добавлять вручную — пока не сломается, не узнаешь, что чего-то не хватало.
Планировщик сборки я написал на Python. Очень пригодился механизм тредов — он позволил запараллелить запросы к API-серверу на предмет зависимостей. Как всё работает: планировщик читает build-лист, собирает очередь на сборку, сверяет зависимости, затем создает Job и отправляет пакет на Jenkins, Jenkins запускает воркер, который принимает метаданные как параметры, выкачивает себе на основе id все зависимости, ставит их, компилирует программу и отправляет дальше.
Чтобы всё заработало, пришлось дописать несколько модулей для Jenkins: адаптировать его под работу с ppc64le и ARM64 (без этого бинарник, собранный для x86 архитектуры, просто не запускался), а также научить отдавать статусы запланированных задач (по умолчанию Jenkins ничего не возвращает, просто «200» и всё). Тут уже я использовал Java.
На создание всей системы ушло около года.
Результат. Компания получила инструмент, который сэкономил много времени на сборку конечного продукта. Теперь не нужно было собирать больше суток в sequentially-режиме какой-то build. Не нужно было запускать сборку параллельно на гигантском количестве серверов.
С точки зрения бизнеса результат можно сформулировать так: повышение скорости фикса багов в продукте, увеличение скорости доставки новых фич, снижение времени, когда команда QA простаивает в ожидании новой сборки, снижение затрат на оборудование. Плюс конфигурировать build-листы в YAML намного приятнее, чем в XML.
Кейс 3. Мониторинг серверов Elasticsearch
Эта история из другой компании, которая занимается стримингом больших данных (около полумиллиона вставок в секунду в Elasticsearch).
Проблема. Для мониторинга Elasticsearch-серверов использовали сервис Telegraf от influxData, но он выводил далеко не всю информацию, которая нас интересовала. Можно было узнать, зелёный инстанс, жёлтый или красный. А вот что происходит на уровне шардов (наименьший блок данных в Elasticsearch), понять было невозможно. Telegraf такой информации не давал.
Зачем опускаться на уровень шардов? Чтобы выяснить, что не так с индексом. Индекс — это сущность, которая не привязана к серверу. К серверу привязываются шарды. Предположим, кто-то начал интенсивно писать на диск, чтение или запись индекса на этом диске замедлилась. Что делать? Мигрировать. Но кого и куда? Из мониторинга этого не понять, надо идти в Kibana или консоль, опрашивать API Elasticsearch, находить шарды проблемного индекса и тогда уже что-то с ним делать. Не самый удобный путь.
Решение и результат. Я написал на Python экспортёры для Prometheus, которые собирали все необходимые данные. На основе этих данных мы уже настроили группу дашбордов и алёрты (алёрты были привязаны к размеру шард).
В результате получилась таблица, на основе которой можно было тюнить пайплайны. Мы могли видеть, что где-то вставляется три терабайта данных в час, и принимать решение: либо разбивать дневной индекс на часовые, либо увеличивать количество шардов внутри индекса так, чтобы они укладывались между 30 и 50 мегабайтами на шард.
Глобально это позволило нам эффективнее мониторить приложения и свести к минимуму простой платформы.
Где ещё пригодится умение программировать
Возможно, мои кейсы покажутся вам редкими, но это потому, что сейчас я работаю над большими проектами, где системное администрирование сливается с системной разработкой. В небольших компаниях тоже есть задачи, решение которых можно автоматизировать:
- бэкапы,
- мониторинг,
- анализ входящих логов,
- безопасность,
- CI/CD.
Возьмём безопасность. Например, кто-то организовал DDoS-атаку на ваш интернет-магазин. С помощью Python можно проанализировать логи балансера и понять, кого стоит заблокировать и на каком уровне.
В настройке CI/CD тоже может пригодиться Python: можно делать нотификации, алёрты в Slack, изменения DNS-записей. Любую динамическую инфраструктуру (если чего-то нет в продукте, который ты используешь), можно написать на Python достаточно легко и быстро.
Ещё одно применение — тесты конфигурации. Есть мнение, что 20% времени системный администратор тратит на настройку, а 80% — на дебаг. Так вот эти 80% можно сильно сократить, если избежать misconfiguration. А сделать это как раз и позволяют тесты конфигурации, написанные на Python.
При этом я не говорю, что вообще все задачи надо автоматизировать. Надо считать часы и деньги: сколько тратишь денег в год, сколько денег уйдёт на разработку автоматизации. Что будет эффективнее, то и выбираешь.
Python — это мастхев
Мир движется в сторону noOps. Активно развиваются облачные провайдеры, всё становится более автоматизированным. И сервера, как pets, в большинстве случаев пропадут. Поэтому чтобы развить себя как инженера, уметь программировать необходимо. Python — это мастхев.
У Python понятный синтаксис, разрабатывать на нём быстро. В Python есть куча инструментов динамической отладки, тот же IPython. Стартовать с него легко. А если не прокачиваться в программировании, работы не останется — нечего будет кушать. Либо будет работа в очень маленьких компаниях с маленькой зарплатой, либо ничего.
Если не встанешь на ступеньку выше, не научишься работать с инфраструктурой на уровне кода, то ты вымрешь, как вымерли операторы пейджера. Это эволюция, так работает мир.
Узнать больше о курсе Python для инженеров и записаться