Управляем кластером на Tarantool из командной строки

от автора

Два года назад мы уже рассказывали вам, что такое Cartridge и как с его помощью разрабатывать распределенные приложения. Это полноценный фреймворк, в который входит CLI-интерфейс, который сильно упрощает разработку и эксплуатацию приложений на Tarantool Cartridge.

Я расскажу вам, как можно использовать Cartridge CLI для эффективного использования ваших локальных приложений, и об интересных фичах самого CLI. Статья больше ориентирована на тех, кто уже использует Cartridge или хочет начать им пользоваться. Поехали!

Какие проблемы решает Cartridge CLI?

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

С чего начать?

Вы захотели использовать Cartridge. Первая мысль, которая возникает в вашей голове: «Как мне запустить мое приложение?» Как минимум, вам нужно реализовать точку входа. Но при этом вы решите лишь часть проблемы — дальше нужно будет понять, как вообще запускать приложение.

Cartridge CLI содержит готовый шаблон приложения. В этом шаблоне есть все необходимые файлы (и не только) для того, чтобы запустить и сконфигурировать ваш кластер. Вам не нужно думать, какие файлы создать в проекте, что они должны из себя представлять и так далее. Кроме того, в стандартный шаблон легко вносить изменения в соответствии с вашими нуждами.

Сборка, запуск и настройка приложения

Приложение нужно собрать: как минимум — поставить сам Cartridge (он устанавливается как отдельный Lua-пакет), а как максимум — еще десяток зависимостей в виде Lua-пакетов (и не только), которые используются в вашем приложении. Конечно, вы можете написать свой скрипт, который будет собирать приложение за вас, и использовать его в каждом вашем приложении. Но зачем всякий раз придумывать велосипед?

Допустим, приложение вы успешно собрали. Теперь вы хотите локально запустить экземпляры и сконфигурировать приложение: создать наборы реплик, выставить им роли и так далее… В Cartridge CLI есть всего три команды, с помощью которых можно выполнить вышеуказанные действия в одну строчку: собрать, запустить и настроить ваше приложение.

Настройка набора реплик и failover

Да, управление через GUI нельзя называть проблемой. Для кого-то, может быть, это будет плюсом. Но я всё равно решил выделить как отдельное преимущество Cartridge CLI, и сейчас объясню почему:

  • Для того, чтобы сконфигурировать кластер через GUI, нужно зайти в браузер и сделать N кликов. Чтобы сделать то же самое с помощью CLI, достаточно ввести одну команду. Как минимум, это экономия времени.
  • Если вы решите сбросить конфигурацию кластера в GUI и заново настроить его, то всё придется повторить — сделать еще N кликов вместо вызова одной команды.
  • Вы можете однажды собрать минимальную конфигурацию кластера, сохранить её в файл и закоммитить в репозиторий. После этого кто угодно (в том числе и вы при каждом перезапуске кластера) сможет поднимать настроенный кластер одной командой.
  • Может быть, вам просто совсем не нравится пользоваться GUI.

Упаковка приложения

Представьте, что вы написали приложение и хотите отправить его клиенту в формате rpm-пакета. Сначала вам нужно будет описать файл .spec, установить (например) утилиту rpmbuild, и только после этого начать сборку пакета. Утомительно, не правда ли?

В Cartridge CLI процесс упаковки приложения унифицирован, содержит основные формы упаковки приложения (deb, rpm, tgz и Docker image) и много упрощающих этот процесс опций. Всё это позволяет не думать об упаковке в принципе, а просто вызвать одну команду с удобным интерфейсом.

Создаем и запускаем первое приложение

Для начала нам потребуется установить Cartridge CLI.

Установка на Debian или Ubuntu:

curl -L https://tarantool.io/IMYxqhi/release/2.7/installer.sh | bash sudo apt install cartridge-cli 

Установка на CentOS, Fedora или ALT Linux:

curl -L https://tarantool.io/IMYxqhi/release/2.7/installer.sh | bash sudo yum install cartridge-cli 

Установка на MacOS:

brew install cartridge-cli 

Чтобы убедиться в успешной установке введите команду:

cartridge version 

В случае, если всё прошло успешно, вы увидите следующее сообщение:

Не обращайте внимание на предупреждение, ведь проект мы еще не создали (и, соответственно, не установили сам Cartridge).

Команда cartridge create создает приложение с использованием стандартного шаблона приложения на Cartridge:

cartridge create --name myapp && cd myapp 

Стандартный шаблон приложения содержит файлы:

