Pull to refresh
139.56

Как мои пальцы закровоточили, и я собрал велосипед для деплоя, который сэкономил больше 2 тысяч рабочих часов за проект

Reading time 12 min
Views 25K
«Денис, ты теперь инженер по развёртыванию». Офигеть, дайте две. В общем, я работаю в КРОК, который славится огромными проектами. В этом проекте мы поддерживали внедрение гигантской аналитической системы класса data lake для нескольких тысяч пользователей объёмом 150 ТБ. Пилят её несколько команд разработки, в общей сложности примерно 40 человек.

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



Разработчики пишут код, который сливается в репозиторий. Из него Jenkins рождает сборки, которые выкладывает на шару. Развёртывание системы с нуля первый раз у меня заняло 4 часа 15 минут по таймеру. Для каждого из порядка десяти компонентов (скрипты разных БД, Tomcat-овские приложения и т. д.) в нужном порядке надо было взять файл с шары, разобраться, где и в скольких экземплярах его нужно развернуть, поправить настройки, указать, где ему искать другие компоненты системы, связать всех со всеми и ничего не перепутать.

Пальцы закровоточили — начал скриптовать. Началось с одного маленького скрипта.

Что было


Система состоит из довольно большого числа компонентов: 6 разных приложений на Томкате, каждое из которых в нескольких экземплярах на разных серверах, кластер DSE = Cassandra + Solr + Spark, скрипты создания объектов в них, загрузка начальных данных, миграции схем Oracle, PostgreSQL, кластер RabbitMQ, балансировщики нагрузки, куча внешних систем и так далее.

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

Итого, развернуть такую систему — много серверов и много компонентов с разными и часто меняющимися конфигами, в которых они желают иметь информацию друг о друге, расположении баз данных, внешних систем и т. д. и т. п. Таким образом, развернуть всё, где нужно, ничего не забыть, не перепутать и правильно сконфигурировать — задача не совсем тривиальная. Мест, где можно сделать ошибку, много, и процесс требует внимания и концентрации. Сначала я скриптовал маленькие части, доставлявшие наибольшее число проблем. Освободившееся время тратил на следующие по злобности моменты, объединение и обобщение.

В итоге получилось, что для каждого кусочка системы был готов один shell-скрипт, который делал всё — от копирования дистрибутива из jenkins-а до правки конфигов и развёртывания приложения или выполнения обработанных скриптов на базе данных. В общем, начиналось всё, как классический админский велосипед: те же скрипты, которые пишут почти все для себя из кирпичиков. Разница в том, что мы решили сделать эти части взаимозаменяемыми и сразу (ладно, через месяц, а не сразу) задумались о структуре. В итоге это сначала стало системой скриптов, где всё довольно гибко конфигурируется (снаружи), а потом появился ещё и web-GUI.

У меня для каждого стенда и для каждого компонента системы уже были готовы скрипты, выполняющие нужные действия. Но появлялись новые стенды, имеющиеся изменялись, разработка системы двигалась семимильными шагами, и отражать все изменения в скриптах было всё сложнее.

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

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



Конфиг — это просто страшноватый текстовый файл, в котором содержится список переменных и их, собственно, значений. Скрипты просто source-ят этот файл и получают все настройки в переменных окружения (на самом деле сейчас стало немного сложнее, но именно немного).

Вот он
#BUTTON_DESC=DSE 4.7JDBC thin<br>Двебуквы
# include "defaults.include"

BUILD_DIRS="data-facade/release-1.5.0:DATA_FACADE,SOMEAPP process-runner/release-1.5.0:PROCESS_RUNNER integration-services/release-1.5.0:INTEGRATION scripts/release-1.5.0:CASS_DDL,ORA_DDL,SOLR_SCHEMA fast-ui/release-1.5.0:FAST_UI cache-manager/release-1.5.0:CACHE_MANAGER"

DSE_HOSTS="xxxdevb.lab.croc.ru xxxdevc.lab.croc.ru xxxdevd.lab.croc.ru xxxdeve.lab.croc.ru"
CASSANDRA_CONNECTION_HOSTS="xxxdevb.lab.croc.ru xxxdevc.lab.croc.ru xxxdevd.lab.croc.ru xxxdeve.lab.croc.ru"
CASS_DDL_NODE="xxxdeve.lab.croc.ru"
SOLR_URL="http://xxxdeve.lab.croc.ru:8983/solr"

ORA_DATABASES="xxxdevg.lab.croc.ru:1521/test"
ORA_CONN_STRING="jdbc:oracle:thin:@xxxdevg.lab.croc.ru:1521/test"
ORA_OPSTORE_PW="###"

