Как стать автором
Обновить
VK
Технологии, которые объединяют

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

Время на прочтение11 мин
Количество просмотров4.9K


Два года назад мы уже рассказывали вам, что такое 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-репозитории. Мы всегда поможем с решением вашей проблемы и будем рады интересным предложениям!
Теги:
Хабы:
+24
Комментарии10

Публикации

Информация

Сайт
team.vk.company
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия
Представитель
Руслан Дзасохов