FreeBSD virtual environment management and repository

2020-10 upd: we reached the first fundraising goal and rented a server in Hetzner for development! Thank you for donating !

CBSD API модуль

Введение

CBSD позволяет пользователю создавать окружения на разных уровнях абстрации, предоставляя большое количество методов по созданию окружений - CBSDfile, команды [jb]create, которые работают как по конфигурационному файлу, так и через аргументы командной строчки. Наконец, вы можете использовать интерактивные диалоговые меню ([jb]construct-tui). Несмотря на разнообразность, все эти варианты требуют входа на сервер каждый раз через ssh и вводить соответствующие команды. RestAPI сервис добавляет для вас еще одну опцию по управления окружениями, позволяя отказаться от необходимости использовать ssh, где вы взаимодействуете с CBSD фреймворком через HTTP/RestAPI запросы или через тонкого клиента. В отличие от других методов, этот уровень абстракции решает следующие проблемы:

  • Полностью удаленный контроль: клиенту нет необходимости заходить на сервер и даже иметь учетную запись на сервере;
  • Забудьте о физических серверах вовсе - неважно сколько физических серверов в облаке, перестаньте об этом думать - работайте с одной точкой входа, которая возьмет вопросы по размещению окружений на себя;
  • Унифицированный интерфейс - RestAPI в отличие от CBSD знаком большинству IT специалистов;
  • Разделение окружений по независимым namespace-ам - вы можете поставить CBSD кластер и предоставить доступ к API вашим друзьям или коллегам, где никто не будет друг другу мешать. Каждый пользователь работает только со своими окружениями;
  • Отсутствие коллизий в именах контейнеров/ВМ между неймспейсами - каждый пользователь может создать контейнер или ВМ с именем 'test' и это не вызовет конфликт имен;
  • Официально поддерживаются три(!) метода работы с кластером/API: платформозависимый - CBSDfile (требует CBSD в качестве тонкого клиента) и два независимых - nubectl (клиент, доступный на всех современных платформах: Linux, Windows, MacOSX) и непосредственно, curl-like клиент с json в качестве payload;
  • максимальная простота: вы регулируете только три параметра, чтобы в течении нескольких секунд получить полностью рабочее окружение;
  • Расширяемость: кастомные рекомендации для выбора хоста (например - DRS), интеграция с внешними службами (например - IPAM), экстрасы (внешние подключаемые хелперы);

Если вы сталкиваетесь с этими проблемами и хотите облегчить свою жизнь - то это статья для Вас!

Архитектура API сервиса поддерживает работу как на одной ноде, когда сам сервис API и гипервизор совмещен, так и позволяет использовать любое количество нод в качестве гипервизоров. Мы начнем с настройки standalone варианта, тем более, что при переходе на multi-node вариант все эти шаги все равно необходимы.


private FreeBSD multi-node bhyve/jail cloud via API demo:

Давайте зафиксируем терминологию, которая будет использована в этой статье.

  • CBSD - набор скриптов, реализующий управление виртуальными машинами на самом низком уровне. Вам потребуется CBSD не ниже 13.0.1. Если версия ниже, пожалуйста, обновитесь перед тем как вы начнете.
  • ZPOOL - ZFS пул, в котором проинициализировано рабочее окружение CBSD. По-умолчанию, рабочий каталог CBSD инициализируется в /usr/jails.
  • Broker - основная шина данных общения между сервисом cbsd-mq-api (один) и cbsd-mq-router (может быть в любых количествах). В текущей статье роль брокера выполняет beanstalkd.
  • Tube - труба (в терминологии beanstald) - FIFO-очередь в брокере, в которую пишет (publish) cbsd-mq-api, а cbsd-mq-router - читает (subscribe).
  • Hypervisor (не путать с bhyve hypervisor) - физическая нода под управлением FreeBSD OS. Количество нод неограничено. Каждый гипервизор имеет как минимум 1 ZPOOL. Каждый пул обслуживается процессом cbsd-mq-router, подписывающийся на персональную pool-очередь для обработки инструкций CBSD.
  • API - сервис (public), предоставляющий RestAPI или json-rpc для взаимоимодействия конечных пользвателей ( curl/UI frontend ). В нашем случае простейшей реализацией будет сервис cbsd-mq-api.

Начнем с рассмотрения самой простой однонодовой инсталляции.

Standalone API

Установка и настройка CBSD API в режиме standalone.

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

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

1) Установим дополнительные пакеты

pkg install -y cbsd-mq-router cbsd-mq-api beanstalkd git
	

2) Сконфигурируем beanstalkd, брокер сообщений.

Поскольку все соединения между сервисами происходят на одном сервере, укажем 127.0.0.1 адрес для входящих соединений:

sysrc beanstalkd_flags="-l 127.0.0.1 -p 11300"
service beanstalkd enable
service beanstalkd restart
	

3) Конфигурирование MQ роутера.

Вначале, получите имя вашего сервера через команду `hostname`. Допустим, ваш сервер имеет hostname: apitest.my.domain

Откройте файл /usr/local/etc/cbsd-mq-router.json в любом редакторе и выставьте параметры "tube" и "reply_tube_prefix" в соответствии с именем вашего хоста, заменив точки на символ подчеркивания ( cbsd_<hostname_without_dot> and cbsd_<hostname_without_dot>_result_id ), например:

{
    "cbsdenv": "/usr/jails",
    "cbsdcolor": false,
    "broker": "beanstalkd",
    "logfile": "/dev/stdout",
    "beanstalkd": {
      "uri": "127.0.0.1:11300",
      "tube": "cbsd_apitest_my_domain",
      "reply_tube_prefix": "cbsd_cbsd_apitest_my_domain_result_id",
      "reconnect_timeout": 5,
      "reserve_timeout": 5,
      "publish_timeout": 5,
      "logdir": "/var/log/cbsdmq"
    }
}
	

4) Запускаем MQ роутер:

service cbsd-mq-router enable
service cbsd-mq-router start
	

5) Установка CBSD API модуля.

cbsd module mode=install api
echo 'api.d' >> ~cbsd/etc/modules.conf
cbsd initenv
	

6) Настройка CBSD API модуля.

Скопируйте пример конфигурационных файлов в рабочий каталог:

cp -a /usr/local/cbsd/modules/api.d/etc/api.conf ~cbsd/etc/
cp -a /usr/local/cbsd/modules/api.d/etc/bhyve-api.conf ~cbsd/etc/
cp -a /usr/local/cbsd/modules/api.d/etc/jail-api.conf ~cbsd/etc/
	

Откройте файл ~cbsd/etc/api.conf в любом редакторе и установите значение параметра "server_list=" в имя вашего сервера (FQDN), например:

...
server_list="apitest.my.domain"
...
	

Дайте права пользвателю 'cbsd' на файл ~cbsd/etc/api.conf:

chown cbsd:cbsd ~cbsd/etc/api.conf
	

На этом этапе мы можем проверить, что скрипты API модуля работают, запустите:

su -m cbsd -c '/usr/local/cbsd/modules/api.d/misc/recomendation.sh'
	

Скрипт должен вернуть имя вашего сервера через параметр server_list ( apitest.my.domain )

su -m cbsd -c '/usr/local/cbsd/modules/api.d/misc/freejname.sh'
	

Эта команда должна вернуть уникальное имя вида 'envX'.

7) Конфигурирование RestAPI сервиса:

mkdir -p /var/db/cbsd-api /usr/jails/var/db/api/map
chown -R cbsd:cbsd /var/db/cbsd-api /usr/jails/var/db/api/map
service cbsd-mq-api enable
service cbsd-mq-api start

Ваш первый частный API кластер виртуальных машин готов к работе!

Создаем jail через curl

Создадим простейший минимальный payload для создания контейнера, например файл jail1.json:

{
  "type": "jail",
  "imgsize": "10g",
  "pubkey": "ssh-ed25519 AAAA..XXX your@localhost"
}

Разумеется, в качестве pubkey используйте свой публичный ключ. Отправим его в endpoint по созданию контейнера, где /jail1 в конце означает выбранное вами имя окружения (произвольное):

curl -X POST -H "Content-Type: application/json" -d @jail1.json http://127.0.0.1:65531/api/v1/create/jail1

При этом API подсчитает MD5 хеш от вашего pubkey и результат автоматичеки становится вашим токеном, который вы можете использовать для контроля окружений и одновременно будет вашим namespace-ом в кластере. В нем вы будете видеть все ресурсы, создававемые с использование вашего публичного ключа.

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

Обратите внимание, что первый контейнер может создаваться не быстро, если вы не создавали на хосте еще ни одного контейнера - CBSD будет скачивать и распаковывать base.txz архив - убедитесь, что сервер имеет выход в интернет для получения файлов с ftp/http.freebsd.org. Либо, перед первым запросом просто 'прогрейте' систему, создав контейнер через cbsd jcreate/jconstruct-tui.

Теперь, зная токен, вы можете получить статус вашего контейнера. Среди этой информации будет строчка для соединения через SSH для доступа в контейнер. Получите md5 сумму вашего ключа, если вы его все еще не знаете ;-)

md5 -qs "ssh-ed25519 AAAA..XXX your@localhost"

И используйте его в запросе:

curl -H "cid:90af7aa8bc164240521753a105df6a05" http://127.0.0.1:65531/api/v1/status/jail1

Так, если потребуется уничтожить окружение, используйте GET запрос на ендпоинт /destroy:

curl -H "cid:90af7aa8bc164240521753a105df6a05" http://127.0.0.1:65531/api/v1/destroy/jail1

Другие параметры в payload, которые могут пригодиться при создании контейнера:

"host_hostname":указать hostname для вашего контейнера, например: "foo.example.com"
"ram":ограничить потребление памяти jail через RACCT, например: "1g"
"cpus":ограничить число ядер, доступных jail, например: "2"
"pkglist":список пакетов на установку, например: "misc/mc fping"
"extras":экстрасы (см. ниже)
"recomendation":указать собственную рекомендацию, на каком конкретно хосте создать контейнер, вместо автоматического выбора. Для multi-node кластеров. Например: "host23.my.domain" (при условии, что хост host23.my.domain существует)

Создаем bhyve vm через curl

Работа с виртуальными машинами имеет аналогичный интерфейс и endpoint, как и в случае с jail, но имеет немного другой payload для создания окружения.

Пример payload, например centos7.json:

{
  "type": "bhyve",
  "imgsize": "10g",
  "ram": "1g",
  "cpus": "2",
  "img": "centos7",
  "pubkey": "ssh-ed25519 AAAA..XXX your@localhost"
}

И создается аналогичным запросом что и jail:

curl -X POST -H "Content-Type: application/json" -d @centos7.json http://127.0.0.1:65531/api/v1/create/cent7

Другие параметры в payload, которые могут пригодиться при создании VM:

"host_hostname":указать hostname для вашей виртуальной машины, например: "foo.example.com"
"extras":экстрасы (см. ниже)
"recomendation":указать собственную рекомендацию, на каком конкретно хосте создать VM, вместо автоматического выбора. Для multi-node кластеров. Например: "host23.my.domain" (при условии, что хост host23.my.domain существует)

Обратите внимание, что в отличие от классических bcreate/bconstruct-tui, параметры vm_os_type и vm_os_profile здесь консолидированы в один параметр "img" для еще большей простоты. При этом маппинг <img> задается в файле, который вы копировали ранее, это ~cbsd/etc/bhyve-api.conf. На момент написания статьи, доступные значения в качестве img: 'centos7', 'centos8', 'ubuntu', 'debian', 'freebsd_ufs', 'freebsd_zfs', 'openbsd', 'netbsd'.

Обратите внимание, что первая ВМ каждого имиджа может создаваться не быстро, если вы не создавали на хосте еще ни одной ВМ данного профиля - CBSD будет скачивать и распаковывать ISO - убедитесь, что сервер имеет выход в интернет для получения файлов. Либо, перед первым запросом просто 'прогрейте' систему, создав-запустив-удалив все профили ОС, с которыми планируете работать через API.

CBSDfile + API

В некоторых случаях curl и RestAPI - намного удобнее ssh + `cbsd bcreate/bconstruct-tui`. Если вам приходится много и часто деплоить виртуальные окружения, вам не избежать необходимость изучить и использовать какой-нибудь язык высокого уровня. Вышеупомянутые Curl и HTTP запросы хорошо подходят, если вы разрабатываете на базе CBSD программируемое облако, однако для людей это не очень удобно. В качестве промежуточного варианта мы можем предложить вариант взаимодействия с API через CBSDfile.

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

Если вы не знакомы с этой возможностью CBSD - непременно ознакомьтесь. Для того, чтобы использовать CBSDfile в вашем частном облаке, вам достаточно добавить в начало CBSDfile всего два параметра - это Endpoint вашего API и ключ. Наличие этих двух параметров заставит CBSD переключиться при создании с локальной инсталляции CBSD на облако. А это может предоставлять уже совершенно нового уровня возможности (пример взаимодействия с multi-node кластером)!

Такие параметры как ssh_wait, jscp и jexec (bscp и bexec для bhyve) также должны работать, что позволяет вам не только развернуть виртуальное окружение в облаке, но и произвести на ней ряд операций при создании, пример такого CBSDfile:

CLOUD_URL="http://127.0.0.1:65531"
CLOUD_KEY="ssh-ed25519 AAAA..XXX your@localhost"

jail_rabbitmq1()
{
        imgsize="30g"
        ssh_wait=1
        pkg_bootstrap=0
        host_hostname="rabbitmq1.my.domain"
}

postcreate_rmqbsd1()
{
        jscp prepare.sh ${jname}:prepare.sh
        jexec /root/prepare.sh
}