ORACLE_HOSTS="DEVG"
DEVG_ADDR="xxxdevg.lab.croc.ru"
DEVG_INSTANCES="TEST"
DEVG_TEST_SID="test"

PG_SERVER="xxxdeva.lab.croc.ru"

DATA_FACADE_HOSTS="xxxdevb.lab.croc.ru"
SOMEAPP_HOSTS="xxxdevb.lab.croc.ru"
PROCESS_RUNNER_HOSTS="xxxdeva.lab.croc.ru"

PP_PROXY_PROCESS_RUNNER_URL="http://xxxdeva.lab.croc.ru:8080/xxx-process-runner"
XX_API_URL="http://#.#.#.#/###/api/"

CASS_DDL_ADD_BOM="yes"
CASS_DDL_TEST_SEED="yes"

KEYSPACE=xxx
REPLICATION_STRATEGY="{'class':'NetworkTopologyStrategy', 'Solr':3}"
CATALINA_HOME=/usr/share/apache-tomcat-8.0.23

CASS_DDL_DISTR_NAME="cass-ddl.zip"
SOLR_DISTR_NAME="solr-schema.zip"
DATA_FACADE_TARGET_WAR_NAME="data-facade.war"
SOMEAPP_DISTR_PATTERN='rest-api-someapp-*-SNAPSHOT.war'
SOMEAPP_TARGET_WAR_NAME="someapp.war"
PROCESS_RUNNER_TARGET_WAR_NAME='xxx-process-runner.war'
PROCESS_RUNNER_DISTR_PATTERN='resources/distr/xxx-process-runner.war'
PROCESS_RUNNER_RESOURCES_DISTR_DIR="resources"

CASS_REQ_FETCHSIZE=100
CASS_REQ_BATCHSIZE=10
CASS_REQ_MAX_LOCAL=2
CASS_REQ_MAX_REMOTE=2
CASS_REQ_CONSISTENCY_LEVEL="LOCAL_QUORUM"

INTEGRATION_AD_SEARCH_NAME="OU=TOGS, DC=testxxxx,DC=local;OU=GMC,DC=testxxxx,DC=local;OU=CA,DC=testxxxx,DC=local"
INTEGRATION_LDAP_PROVIDER_ADDRESS="#.#.#.#"
INTEGRATION_LDAP_PROVIDER_PORT="389"
INTEGRATION_LDAP_SECURITY_PRINCIPAL='testxxxx\\\\lanadmin'
INTEGRATION_LDAP_SECURITY_CREDENTIALS='СЕКРЕТЖИ!'
INTEGRATION_AD_ROOT_DEPARTMENT="DC=testxxxx,DC=local"

SSTABLELOADER_OPTS=""
CASS_REQ_QUEUESIZE=1

OSR_URL=http://#.#.#.#/SPEXX

QUEUE_HOST="xxxdevg.lab.croc.ru"
QUEUE_API_HOST="http://xxxdevg.lab.croc.ru:%s/api/"
QUEUE_ENABLE="true"

TOMCAT_HOSTS="DEVA DEVB"
DEVA_ADDR="xxxdeva.lab.croc.ru"
DEVA_CATALINA_HOMES="CH1"
DEVA_CH1_APPS="PROCESS_RUNNER"
DEVB_ADDR="xxxdevb.lab.croc.ru"
DEVB_CATALINA_HOMES="CH1"
DEVB_CH1_APPS="DATA_FACADE SOMEAPP FAST_UI CACHE_MANAGER"

CACHE_MANAGER_URL=http://xxxdevb.lab.croc.ru:8080/cache-manager/


Чтобы сделать более удобным ещё и управление конфигами стендов, позже добавил инклуды — пачки логически связанных настроек, записанных в отдельных файлах, которые можно скопом подключать к конфигам или другим инклудам. Например, настройки, связанные с AD, записаны в 5 разных переменных, а сервера AD всего два, для каждого из них сделан инклуд с этими 5 настройками. Чтобы быстро переключать стенды, между ними достаточно подключить нужный инклуд. Чтобы отразить какое-то изменение, произошедшее на сервере, надо поправить настройки в одном файле, и все нацеленные на него стенды узнают об этом.

Эта структура скриптов позже обросла свистоперделками, но в основном сохранилась.



Действия обычно выполняются пачкой — смысл имеет последовательность действий, например: на тестовом стенде сохрани НСИ, пересоздай схему в Оракле, загрузи НСИ обратно. Если предыдущий компонент отвалился с ошибкой, вероятно, надобность в следующих отпала. Чтобы было удобнее, сделан скрипт-запускалка:

./run.sh "test" "save-nsi ora-ddl-init load-nsi"

