Версия:

Руководство пользователя / Tarantool Cartridge / Руководство разработчика Tarantool Cartridge
Руководство пользователя / Tarantool Cartridge / Руководство разработчика Tarantool Cartridge

Руководство разработчика Tarantool Cartridge

Руководство разработчика Tarantool Cartridge

Если вам необходимо быстро начать работу, можете спокойно пропустить подробное описание ниже и сразу перейти к подробному руководству по созданию Tarantool-приложения с поддержкой кластера.

Если же вы хотите всесторонне изучить возможности Tarantool Cartridge, продолжайте читать этот раздел.

Короче говоря, чтобы разработать и запустить приложение, вам необходимо выполнить следующие шаги:

  1. Установить Tarantool Cartridge и другие компоненты среды разработки.
  2. Выбрать шаблон для приложения и создать проект.
  3. Разработать приложение. Если это приложение с поддержкой кластеров, реализуйте его логику в виде отдельной (пользовательской) кластерной роли, чтобы инициализировать базу данных в кластерной среде.
  4. Развернуть приложение на сервере или серверах. Это включает в себя настройку и запуск экземпляров.
  5. Если это приложение с поддержкой кластеров, развернуть кластер.

В следующих разделах подробно описывается каждый из этих шагов.

Установка Tarantool Cartridge

  1. Установите catridge-cli – инструмент командной строки для разработки, развертывания и управления Tarantool-приложениями:

    $ tarantoolctl rocks install cartridge-cli
    

    Среда Cartridge станет зависимостью при создании проекта.

    Все будет установлено в .rocks/bin, поэтому для удобства использования добавьте .rocks/bin в путь к исполняемому файлу:

    $ export PATH=$PWD/.rocks/bin/:$PATH
    
  2. Установите git, систему управления версиями.

  3. Установите npm, менеджер пакетов для node.js.

  4. Установите утилиту unzip.

Шаблоны приложений

В Tarantool Cartridge есть два шаблона, которые помогут вам мгновенно настроить среду разработки приложений:

  • plain – для разработки приложения, которое работает на одном или нескольких независимых экземплярах Tarantool’а (например, в качестве прокси для сторонних баз данных), что можно было делать и раньше без Tarantool Cartridge, но теперь это гораздо удобнее.
  • cartridge – для разработки приложений с поддержкой кластеров – эксклюзивная функция Tarantool Cartridge.

Чтобы создать проект на основе одного из шаблонов, в любой директории выполните команду:

# простое приложение
$ plain create --name <имя_приложения> /path/to/

# - ИЛИ -

# кластерное приложение
$ cartridge create --name <имя_приложения> /path/to/

Это автоматически настроит Git-репозиторий в новой директории /path/to/<имя_приложения>/, проставит тег с версией 0.1.0 и поместит туда необходимые файлы (файлы, размещаемые по умолчанию в каждом шаблоне, описаны ниже).

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

Шаблон plain

Шаблон plain создает директорию <имя_приложения>/, которая содержит следующее:

  • файл <имя_приложения>-scm-1.rockspec, где можно указать зависимости приложения.
  • скрипт deps.sh, который решает проблемы с зависимостями из файла .rockspec.
  • файл init.lua, который является точкой входа в ваше приложение.
  • файл .git, необходимый для Git-репозитория.
  • файл .gitignore, чтобы не учитывать ненужные файлы.

Шаблон cluster

Помимо файлов, перечисленным в разделе о шаблоне plain, шаблон cluster содержит следующее:

  • файл env.lua, который устанавливает общие пути для модулей, чтобы приложение можно было запустить из любой директории.
  • файл custom-role.lua, который представляет собой объект-заполнитель для пользовательской кластерной роли.

Файл входа в приложение (init.lua) в шаблоне cluster отличается от аналогичного файла в шаблоне plain. Помимо прочего, он загружает модуль cartridge и вызывает его функцию инициализации:

...
local cartridge = require('cartridge')
...
cartridge.cfg({
  workdir = ...,
  advertise_uri = ...,
  cluster_cookie = ...,
  ...
})
...

Вызов cartridge.cfg() позволяет управлять экземпляром через административную консоль, но не вызывает box.cfg() для настройки экземпляров.

Предупреждение

Запрещается вызывать функцию box.cfg().