И поместить в ту же директорию с CBSDfile исполняемый файл prepare.sh, который будет скопирован и запущен в созданном окружении.

Кроме операций по созданию и удалению, с API-enabled CBSDfile будут работать команды: cbsd login, cbsd status

nubectl

Наконец, существует еще один вариант в виде тонкого клиента под названием nubectl, билды которого доступны для всех современных ОС. С помощью него вы можете создавать и удалять окружения, а также выполнять вход по ssh для unix-like гостей, даже если вы работаете на Microsoft Windows.

Кроме этого, nubectl поддерживает описание Infrastructure as a Code через yaml файлы. Refer to example cloud config.


Еще пара примеров для nubectl-windows:

nubectl-windows status --cloudkey="c:\authorized_keys" --cloudurl=http://127.0.0.1:65531
nubectl-windows create vm --cloudkey="c:\authorized_keys" --cloudurl=http://127.0.0.1:65531
nubectl-windows ssh vm --cloudkey="c:\authorized_keys" --cloudurl=http://127.0.0.1:65531 [--sshkey=c:\id_ed25519]

Multinode API

Мультинодовый API/CBSD кластер

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

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

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

Здесь дается любой полет фантазии для имплементации логики на любом удобном для вас языке программирования и использования любых алгоритмов. Так, например, если часть ваших серверов имеет высокопроизводительные но небольшого объема NVME диски и часть серверов - емкие, но медленные hdd, вы можете легким образом реализовать простую логику вида

Если запрашивается виртуальная машина с объемом диска > 500GB - выбирать из списка серверов с hdd.

Вместе с модулем API поставляются два скрипта на sh, которые в качестве примеров дают уникальный ID в качестве имени виртуальной машины и выдающий сервера по алгоритму round-robin. Что должно хватать для запуска полноценного мультинодового кластера за 10 минут. Давайте сделаем это.

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

Начнем с настройки API сервиса. По отношению к standalone конфигурации, в файле ~cbsd/etc/api.conf мы расширяем список на необходимое количество участников в кластере, напрмер:

server_list="srv-01.olevole.ru srv-02.olevole.ru srv-03.olevole.ru bob.your-server.de"

Вы можете проверить, что скрипт рекомендаций ( /usr/local/cbsd/modules/api.d/misc/recomendation.sh )по-умолчанию предлагает хосты в round-robin:

WIP...

MyB: MyBee appliance

Для тех, кто не любит настраивать систему - мы подготовили независимый дистрибутив FreeBSD с преднастроенным CBSD и сервисом API - вы можете начать работать с виртуальными окружениями сразу после установки дистрибутива на bare metal. Встречайте: MyBee.

API: advanced/custom конфигурации

С помощью конфигурационного файла вы можете регулировать некоторые поведения, такие как работа с IP адресами, редиректами, предпочтениями IPv6 и тд. По-умолчанию, CBSD выбирает IP адреса из вашего nodeip4pool. Подразумевается, что пул указывает на приватные (rfc1918) адреса. Для того, чтобы доступ внутрь окружения был доступен извне, CBSD автоматически находит первый свободный порт и создает редирект порта с внешнего IP адреса (nodeip) внутрь контейнера. В качестве ssh4_string CBSD, строка для соединения с окружением, отдается nodeip внешний адрес и новый порт.

Если вы используете в качестве пула внешние адреса, или у вас есть прямой доступ ( IPSEC/VXLAN/туннели) к приватной сети хоста - вы можете изменить поведение, запретив выбор динамического порта и выключить редирект вовсе. Тогда, API будет отдавать прямой IP:22 порт виртуальной машины. За это отвечает параметр nodeip_expose=1 в ~cbsd/etc/bhyve-api.conf и ~cbsd/etc/jail-api.conf (для bhyve и jail соответственно).

cЕсли вы используете кластер с несколькими серверами в разных центрах обработки данных, которые объединены в одну частную сеть, в которой работают среды, вы можете захотеть изменить источник выдачи адресов на внешнюю службу, как это сделано здесь

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

extras="dns:my.domain"

вы можете заставить API зарегистрироват в службе DNS имя my.domain, которая будет указывать на созданное окружение.

Или можете захотеть использовать запись вида:

extras="lb:true"

которая при создании окружения сконфигурирует vhost на внешнем балансере, указав в качестве апстрима для виртуального хоста IP адрес созданного окружения.

extras-ы можно комбинировать, например запись вида:

extras="dns:wordpress.my.domain,lb:true,ipv6:external,letsencrypt:true"

Может заставить API при создании окружения завести в DNS запись wordpress.my.domain, заказать для домена сертификат LetsEncrypt через certbot, добавит окружению IPv6 и создаст конфигурацию на балансере