Управляем кластером на Tarantool из командной строки / Блог компании Mail.ru Group / Хабр

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

Source link

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

Ваш адрес email не будет опубликован.