Сам кластер сделает это за вас, когда придет время:

  • загрузить текущий экземпляр, когда вы:
    • выполните cartridge.bootstrap() в административной консоли, или
    • нажмете Create (Создать) в веб-интерфейсе;
  • присоединить экземпляр к существующему кластеру, когда вы:
    • выполните cartridge.join_server({uri = ''uri_другого_экземпляра'}) в консоли, или
    • нажмете Join (Присоединить – к уже существующему набору реплик) или Create (Создать – для нового набора реплик) в веб-интерфейсе.

Обратите внимание, что вы можете указать cookie для кластера (параметр cluster_cookie), если необходимо запустить несколько кластеров в одной сети. Cookie может представлять собой любое строковое значение.

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

Кластерные роли

Кластер Tarantool Cartridge распределяет функции экземпляров на основе ролей. Кластерные роли – это Lua-модули, которые реализуют некоторые заданные для экземпляра функции и/или логику.

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

Встроенные роли

В модуль cartridge входят две встроенные роли, которые реализуют автоматический шардинг:

  • vshard-router обрабатывает ресурсоемкие вычисления в vshard: направляет запросы к узлам хранения данных.

  • vshard-storage работает с большим количеством транзакций в vshard: хранит подмножество набора данных и управляет им.

    Примечание

    Для получения дополнительной информации о шардинге см. докуемнтацию по модулю vshard.

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

Ни vshard-router, ни vshard-storage не управляют спейсами, индексами и форматами. Чтобы начать разработку приложения, отредактируйте файл-заглушку custom-role.lua: добавьте вызов box.schema.space.create() в свою первую кластерную роль.

Кроме того, можно реализовать несколько таких ролей, чтобы:

  • определять хранимые процедуры;
  • реализовать функции поверх vshard;
  • полностью обойтись без vshard;
  • внедрить одну или несколько дополнительных служб, таких как средство уведомления по электронной почте, репликатор и т.д.

Пользовательские роли

Чтобы внедрить пользовательскую кластерную роль, выполните следующие действия:

  1. Зарегистрируйте новую роль в кластере, изменив вызов cartridge.cfg() в файле входа в приложение init.lua:

    ...
    local cartridge = require('cartridge')
    ...
    cartridge.cfg({
      workdir = ...,
      advertise_uri = ...,
      roles = {'custom-role'},
    })
    ...
    

    где custom-role (пользовательская роль) – это название загружаемого Lua-модуля.

  2. Поместите роль в файл с соответствующим именем (custom-role.lua). Например:

    #!/usr/bin/env tarantool
    -- Реализация пользовательской роли
    local role_name = 'custom-role'
    
    local function init()
    ...
    end
    
    local function stop()
    ...
    end
    
    return {
        role_name = role_name,
        init = init,
        stop = stop,
    }
    

    Где имя роли role_name может отличаться от имени модуля, переданного в функции cartridge.cfg(). Если не указать переменную role_name, по умолчанию будет использовано имя модуля.

    Примечание

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

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

  • init() – это функция инициализации роли.

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

    local function init(opts)
        -- Кластер передает Lua-таблицу 'opts', которая содержит флаг 'is_master'.
        if opts.is_master then
            local customer = box.schema.space.create('customer',
                { if_not_exists = true }
            )
            customer:format({
                {'customer_id', 'unsigned'},
                {'bucket_id', 'unsigned'},
                {'name', 'string'},
            })
            customer:create_index('customer_id', {
                parts = {'customer_id'},
                if_not_exists = true,
            })
        end
    end
    

    Примечание

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

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

  • validate_config() и apply_config() – это функции валидации и применения конфигурации соответственно, которые обеспечивают возможность настройки ролей. Используйте их, если некоторые настройки должны храниться на уровне кластера.

Затем изучите жизненный цикл роли, чтобы реализовать необходимые функции.

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

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

Например:

-- Зависимости между ролями, заданные в пользовательской роли custom-role.lua
local role_name = 'custom-role'
...
return {
    role_name = role_name,
    dependencies = {'cartridge.roles.vshard-router'},
    ...
}

Здесь роль vshard-router будет инициализирована автоматически для каждого экземпляра, в котором включена роль custom-role.

Использование нескольких групп vshard storage

Для наборов реплик с ролью vshard-storage можно задавать группы. Например, группы hot и cold предназначены для независимой обработки горячих и холодных данных.

Группы указаны в конфигурации кластера:

cartridge.cfg({
    vshard_groups = {'hot', 'cold'},
    ...
})

Если ни одна группа не указана, кластер предполагает, что все наборы реплик входят в группу default (по умолчанию).

Если включены несколько групп, каждый набор реплик с включенной ролью vshard-storage должен быть назначен в определенную группу. Эту настройку нельзя изменить впоследствии.

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

Наконец, обратите внимание на новый синтаксис для доступа к роутеру. Каждый экземпляр со включенной ролью vshard-router инициализирует несколько роутеров. Доступ к ним можно получить через роль:

local router_role = cartridge.service_get('vshard-router')
router_role.get('hot'):call(...)

Если роли не указаны, доступ к статическому роутеру можно получить, как и прежде:

local vhsard = require('vshard')
vshard.router.call(...)

Тем не менее, при использовании нового API следует вызывать статический роутер при помощи двоеточия:

local router_role = cartridge.service_get('vshard-router')
local default_router = router_role.get() -- или router_role.get('default')
default_router:call(...)

Жизненный цикл роли и порядок выполнения функций

Кластер отображает все имена пользовательских ролей вместе с именами встроенных ролей из vshard в веб-интерфейсе. Администраторы кластера могут включать и отключать их для определенных экземпляров либо через веб-интерфейс, либо через общедоступный API кластера. Например:

cartridge.admin.edit_replicaset('uuid-набора-реплик', {roles = {'vshard-router', 'пользователськая-роль'}})

Если несколько ролей одновременно включены на экземпляре, кластер сначала инициализирует встроенные роли (если они есть), а затем пользовательские (если они есть) в том порядке, в котором последние были перечислены в cartridge.cfg().

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

Кластер вызывает функции роли в следующих случаях:

  • Функция init() обычно выполняется один раз: либо когда администратор включает роль, либо при перезапуске экземпляра. Как правило, достаточно один раз включить роль.
  • Функция stop() – только когда администратор отключает роль, а не во время завершения работы экземпляра.
  • Функция validate_config(): сначала до автоматического вызова box.cfg()` (инициализация базы данных), а затем при каждом обновлении конфигурации.
  • Функция apply_config() – при каждом обновлении конфигурации.

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

  • Присоединение экземпляра или создание набора реплик (в обоих случаях с включенной ролью):
    1. validate_config()
    2. init()
    3. apply_config()
  • Перезапуск экземпляра с включенной ролью:
    1. validate_config()
    2. init()
    3. apply_config()
  • Отключение роли: stop().
  • При вызове cartridge.confapplier.patch_clusterwide():
    1. validate_config()
    2. apply_config()
  • При запущенном восстановлении после отказа:
    1. validate_config()
    2. apply_config()

Учитывая вышеописанное поведение:

  • Функция init() может:
    • Вызывать функции box.
    • Запускать файбер, и в таком случае функция stop() должна позаботиться о завершении работы файбера.
    • Настраивать встроенный HTTP-сервер.
    • Выполнять любой код, связанный с инициализацией роли.
  • Функции stop() должны отменять любую задачу, которую необходимо отменить при завершении работы роли.
  • Функция validate_config() должна валидировать любые изменения конфигурации.
  • Функция apply_config() может выполнять любой код, связанный с изменением конфигурации, например, следить за файбером expirationd.

Функции валидации и применения конфигурации вместе позволяют настраивать конфигурацию всего кластера, как описано в следующем разделе.

Конфигурация пользовательских ролей

Доступны следующие операции:

  • Хранить настройки пользовательских ролей в виде разделов в конфигурации на уровне кластера, например:

    # YAML configuration file
    my_role:
      notify_url: "https://localhost:8080"
    
    -- init.lua file
    local notify_url = 'http://localhost'
    function my_role.apply_config(conf, opts)
      local conf = conf['my_role'] or {}
      notify_url = conf.notify_url or 'default'
    end
    
  • Загружать и выгружать конфигурацию всего кластера через веб-интерфейс кластера или с помощью API (запросы GET/PUT к конечной точке admin/config: curl localhost:8081/admin/config и curl -X PUT -d "{'my_parameter': 'value'}" localhost:8081/admin/config).

  • Использовать ее в своей функции apply_config().

Каждый экземпляр в кластере хранит копию конфигурационного файла в своей рабочей директории (которую можно задать с помощью cartridge.cfg({workdir = ...})):

  • /var/lib/tarantool/<instance_name>/config.yml для экземпляров, развернутых из RPM-пакетов, под управлением systemd.
  • /home/<username>/tarantool_state/var/lib/tarantool/config.yml для экземпляров, развернутых из архивов, под управлением tarantoolctl.

Конфигурация кластера представляет собой Lua-таблицу. Если некоторые данные конфигурации для конкретного приложения (например, схему базы данных, описанную с помощью языка определения данных DDL) необходимо хранить в каждом экземпляре кластера, можно использовать свой собственный API, добавив в таблицу специальный раздел. Кластер поможет вам безопасно передать его всем экземплярам.

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

Самый распространенный способ заключается в том, чтобы:

  • validate_config(conf_new, conf_old) для валидации изменений, сделанных в новой конфигурации (conf_new) по отношению к старой конфигурации (conf_old).
  • apply_config(conf, opts) для выполнения любого кода, связанного с изменениями конфигурации. Входными данными для этой функции будут применяемая конфигурация (conf, которая и есть новая конфигурация, проверенная чуть ранее с помощью validate_config()), а также параметры (аргумент opts включает в себя описываемый ниже логический флаг is_master ).

Важно

Функция validate_config() должна обнаружить все проблемы конфигурации, которые могут привести к ошибкам apply_config(). Для получения дополнительной информации см. следующий раздел.

При реализации функций валидации и применения конфигурации, которые по какой-либо причине вызывают функции box, следует принять следующие меры предосторожности:

  • Жизненный цикл роли не предполагает, что кластер автоматически вызовет box.cfg() до вызова validate_config().

    Если функция валидации должна вызвать какие-либо функции из box (например, для проверки формата), убедитесь, что вызовы заключены в защитный условный оператор, который проверяет, произошел ли уже вызов box.cfg():

    -- В рамках функции валидации:
    
    if type(box.cfg) == 'function' then
    
        -- Здесь можно вызвать функции из box
    
    end
    
  • В отличие от функции валидации, как и в случае с функцией инициализации, apply_config() может свободно вызывать функции из box, поскольку кластер применяет пользовательскую конфигурацию после автоматического вызова box.cfg().

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

    По выполнении apply_config(conf, opts) кластер передает флаг is_master в таблице opts, который можно использовать для заключения функций из box в защитный условный оператор, если они могут вызвать конфликт:

    -- В рамках функции применения конфигурации:
    
    if opts.is_master then
    
        -- Here you can call box functions
    
    end
    

Пример пользовательской конфигурации

Рассмотрим следующий код как часть реализации модуля роли (custom-role.lua):

#!/usr/bin/env tarantool
-- Реализация пользовательской роли

local cartridge = require('cartridge')

local role_name = 'custom-role'

-- Изменение конфигурации с вводом сеттера (альтернатива HTTP PUT)
local function set_secret(secret)
    local custom_role_cfg = cartridge.confapplier.get_deepcopy(role_name) or {}
    custom_role_cfg.secret = secret
    cartridge.confapplier.patch_clusterwide({
        [role_name] = custom_role_cfg,
    })
end
-- Валидация
local function validate_config(cfg)
    local custom_role_cfg = cfg[role_name] or {}
    if custom_role_cfg.secret ~= nil then
        assert(type(custom_role_cfg.secret) == 'string', 'custom-role.secret must be a string')
    end
    return true
end
-- Применение
local function apply_config(cfg)
    local custom_role_cfg = cfg[role_name] or {}
    local secret = custom_role_cfg.secret or 'default-secret'
    -- Make use of it
end

return {
    role_name = role_name,
    set_secret = set_secret,
    validate_config = validate_config,
    apply_config = apply_config,
}

После настройки конфигурации выполните одно из следующих действий:

Применение конфигурации пользовательской роли

В примере реализации можно вызвать функцию set_secret(), чтобы применить новую конфигурацию с помощью административной консоли или конечной точки HTTP, если роль экспортирует таковую.

Функция set_secret() вызывает cartridge.confapplier.patch_clusterwide(), которая производит двухфазную фиксацию транзакций:

  1. Исправляет активную конфигурацию в памяти: копирует таблицу и заменяет раздел "custom-role" в копии на раздел, который задан функцией set_secret().
  2. The cluster checks if the new configuration can be applied on all instances except disabled and expelled. All instances subject to update must be healthy and alive according to the membership module.
  3. (Фаза подготовки) Кластер передает исправленную конфигурацию. Каждый экземпляр валидирует ее с помощью функции validate_config() каждой зарегистрированной роли. В зависимости от результата валидации:
    • В случае успеха (то есть возврата значения true) экземпляр сохраняет новую конфигурацию во временный файл с именем config.prepare.yml в рабочей директории.
    • (Фаза отмены) В противном случае экземпляр сообщает об ошибке, а все остальные экземпляры откатывают обновление: удаляют файл, который они, возможно, уже подготовили.
  4. (Фаза фиксации) После успешной подготовки всех экземпляров кластер фиксирует изменения. Каждый экземпляр:
    1. Создает жесткую ссылку активной конфигурации.
    2. Атомарно заменяет активную на подготовленную. Атомарная замена неделима, то есть она может быть либо выполнена, либо не выполнена полностью, но не частично.
    3. Вызывает функцию apply_config() каждой зарегистрированной роли.

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

Такого рода исправлений можно избежать, если функция validate_config() сможет обнаружить все проблемы конфигурации, которые могут привести к ошибкам в apply_config().

Использование встроенного HTTP-сервера

Кластер запускает экземпляр httpd-сервера во время инициализации (cartridge.cfg()). Можно привязать порт к экземпляру через переменную окружения:

-- Получение порта из переменной окружения или используемого по умолчанию:
local http_port = os.getenv('HTTP_PORT') or '8080'

local ok, err = cartridge.cfg({
   ...
   -- Передача порта в кластер:
   http_port = http_port,
   ...
})

Чтобы использовать httpd-экземпляр, получите к нему доступ и настройте маршруты в рамках функции init() для какой-либо роли (например, для роли, которая предоставляет API через HTTP):

local function init(opts)

...

   -- Получение httpd-экземпляра:
   local httpd = cartridge.service_get('httpd')
   if httpd ~= nil then
       -- Настройка маршрута, к примеру, к метрике:
       httpd:route({
               method = 'GET',
               path = '/metrics',
               public = true,
           },
           function(req)
               return req:render({json = stat.stat()})
           end
       )
   end
end

Для получения дополнительной информации об использовании HTTP-сервера Tarantool обратитесь к соответствующей документации.

Реализация авторизации в веб-интерфейсе

Чтобы реализовать авторизацию в веб-интерфейсе каждого экземпляра в кластере Tarantool’а:

  1. Используйте модуль, к примеру, auth с функцией check_password. Данная функция проверяет учетные данные любого пользователя, который пытается войти в веб-интерфейс.

    Функция check_password принимает имя пользователя и пароль и возвращает результат аутентификации: пройдена или нет.

    -- auth.lua
    
    -- Добавление функции для проверки учетных данных
    local function check_password(username, password)
    
        -- Проверка учетных данных любым способом
    
        -- Возврат пройденной или непройденной аутентификации
        if not ok then
            return false
        end
        return true
    end
    ...
    
  2. Передайте имя используемого модуля auth в качестве параметра для cartridge.cfg(), чтобы кластер мог использовать его:

    -- init.lua
    
    local ok, err = cartridge.cfg({
        auth_backend_name = 'auth',
        -- Кластер автоматически вызовет 'require()' для модуля 'auth'.
        ...
    })
    

    Это добавит кнопку Log in (Войти) в верхний правый угол в веб-интерфейсе, но все же позволит неавторизованным пользователям взаимодействовать с интерфейсом, что удобно для тестирования.

    Примечание

    Кроме того, для авторизации запросов к API кластера можно использовать базовый заголовок HTTP для авторизации.

  3. Чтобы требовать авторизацию каждого пользователя в веб-интерфейсе даже до начальной загрузки кластера, добавьте следующую строку:

    -- init.lua
    
    local ok, err = cartridge.cfg({
        auth_backend_name = 'auth',
        auth_enabled = true,
        ...
    })
    

    С включенной аутентификацией при использовании модуля auth пользователь не сможет даже загрузить кластер без входа в систему. После успешного входа в систему и начальной загрузки можно включить и отключить аутентификацию для всего кластера в веб-интерфейсе, а параметр auth_enabled игнорируется.

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

В Tarantool Cartridge семантическое управление версиями осуществляется так, как описано на сайте semver.org. При разработке приложения создайте новые ветки Git и пометьте их соответствующими тегами. Эти теги используются для расчета увеличения значения версий для последующей упаковки.

Например, если версия вашего приложения – 1.2.1, пометьте текущую ветку тегом 1.2.1 (с аннотациями или без них).

Чтобы получить значение текущей версии из Git, выполните команду:

$ git describe --long --tags
1.2.1-12-g74864f2

Вывод показывает, что после версии 1.2.1 было 12 коммитов. Если мы соберемся упаковать приложение на данном этапе, его полная версия будет 1.2.1-12, а пакет будет называться <имя_приложения>-1.2.1-12.rpm.

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

После упаковки приложения его версия сохраняется в файл VERSION в корневой каталог пакета.

Использование файлов .cartridge-cli.ignore

В репозиторий приложения можно добавить файл .cartridge-cli.ignore, чтобы не включать определенные файлы и/или директории в сборки пакета.

По большей части логика похожа на логику файлов .gitignore. Основное отличие состоит в том, что в файлах .cartridge-cli.ignore порядок исключения относительно остальных шаблонов не имеет значения, а в файлах .gitignore – имеет.

запись в .cartridge-cli.ignore игнорирует все…
target/ папки (поскольку в конце стоит /) под названием target рекурсивно
target файлы или папки под названием target рекурсивно
/target файлы или папки под названием target в самой верхней директории (поскольку в начале стоит /)
/target/ папки под названием target в самой верхней директории (в начале и в конце стоит /)
*.class файлы или папки, оканчивающиеся на .class, рекурсивно
#comment ничего, это комментарий (первый символ – #)
\#comment файлы или папки под названием #comment (\\ для выделения)
target/logs/ папки под названием logs, которые представляют собой поддиректорию папки под названием target
target/*/logs/ папки под названием logs на два уровня ниже папки под названием target (* не включает /)
target/**/logs/ папки под названием logs где угодно в пределах папки target (** включает /)
*.py[co] файлы или папки, оканчивающиеся на .pyc или .pyo, но не на .py!
*.py[!co] файлы или папки, оканчивающиеся на что угодно, кроме c или o
*.file[0-9] файлы или папки, оканчивающиеся на цифру
*.file[!0-9] файлы или папки, оканчивающиеся на что угодно, кроме цифры
* всё
/* всё в самой верхней директории (поскольку в начале стоит /)
**/*.tar.gz файлы *.tar.gz или папки, которые находятся на один или несколько уровней ниже исходной папки
!file файлы и папки будут проигнорированы, даже если они подходят под другие типы

Развертывание приложения

Развернуть приложение Tarantool Cartridge можно четырьмя способами:

  • в виде rpm-пакета (для эксплуатационной среды);
  • в виде deb-пакета (для эксплуатационной среды);
  • в виде архива tar+gz (для тестирования или для эксплуатационной среды, если отсутствует доступ уровня root).
  • из исходных файлов (только для локального тестирования).

Развертывание приложения в виде пакета rpm или deb

  1. Упакуйте файлы приложения в распространяемый пакет:

    $ cartridge pack rpm /path/to/<app_name>
    # -- OR --
    $ cartridge pack deb /path/to/<app_name>
    

    Будет создан RPM-пакет (например, ./my_app-0.1.0-1.rpm) или же DEB-пакет (например, ./my_app-0.1.0-1.deb).

  2. Загрузите пакет на необходимые серверы с поддержкой systemctl.

  3. Установите:

    $ yum install ИМЯ_ПРИЛОЖЕНИЯ-ВЕРСИЯ.rpm
    # -- ИЛИ --
    $ dpkg -i ИМЯ_ПРИЛОЖЕНИЯ-ВЕРСИЯ.deb
    
  4. Выполните конфигурацию экземпляров.

  5. Запустите экземпляры Tarantool’а с соответствующими службами. Например, это можно сделать, используя systemctl:

    # запуск одного экземпляра
    $ systemctl start my_app
    
    # запуск нескольких экземпляров
    $ systemctl start my_app@router
    $ systemctl start my_app@storage_A
    $ systemctl start my_app@storage_B
    
  6. Если это приложение с поддержкой кластеров, далее переходите к развертыванию кластера.

Развертывание архива tar+gz

  1. Упакуйте файлы приложения в распространяемый пакет:

    $ cartridge pack tgz /path/to/<app_name>
    

    Будет создан архив tar+gz (например, ./my_app-0.1.0-1.tgz).

  2. Загрузите архив на необходимый сервер с установленным tarantool и (необязательно) cartridge-cli.

  3. Распакуйте архив:

    $ tar -xzvf ИМЯ_ПРИЛОЖЕНИЯ-ВЕРСИЯ.tgz
    
  4. Выполните конфигурацию экземпляров.

  5. Запустите экземпляры Tarantool’а. Это можно сделать, используя:

    • tarantoolctl, например:

      $ tarantool init.lua # запускает одиночный экземпляр
      
    • или cartridge, например:

      # в директории приложения
      $ cartridge start # запускает все экземпляры
      $ cartridge start .router_1 # запускает один экземпляр
      
      # в среде с несколькими приложениями
      $ cartridge start my_app # запускает все экземпляры my_app
      $ cartridge start my_app.router # запускает один экземпляр
      
  6. Если это приложение с поддержкой кластеров, далее переходите к развертыванию кластера.

Развертывание из исходных файлов

Такой метод развертывания предназначен только для локального тестирования.

  1. Вытяните все зависимости в директорию .rocks:

    $ tarantoolctl rocks make

  2. Выполните конфигурацию экземпляров.

  3. Запустите экземпляры Tarantool’а. Это можно сделать, используя:

    • tarantoolctl, например:

      $ tarantool init.lua # запускает одиночный экземпляр
      
    • или cartridge, например:

      # в директории приложения
      cartridge start # запускает все экземпляры
      cartridge start .router_1 # запускает один экземпляр
      
      # в среде с несколькими приложениями
      cartridge start my_app # запускает все экземпляры my_app
      cartridge start my_app.router # запускает один экземпляр
      
  4. Если это приложение с поддержкой кластеров, далее переходите к развертыванию кластера.

Конфигурация экземпляров

Конфигурация экземпляра состоит из двух наборов параметров:

Задать эти параметры можно:

  1. В аргументах в командной строке.
  2. В переменных окружения.
  3. В конфигурационном файле формата YAML.
  4. В файле init.lua.

Вышеуказанный порядок определяет приоритет: аргументы в командной строке замещают переменные окружения и т.д.

Независимо от того, как вы запускаете экземпляры, необходимо задать следующие параметры cartridge.cfg() для каждого экземпляра:

  • advertise_uri – либо <ХОСТ>:<ПОРТ>, либо <ХОСТ>:, либо <ПОРТ>. Используется другими экземплярами для подключения. НЕ указывайте 0.0.0.0 – это должен быть внешний IP-адрес, а не привязка сокета.
  • http_port – порт, который используется, чтобы открывать административный веб-интерфейс и API. По умолчанию: 8081. Чтобы отключить, укажите "http_enabled": False.
  • workdir – директория, где хранятся все данные: файлы снимка, журналы упреждающей записи и конфигурационный файл cartridge. По умолчанию: ..

Если вы запустите экземпляры, используя интерфейс командной строки cartridge или systemctl, сохраните конфигурацию в формате YAML, например:

my_app.router: {"advertise_uri": "localhost:3301", "http_port": 8080}
my_app.storage_A: {"advertise_uri": "localhost:3302", "http_enabled": False}
my_app.storage_B: {"advertise_uri": "localhost:3303", "http_enabled": False}

С помощью интерфейса командной строки cartridge вы можете передать путь к этому файлу в качестве аргумента командной строки --cfg для команды cartridge start – или же указать путь в конфигурации cartridge./.cartridge.yml или ~/.cartridge.yml):

cfg: cartridge.yml
run_dir: tmp/run
apps_path: /usr/local/share/tarantool

С помощью systemctl сохраните файл в формате YAML в /etc/tarantool/conf.d/ (по умолчанию путь systemd) или в место, указанное в переменной окружения TARANTOOL_CFG.

Если вы запускаете экземпляры с помощью tarantool init.lua, необходимо также передать другие параметры конфигурации в качестве параметров командной строки и переменных окружения, например:

$ tarantool init.lua --alias router --memtx-memory 100 --workdir "~/db/3301" --advertise_uri "localhost:3301" --http_port "8080"

Запуск/остановка экземпляров

В зависимости от способа развертывания вы можете запускать/останавливать экземпляры, используя tarantool, интерфейс командной строки cartridge или systemctl.

Запуск/остановка с помощью tarantool

С помощью tarantool можно запустить только один экземпляр:

$ tarantool init.lua # простейшая команда

Можно также задать дополнительные параметры в командной строке или в переменных окружения.

Чтобы остановить экземпляр, используйте Ctrl+C.

Запуск/остановка с помощью CLI в cartridge

С помощью интерфейса командной строки cartridge, можно запустить один или несколько экземпляров:

$ cartridge start [ИМЯ_ПРИЛОЖЕНИЯ[.ИМЯ_ЭКЗЕМПЛЯРА]] [параметры]

Возможные параметры:

--script FILE

Точка входа в приложение. По умолчанию:

  • TARANTOOL_SCRIPT, либо
  • ./init.lua, если запуск идет из директории приложения, или же
  • :путь_к_приложениям/:имя_приложения/init.lua в среде с несколькими приложениями.
--apps_path PATH
Путь к директории с приложениями при запуске из среды с несколькими приложениями. По умолчанию: /usr/share/tarantool.
--run_dir DIR
Директория с файлами pid и sock. По умолчанию: TARANTOOL_RUN_DIR или /var/run/tarantool.
--cfg FILE
Конфигурациионный файл в формате YAML для экземпляров Cartridge. По умолчанию: TARANTOOL_CFG или ./instances.yml.
--foreground
Не в фоне.

Например:

cartridge start my_app --cfg demo.yml --run_dir ./tmp/run --foreground

Это запустит все экземпляры Tarantool’а, указанные в файле cfg, не в фоновом режиме с принудительным использованием переменных окружения.

Если ИМЯ_ПРИЛОЖЕНИЯ не указано, cartridge выделит его из имени файла ./*.rockspec.

Если ИМЯ_ЭКЗЕМПЛЯРА не указывается, cartridge прочитает файл cfg и запустит все указанные экземпляры:

# в директории приложения
cartridge start # запускает все экземпляры
cartridge start .router_1 # запускает отдельный экземпляр

# в среде с несколькими приложениями
cartridge start my_app # запускает все экземпляры my_app
cartridge start my_app.router # запускает отдельный экземпляр

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

$ cartridge stop [ИМЯ_ПРИЛОЖЕНИЯ[.ИМЯ_ЭКЗЕМПЛЯРА]] [параметры]

Поддерживаются следующие параметры из команды cartridge start`:

  • --run_dir DIR
  • --cfg FILE

Запуск/остановка с помощью systemctl

  • Чтобы запустить отдельный экземпляр:

    $ systemctl start ИМЯ_ПРИЛОЖЕНИЯ
    

    Это запустит службу systemd, которая будет прослушивать порт, указанный в конфигурации экземпляра (параметр http_port).

  • Чтобы запустить несколько экземпляров на одном или нескольких серверах:

    $ systemctl start ИМЯ_ПРИЛОЖЕНИЯ@ЭКЗЕМПЛЯР_1
    $ systemctl start ИМЯ_ПРИЛОЖЕНИЯ@ЭКЗЕМПЛЯР_2
    ...
    $ systemctl start ИМЯ_ПРИЛОЖЕНИЯ@ЭКЗЕМПЛЯР_N
    

    где ИМЯ_ПРИЛОЖЕНИЯ@ЭКЗЕМПЛЯР_N – это имя экземпляра сервиса systemd с инкрементным числом N (уникальным для каждого экземпляра), которое следует добавить к порту 3300 для настройки прослушивания (например, 3301, 3302 и т.д.).

  • Чтобы остановить все сервисы на сервере, используйте команду systemctl stop и укажите имена экземпляров по одному. Например:

    $ systemctl stop ИМЯ_ПРИЛОЖЕНИЯ@ЭКЗЕМПЛЯР_1 ИМЯ_ПРИЛОЖЕНИЯ@ЭКЗЕМПЛЯР_2 ... ИМЯ_ПРИЛОЖЕНИЯ@ЭКЗЕМПЛЯР_<N>