Скрипт run.sh уходит пересоздавать схему с сохранением НСИ на тестовом стенде, а инженер — пить чай.

GUI


Стало казаться, что инженер в процессе развёртывания системы нужен только для перевода слов из человеческого («разверни мне первое, второе и компот») в имена скриптов в последовательности.

Команда не очень любит unix-овую консоль, поэтому к идее запускать скрипты без инженеров отнеслись скептически. Но лень толкнула предпринять ещё одну попытку — сделал страничку из cgi скрипта на Питоне, на которой нехитрым образом можно было выбрать из списка конфиг и натыкать мышкой последовательность компонентов. Грубо говоря, просто графическую кнопку, которую можно нажать вместо консольной команды. Ей стали пользоваться.

Идея прижилась, туда стали добавляться и другие рутинные инженерные действия, перезапуск отдельных компонентов и серверов в целом, выгрузка-загрузка-сохранение информации из разных БД, управление балансировкой, включение «балета» на время даунтаймов и т. д. Прижилось и кодововое имя «Кнопка».

Это творение моих кривых рук потихоньку переделал, теперь она работает на python + flask и умеет делать всё без перезагрузки страницы: обновлять список стендов и их состояние, обновлять хвосты логов, запускать компоненты и пристреливать их, если шалят.

Коллега Андрей применил дизайнерскую магию и из месива моих чёрно-белых div-ов сделал красиво оформленную страничку.



Слева — список стендов, там выбираем стенд, с которым нужно что-то сделать. Это название стенда, которое инженеры раньше передавали в скрипт.

./run.sh "dev-letters" "save-nsi ora-ddl-init load-nsi"

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



dev-letters — это название. Ниже — краткое описание стенда от инженеров (из коммента, первой строчки конфига). Ссылки «посмотреть логи» и развёрнутые версии софтов, затем — указание, из какой ветки будут браться сборки для этого стенда. И возможность изменить эту ветку:


Все заскриптованные действия со стендами распределены по категориям и подписаны «Компоненты». Это названия действий, которые инженеры раньше передавали скриптам:

./run.sh "dev-letters" "save-nsi ora-ddl-init load-nsi"

Когда из списка выбирается компонент-действие, он попадает в правую часть страницы:



Здесь из них формируется очередь выполнения: распределяем их в нужном порядке (или добавляем в нужной последовательности). Например, на скрине будет выполнено: выгрузить nsi, пересоздать схему в Оракловой БД, загрузить nsi обратно.

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

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



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

Есть обмен данными между стендами, в частности, между Кассандрами. Можно нажать кнопочку Save data, придумать имя для архива и список таблиц, тогда данные будут заботливо сохранены. Затем можно выбрать другой стенд и загрузить их туда кнопочкой Load data, выбрав нужный архив из списка имеющихся.



Пользователи аутентифицируются через корпоративный AD. Есть простенький контроль доступа: роли, которые можно распределять пользователям, и привилегии для разных стендов, которые можно распределять ролям. Это чтобы никто из пока неопытных коллег не запустил деструктивные компоненты (пересоздание БД, например) на важных стендах.

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



Также единорог сообщает, если скрипты отвалились с ошибкой, чтобы пользователь о том, что 3-часовая заливка бэкапа срубилась после 10 минут работы, узнал сразу же, а не через 3 часа (к тому же ему не нужно будет постоянно смотреть за процессом).



Чтобы, не дожидаясь нотификаций заботливого единорога, узнать, как там идёт процесс, есть логи выполнения скриптов.



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



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

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



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

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

То есть для всех стендов оно само подключается, куда ему надо, и делает нужные вещи. А для того, где подключиться нельзя, пакует себя в чемодан, из которого по приезде на место вылезает и делает своё дело. Получается такое «отложенное выполнение»: формируются скрипты, которые нужно отнести за стенку, запустить ./run_all.sh, и начнёт происходить всё то же самое, что и с остальными стендами.

Вишенка на торте — вверху, как видите, техническая информация, в частности, дежурный инженер, его телефон, гертруда, чтобы разработчик видел, что страница реально обновилась, и всякие мелкие полезности:



Сколько времени экономит


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

Если взять типовой сценарий, который выполняется чаще других: изменилась структура БД, нужно накатить миграции и обновить (допустим, одно) приложение, затронутое обновлением, то это займёт примерно минут 30–40 в случае одного сервера.

В зависимости от количества серверов с таким приложением изменится и число операций копирования приложения на сервер и исправления кучи параметров в конфигах (+ схемы Касандры, Оракла и Солара).

