Не так давно Ростелеком объявил о создании центра компетенций по разработке программных решений под отечественные процессоры. Первая задача, которую нам пришлось решать как нам разграничить серверные ресурсы между сотрудниками занимающимися портированием и разработкой, организовать демонстрационные стенды, а, в перспективе, при росте нагрузок, ещё и управлять такими ресурсами как память и процессорное время.
Традиционно эту задачу решают средствами виртуализации, но, к сожалению, наши процессоры еще не поддерживают её. Альтернативным решением является контейнеризация. Изучив доступные варианты, которые можно реализовать на ОС Эльбрус, мы остановились на LXC как стабильном решении. В данной статье я хочу рассказать как пользоваться LXC в ОС Эльбрус.
Что мы еще рассматривали
chroot- имеет право на жизнь, но хочется аналог виртуальных машин, что даст нам больше гибкости.docker- есть только в экспериментальной версии, возможно вернемся к нему, но хочется сосредоточиться на работе, а не выяснении почему все упало.В ОС Эльбрус есть собранный
Bochs, но он не умеет эмулироватьe2kархитектуру разработка под которую является целевой для нас.QEMU- в версии ядра 2.6 для ОС Эльбрус работалQEMUв режиме паравиртуализации, потом его убирали на доработку. В пакетах ОС Эльбрус он есть, но его работоспособность мной не проверялась (как проверим, обязательно расскажем).
Исходные данные
Итак, для начала у нас имеется:
сервер на базе процессоров Эльбрус-8С;
на сервер установлена ОС Эльбрус версии 6.0.1
LXC версии 2.0.8
в качестве
rootfsбэкенда в LXC мы будем использовать каталог (опцияlxc.rootfs.backend = dir), это даст нам дополнительные возможности, о которых я расскажу ниже.
Подготовка и настройка сервера
Устанавливаем пакеты lxc и lxcfs командой:
sudo apt install lxc lxcfs
Настраиваем сеть для контейнеров, для этого создаем файл /etc/default/lxc-net следующего содержания:
USE_LXC_BRIDGE="true" LXC_BRIDGE="lxcbr0" LXC_ADDR="192.168.103.1" LXC_NETMASK="255.255.255.0" LXC_NETWORK="192.168.103.0/24" LXC_DHCP_RANGE="192.168.103.2,192.168.103.254" LXC_DHCP_MAX="253" #LXC_DHCP_CONFILE="" LXC_DOMAIN=""
Для применения сетевых настроек ко вновь создаваемым контейнерам вносим изменения в файл /etc/lxc/default.conf:
lxc.network.type = veth lxc.network.link = lxcbr0 lxc.network.flags = up lxc.network.hwaddr = 00:16:3e:xx:xx:xx
Для создания сетевого моста нужно запустить службу lxc-net:
sudo service lxc start
Ну и включаем необходимые службы для автоматического запуска при старте операционной системы:
sudo chkconfig lxc-net on sudo chkconfig lxc on
Создание первого контейнера
С ОС Эльбрус идет шаблон osl для создания контейнера из образа установочного диска. Для создания нашего первого контейнера копируем на сервер iso-образ (в моем случае я его залил в /opt/iso) и монтируем его:
sudo mkdir -p /mnt/cdrom sudo mount -t iso9660 -o loop /opt/iso/el-6.0.1-e8c-boot.iso /mnt/cdrom
Следует заметить, что монтировать нужно строго в /mnt/cdrom так как этот путь зашит в скрипте шаблона.
Создаем контейнер командой:
sudo lxc-create -t osl -n osl-test
Ждем окончания развертывания, запускаем контейнер и подключаемся к нему:
sudo lxc-start -n osl-test sudo lxc-attach -n osl-test
У нас есть работающий контейнер, который уже можно использовать как замену виртуальной машины. В нем потребуется еще произвести настройку и установку необходимых для работы пакетов.
Если в ваших планах не входит частое развертывание новых контейнеров, то можете пользоваться этим способом, но у нас грандиозные планы и поэтому было принято решение сделать шаблон который бы позволил нам развертывать новые контейнеры из нескольких заранее настроенных тарболов.
Шаблон для создания контейнера из тарбола
Как я уже писал ранее, в качестве rootfs бэкенда мы используем каталог, значит мы можем создать контейнер по первому способу, провести в нем необходимые нам настройки и упаковать его в тарбол. При создании нового контейнера нам достаточно всего лишь распаковать содержимое контейнера в каталог rootfs нового контейнера и дописать необходимые параметры в файл config.
За основу нового шаблона был взят аналогичный шаблон из SaltStack с небольшими доработками под специфику ОС Эльбрус.
Первая правка которую нам нужно внести касается задания hostname, в ОС Эльбрус имя хоста задается в файле /etc/sysconfig/network для этого в файл шаблона в конец функции deploy_tar() дописываем:
if [ -f "${rootfs_path}/etc/sysconfig/network" ]; then OLD_HOSTNAME=$(grep HOSTNAME ${rootfs_path}/etc/sysconfig/network) sed -i "s/$OLD_HOSTNAME/HOSTNAME=$name/" ${rootfs_path}/etc/sysconfig/network fi
Мы не планируем настраивать сеть из шаблона, для этого убираем строки, отвечающие за настройки настройки сети:
lxc_network_type="veth" lxc_network_link="br0" ... -t|--network_type) lxc_network_type=${2}; shift 2;; -l|--network_link) lxc_network_link=${2}; shift 2;; -r|--root_passwd) root_passwd=${2}; shift 2;; ... if [ ! -e /sys/class/net/${lxc_network_link} ]; then echo "network link interface does not exist" exit 1 fi
Задаем новое имя нашему файлу, в LXC имена шаблонов имеют вид lxc-<имя шаблона>, где часть <имя шаблона> потом используется в команде lxc-create, для файла выставляем права на запуск и копируем его в /usr/share/lxc/templates/. Свой шаблон я назвал osl-img:
mv salt_tarball lxc-osl-img chmod +x lxc-osl-img TODO: уточнить права на шаблонах chown root:root lxc-osl-img sudo mv lxc-osl-img /usr/share/lxc/templates/
Создаем шаблонный образ rootfs
Прежде всего создаем контейнер по первой части нашей инструкции и проводим настройку контейнера.
Исправление ошибок при выполнении команды chkconfig
Данные действия можно произвести без запуска контейнера, напрямую отредактировав файлы. По умолчанию LXC создает новые контейнеры в /var/lib/lxc/<имя вашего контейнера> (далее пути будут указаны относительно этого пути).
Нам нужно отредактировать файл rootfs/etc/init.d/sysklogd вписав после строки
### BEGIN INIT INFO
строку:
# Provides: sysklogd
Удаляем файл rootfs/etc/rcsysinit.d/S05mknod и создаем файл rootfs/etc/init.d/mknod со следующим содержимым:
#!/bin/sh ### BEGIN INIT INFO # Provides: mknod # Required-Start: mountkernfs # Required-Stop: mountkernfs # Default-Start: S # Default-Stop: 0 6 # Short-Description: # Description: ### END INIT INFO . /etc/sysconfig/rc . ${rc_functions} case "${1}" in start) mknod -m 660 /dev/loop0 b 7 0 mknod -m 660 /dev/loop1 b 7 1 mknod -m 660 /dev/loop2 b 7 2 mknod -m 660 /dev/loop3 b 7 3 (exit ${failed}) evaluate_retval ;; *) echo "Usage: ${0} {start}" exit 1 ;; esac
Настройка сети
В своих тарболах я использую назначение адресов по DHCP, если требуются другие настройки, то это уже конфигурируется для конкретных контейнеров. Настройки сетевых интерфейсов в ОС Эльбрус располагаются в /etc/sysconfig/network-devices/ifconfig.<имя интерфейса>/ipv4, для интерфейса eth0 создаем файл rootfs/etc/sysconfig/network-devices/ifconfig.eth0/ipv4 следующего содержания:
BOOTPROTO=dhcp ONBOOT=yes SERVICE=dhclient
Создаем служебного пользователя
Я являюсь противником работы от пользователя root, поэтому создадим служебного пользователя под которым можно будет производить дальнейшие настройки.
Стартуем наш контейнер lxc-start -n <имя контейнера>, и подключаемся к нему lxc-attach -n <имя контейнера>. Создаем пользователя admin:
useradd -m admin passwd admin usermod -a -G wheel admin
Редактируем файл /etc/sudoers разрешая членам группы wheel выполнять команды через sudo. Для этого раскомментируем строку:
%wheel ALL=(ALL) ALL
Не лишним будем установить новый пароль пользователю root:
passwd root
Автозапуск служб
Для корректной работы контейнера нам требуется выставить автозагрузку некоторых служб, для этого выполним внутри контейнера следующие команды:
chkconfig devpts on chkconfig network on chkconfig mknod on
Упаковка rootfs в тарбол
Останавливаем контейнер командой lxc-stop -n <имя контейнера>. И выполняем команду:
tar -cvzf osl-template.tar.gz -C /var/lib/lxc/<имя контейнера>/rootfs/ .
Получившийся архив перемещаем в удобное для хранения место.
Как пользоваться?
Свой шаблон я назвал osl-img, поэтому в примерах он будет фигурировать с таким именем. Что-бы развернуть новый контейнер нам потребуется выполнить команду:
sudo lxc-create -t osl-img -n tarball-test -- --imgtar /path/to/osl-template.tar.gz
Если все сделали правильно, то мы получим новый контейнер, который даже работает.
Доступ в контейнеры по SSH
Подключаться к контейнеру через lxc-attach конечно хорошо, но не очень удобно, тем более некоторые IDE позволяют производить компиляцию на удаленном хосте через SSH, что было бы очень удобно при портировании и разработке под Эльбрус.
Мною опробованы два способа. Первый способ, работает при использовании моста на сетевой интерфейс, в этом случае хостовую систему можно использовать как jump host и настроить ssh клиента для работы через него. Для этого нужно внести в файл ~/.ssh/config следующие строки:
Host e2k-proxy HostName <доменное имя или ip вашего хоста> ForwardAgent yes Host 192.168.103.* ProxyCommand ssh e2k-proxy -W [%h]:%p
После этих настроек все соединения на хосты с адресами 192.168.103.1/24 (сеть которую мы настраивали ранее в файле /etc/default/lxc-net) будут осуществляться через хостовую систему.
Второй вариант, выставить контейнер наружу сетевым интерфейсом. Такое возможно, если вместо veth мы будем использовать macvlan, для этого в конфигурацию контейнера (/var/lib/lxc/<имя контейнера>/config) нужно внести следующие изменения:
lxc.network.type = macvlan lxc.network.macvlan.mode = bridge lxc.network.link = eth0
Если ваш контейнер был запущен, то перезапускаем его. Подключаемся к нему и настраиваем сетевой интерфейс. Пример файла ipv4 для статического адреса выглядит так:
IP=192.168.103.2 GATEWAY=192.168.103.1 PREFIX=24 CHECK_LINK=yes ONBOOT=yes TYPE=Ethernet SERVICE=ipv4-static
Вместо заключения
В статье не затронуто много аспектов работы с LXC, я постарался сделать больше упор на специфику ОС Эльбрус. Как вы уже поняли, работа с LXC на Эльбрусе не отличается от таковой в других дистрибутивах Linux и на других архитектурах процессоров.
По первым результатам работы коллег, у нас уже появились планы по улучшению текущей системы:
запустить альтернативные операционные системы в контейнерах (под Эльбрус есть как минимум еще Альт и Astra Linux)
создать контейнеры с GUI для случаев когда требуется посмотреть как это будет работать у пользователя
ну и мы уже начали работу по автоматизации, там тоже поле не паханое и очень интересное.