### Файлы приложения ├── README.md ├── init.lua ├── stateboard.init.lua ├── myapp-scm-1.rockspec ├── app │   ├── admin.lua          │   └── roles              ### Сборка и упаковка ├── cartridge.pre-build ├── cartridge.post-build ├── Dockerfile.build.cartridge ├── Dockerfile.cartridge ├── package-deps.txt ├── systemd-unit-params.yml ### Локальный запуск приложения ├── instances.yml ├── replicasets.yml ├── failover.yml ├── .cartridge.yml ├── tmp ### Тестирование ├── deps.sh ├── test │   ├── helper.lua │   ├── integration │   └── unit 

Если вам не нравится стандартный шаблон приложения, то можете создать свой шаблон и использовать его:

cartridge create --from mytemplate --name mycustomapp && cd mycustomapp 

В корне проекта сразу инициализируется локальный Git-репозиторий, который уже содержит первый коммит:

Чтобы запустить экземпляры, соберем наше приложение:

cartridge build 

Сборка выполняется с помощью утилиты tarantoolctl: она устанавливает все необходимые зависимости, в том числе Cartridge. Зависимости описаны в файле myapp-scm-1.rockspec. Если в вашем проекте понадобилась еще какая-либо зависимость, отредактируйте файл .rockspec, поместив зависимость туда, и введите команду cartridge build.

Проект содержит файл cartridge.pre-build: он запускается перед установкой зависимостей. Например, вы можете установить нестандартные модули rocks с помощью той же tarantoolctl:

#!/bin/sh tarantoolctl rocks make --chdir ./third_party/my-custom-rock-module 

Проверим, что проект был успешно собран и все зависимости установлены:

На экране появилась информация о версии Cartridge и список rocks проекта — информация о них выводится на экран, если указан флаг --rocks.

В файле instances.yml можно сконфигурировать ваши экземпляры (имя, порт и так далее). Описание должно быть в формате <имя-приложения>.<имя экземпляра>. Стандартый шаблон приложения уже содержит этот файл:

myapp.router:   advertise_uri: localhost:3301   http_port: 8081  myapp.s1-master:   advertise_uri: localhost:3302   http_port: 8082  myapp.s1-replica:   advertise_uri: localhost:3303   http_port: 8083  myapp.s2-master:   advertise_uri: localhost:3304   http_port: 8084  myapp.s2-replica:   advertise_uri: localhost:3305   http_port: 8085 

Чтобы запустить описанные в этом файле экземпляры, используйте команду cartridge start:

cartridge start -d  # убедимся, что все инстансы приложения были успешно запущены cartridge status 

Не обязательно запускать сразу все экземпляры. Можно, например, запустить лишь один s1-master:

cartridge start s1-master -d  cartridge status s1-master 

Точкой входа в наше приложение является файл с именем init.lua. Именно он под капотом запускает cartridge start.

Стандартный шаблон приложения в своём корне содержит папку tmp.

  • tmp/run — директория, хранящая PID процессов-экземпляров и socket-файлы;
  • tmp/data — директория, хранящая данные экземпляров;
  • tmp/log — директория, хранящая логи экземпляров.

Вы можете изменить стандартные пути к вышеописанным директориям, указав новые пути в файле .cartridge.yml или с помощью флагов команды cartridge start. Чтобы запустить экземпляры в фоновом режиме, используйте флаг -d. В таком случае логи будут сохраняться в файл и мы сможем их посмотреть с помощью команды cartridge log:

С помощью флага --stateboard или настройки stateboard: true в файле конфигурации .cartridge.yml вы можете также запустить изолированный экземпляр Tarantool, который можно будет использовать в качестве поставщика состояний для failover. Я предлагаю всегда запускать экземпляр stateboard (в дальнейшем его можно использовать для настройки failover), поэтому стандартный шаблон приложения уже содержит флаг stateboard: true. При необходимости вы можете безболезненно убрать этот флаг из файла конфигурации.

Настраиваем топологию

Команда cartridge replicasets позволяет выполнять различные действия по изменению топологии кластера (например, из конфигурационного файла) и сохранять конфигурацию кластера в файл. Созданный командой cartridge create шаблон приложения содержит файл replicasets.yml, с помощью которого мы можем сконфигурировать базовую топологию нашего кластера:

cartridge replicasets setup --bootstrap-vshard # убедимся, что топология была успешно настроена cartridge replicasets list 

Всё! Одной командой мы настроили топологию, а также включили шардирование. Круто, не правда ли? Рассмотрим файл replicasets.yml подробнее:

router:   instances:   - router   roles:   - failover-coordinator   - vshard-router   - app.roles.custom   all_rw: false s-1:   instances:   - s1-master   - s1-replica   roles:   - vshard-storage   weight: 1   all_rw: false   vshard_group: default s-2:   instances:   - s2-master   - s2-replica   roles:   - vshard-storage   weight: 1   all_rw: false   vshard_group: default 