Кнопка это делает самостоятельно, без промедлений и участия пользователя, нужно только выбрать желаемые шаги. Но стоит ли это всё потраченных усилий, если это нужно сделать один раз в году. Сколько действий запускается в день?

Чтобы ответить на этот вопрос, я попробовал грубо проанализировать логи запусков. Судя по первым записям в логах, мы запустили эту версию Кнопки в работу около 1 февраля 2016-го. На 10 ноября 2016-го прошло 185 дней, из них, грубо говоря, 185*5/7 = 132 рабочих дня.

Количество запусков:


[dpotapov@dpotapovl logs]$ (sum=0; for f in *.log ; do sum=$(expr $sum + $(grep "requested run" "$f" | wc -l)) ; done ; echo $sum)

22192219/132=16.8106 запусков в день.

Но каждый запуск — это целая последовательность компонентов: посчитаем, сколько их было всего:

for f in *.log ; do
grep "requested run" $f \
|sed 's/^.*\[\(.*\)\].*$/\1/' \
| while read l ; do 
for w in $l ; do
echo "$w" \
| sed 's/,$//'
done
done \
done \
> /tmp/requests.list

cat /tmp/requests.list | wc –l

[dpotapov@dpotapovl logs]$ cat /tmp/requests.list | wc –l
6442

6442/132=48.8030 компонентов в день.

Сложно точно посчитать, сколько руками мы разворачивали бы каждый компонент, но думаю, можно пальцем в небо оценить в 20 минут. Если так, то руками сделать то, что Кнопка делает в среднем за день, будет 48*20/60 = 16 часов. 16 часов работы инженера — без ошибок, косяков, залипаний в интернетах, обедов и болтовни с коллегами.

Можно ещё добавить, что Кнопка на всех стендах работает одновременно, когда это нужно пользователю. Разные пользователи на разных стендах друг другу не мешают. В случае инженера сюда следует ещё добавить время, которое упускает пользователь-заказчик, пока ждёт в очереди у инженера.

Это уже девопс?


С одной стороны — нет, потому что рутового доступа на продуктивы у наших разработчиков нет. Они не готовы его получить, потому что вместе с доступом нужно принять ответственность, а там довольно сложная инфраструктура — Инфинибэнд, Спарки, вот это всё — очень легко выстрелить себе в ногу.

С другой стороны, у нас кто-угодно-опс, потому что любой участник команды может накатить сборку на стенды, куда у него есть доступ.

Сборки на продуктив, например, чаще всего накатывает лидер группы тестирования.

Почему не докер или не другое готовое решение?

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

Начиналось как малая автоматизация. Надо было выполнить кучу скриптов БД из директории — сделал скрипт, который обходит директорию и запускает всё в ней. Потом подумалось, что круто было бы насильно конвертировать каждый скрипт в UTF, добавили эту процедуру туда же. Потом стали дописывать директивы в каждый скрипт, чтобы выставлять уровень консистентности, с которым выполнять скрипт. Потом стали из них каждого скрипта удалять пустые строки, когда поменяли версию клиента БД, и он на это плевался. И так далее.

У нас почти не было чёткого рубежа, до которого это было сборищем такой мелкой автоматизации, а после стало системой. Оно как-то само выросло, мелкими шажками. Поэтому и вопрос о том, что наверняка есть какой-то готовый продукт, встал только когда наша поделка уже решала задачу. Тогда уже получалось, что нам надо заменить что-то, что работает и закрывает вопрос на что-то, что придётся изучить и заточить под свои нужды (неизвестно какого калибра напильником).

Резюме


Вот так у нас и получился пульт управления всем сразу: в несколько кликов можно переключать заставку обслуживания, мигрировать схемы баз данных, перестраивать индексы, устанавливать новые сборки сразу с нужными настройками под стенд и без остановки работы пользователей (за счёт последовательного вывода из балансировки) — любой версии на любой стенд, перекачивать данные между стендами, смотреть за состоянием стендов и историй изменений на них.

Скрипты под капотом устроены так, что адаптировать или доработать их довольно просто, так что и другие проекты потихоньку начинают адаптировать Кнопку под себя или писать свой велосипед на основе тех же идей.

Трудно сказать, лучшим ли способом мы это всё устроили (наверняка ведь нет), но работать — работает.

Получилось сэкономить примерно 16 рабочих часов админа в день — это целых два землекопа. Так что меня теперь трое из ларца, одинаковых с лица. Если вдруг есть вопросы не для комментариев, моя почта — dpotapov@croc.ru.
Tags:
Hubs:
+41
Comments 67
Comments Comments 67

Articles

Information

Website
croc.ru
Registered
Founded
Employees
1,001–5,000 employees
Location
Россия