В нем содержится три набора реплик с именами router, s-1 и s-2.

  • instances — в этом блоке описаны экземпляры, которые содержит каждый из набора реплик. Имена экземпляров должны совпадать с именами, которые описаны в instances.yml.
  • В блоке roles описаны роли для каждого набора реплик;
  • weight — vshard-вес набора реплик.
  • all_rw — флаг, указывающий, что все экземпляры в наборе реплик должны быть доступны как для чтения, так и для записи.
  • vshard_group — имя группы vshard, к которой принадлежит набор реплик.

Если вдруг вам захотелось настроить всё это в ручную (без использования конфига replicasets.yml), то можете воспользоваться другими опциями cartridge replicasets:

# объединим экземпляры s1-master и s1-replica в набор реплик s-1: cartridge replicasets join --replicaset s-1 s1-master s1-replica # добавим реплику router: cartridge replicasets join --replicaset router router # посмотрим текущие доступные роли и выберем из них подходящие для каждой из реплик: cartridge replicasets list-roles # добавим роль vshard-storage для набора реплик s-1: cartridge replicasets add-roles --replicaset s-1 vshard-storage # также добавим роли для реплики router: cartridge replicasets add-roles \   --replicaset router \   vshard-router app.roles.custom failover-coordinator metrics # и наконец забутстрапим vshard: cartridge replicasets bootstrap-vshard # посмотрим конфигурацию набора реплик: cartridge replicasets list 

Сбросить заданную конфигурацию кластера можно с помощью следующих команд:

cartridge stop cartridge clean 

Настраиваем failover

После конфигурации топологии кластера, можно настроить failover:

cartridge failover setup # посмотрим состояние failover cartridge failover status 

Команда cartridge failover setup использует конфигурацию, описанную в файле failover.yml, который находится в корне созданного приложения.

mode: stateful state_provider: stateboard stateboard_params:   uri: localhost:4401   password: passwd 

У failover может быть три состояния: eventual, stateful и disabled:

  • eventual и disabled не требуют никаких дополнительных настроек;
  • stateful требует указания поставщика состояний (поле state_provider) и указания параметров для этого поставщика. На данный момент поддерживаются поставщики stateboard и etcd2.

Подробнее об архитектуре failover вы можете прочитать здесь. А здесь вы можете прочитать о всех параметрах, которые вы можете указать при его конфигурации. Вы также можете использовать команду cartridge failover set для ввода настроек failover прямо в командной строке:

cartridge failover set stateful \   --state-provider etcd2 \    --provider-params '{"lock_delay": 15}' 

Для отключения failover используйте следующие команды:

cartridge failover disable # или cartridge failover set disabled 

Подключаемся к экземплярам

Вам вдруг понадобилось подключиться экземпляру и ввести там интересующие вас команды, например, выполнить cartridge.reload_roles()? Легко!

С помощью cartridge enter вы можете подключиться к экземпляру через консольный сокет, размещенный в run-dir. Никаких дополнительных параметров не нужно, достаточно ввести имя экземпляра, указанного в instances.yml:

cartridge enter instance-name 

Вы также можете использовать cartridge connect для подключения к интересующему вас экземпляру. Отличие этого подхода в том, что вы можете указать адрес экземпляра или путь к UNIX-сокету.

cartridge connect localhost:3301 \   --username admin \   --password secret-cluster-cookie # либо cartridge connect admin:secret-cluster-cookie@localhost:3301 

Упаковываем приложение

Для упаковки приложения есть команда cartridge pack <tуpe>. На данный момент поддерживается четыре варианта упаковки:

  • deb — deb-пакет;
  • rpm — rpm-пакет;
  • tgz — tgz-архив;
  • docker — Docker-образ.

Например, для упаковки вашего приложения в tgz-архив используйте следующую команду:

cartridge pack tgz 

Хотите собрать rpm- или deb-пакет, но при этом используете MacOS? Вы не можете сделать это просто так: в упакованном приложении будут rocks и исполняемые файлы, которые нельзя использовать в Linux. Специально для такого случая существует флаг --use-docker, который собирает в Docker:

cartridge pack deb --use-docker 

Помимо --use-docker, команда cartridge pack имеет множество других полезных опций. Рассмотрим самые интересные из них.

Добавляем зависимости в пакет

Добавим в наш rpm- или deb-пакет какую-нибудь зависимость. Например, unzip:

cartridge pack deb --deps unzip>=6.0 

Либо вы можете описать зависимости для вашего пакета в файле package-deps.txt, который уже находится в корне созданного приложения:

unzip==6.0 neofetch>=6,<7 gcc>8 

Теперь, упаковав приложение с помощью команды cartridge pack deb, ваш пакет будет содержать зависимости unzip, neofetch и gcc. Вы можете использовать файл с другим именем для указания ваших зависимостей с помощью флага --deps-file:

cartridge pack rpm --deps-file=path-to-deps-file 

Добавляем сборочные сценарии до (и после)

А что если во время упаковки вам нужно создать файл, папку, поставить какую-либо утилиту — то есть внести какие-либо изменения в сценарий упаковки приложения? Для этого используются файлы preinst.sh и postinst.sh.

Все пути к исполняемым файлам в сценариях до и после установки должны быть абсолютными. Либо используйте /bin/sh -c '':

/bin/sh -c 'touch file-path' /bin/sh -c 'mkdir dir-path' 

С помощью флагов --preinst и --postinst вы можете использовать файлы с любым именем:

cartridge pack rpm \   --preinst=path-to-preinst-script \   --posints=path-to-posinst-script  

Сценарии работают только для сборки rpm- и deb-пакетов.

Кешируем пути

При каждом запуске упаковки приложение собирается с нуля. Например, сборка всех зависимостей (т.е. rocks) начинается заново. Чтобы этого избежать (и уменьшить время переупаковки приложения), существует опция кеширования путей и файл pack-cache-config.yml:

- path: '.rocks':   key-path: 'myapp-scm-1.rockspec' - path: 'node_modules':   always-cache: true - path: 'third_party/custom_module':   key: 'simple-hash-key' 

Рассмотрим подробнее параметры конфигурационного файла:

  • path — путь от корня проекта до кешируемого пути;
  • key-path — путь до файла, содержимое которого будет ключом кеширования. В примере выше для пути .rocks ключом кеширования является файл myapp-scm-1.rockspec — если изменить его, то cache hit не произойдет и все rocks приложения будут собираться заново;
  • always-cache — кеширование указанного пути всегда, независимо от каких-либо ключей;
  • key — простой ключ кеширования в виде строки.

В стандартном шаблоне приложения уже содержится один кешируемый путь:

- path: '.rocks'   key-path: myapp-scm-1.rockspec 

Я предлагаю всегда кешировать содержимое папки .rocks опираясь на содержимое файла .rockspec. Для одного пути может быть только один кеш. Например, у вас в кеше находится папка .rocks, вы меняете ключ и запускаете упаковку приложения. В этот момент старый кеш .rocks удаляется и заменяется новым на основе нового ключа.

Чтобы отключить кеширование путей, используйте флаг --no-cache. С полным списком опций команды cartridge pack вы можете ознакомиться здесь.

Подробнее о процессе упаковки

Команда cartridge pack помимо упаковки приложения в пакет ещё и собирает его (аналогично команде cartridge build). По умолчанию сборка выполняется во временной директории ~/.cartridge/tmp. Вы можете изменить её на свою, установив значение переменной окружения CARTRIDGE_TEMPDIR:

  • Если эта директория не существует, она будет создана и использована для сборки приложения, а затем удалена.
  • В противном случае сборка будет выполнена в директории CARTRIDGE_TEMPDIR/cartridge.tmp.

Создание временной директории (в которой будет выполняться сборка) с исходными файлами вашего приложения происходит в три этапа:

  1. Копирование файлов во временную директорию и её очистка. Папка с приложением копируется во временную директорию, выполняется команда git clean -X -d -f для удаления неотслеживаемых файлов и удаляются папки .rocks и .git.
  2. Сборка приложения в очищенной директории.
  3. Запуск скрипта cartridge.post-build (если он существует).

В корне проекта находится файл cartridge.post-build. Это скрипт, основная цель которого — удаление артефактов сборки из результирующего пакета. После сборки приложения во временной директории генерируются специальные файлы, такие как VERSION и VERSION.lua, которые содержат версию приложения. В случае сборки в rpm и deb инициализируются директории systemd и tmpfiles. Далее приложение упаковывается.

Подробнее о структуре и дальнейшей работе с полученными rpm- и deb-пакетами вы можете прочитать здесь. А здесь — про работу с Docker-образами.

Итоги

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

Cartridge CLI имеет еще одну команду, о которой я не рассказал в этой статье. Команда cartridge admin призвана упростить разработчикам написание и поддержку эксплуатационных кейсов, повысить переиспользование операций, оптимизировать поставку в эксплуатацию. Почитать подробнее об этом вы можете в этой статье.

Если у вас что-то вдруг пошло не так, или вы знаете, как можно улучшить продукт, то всегда можете завести тикет в нашем GitHub-репозитории. Мы всегда поможем с решением вашей проблемы и будем рады интересным предложениям!


ссылка на оригинал статьи https://habr.com/ru/articles/571936/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *