Не так давно Ростелеком объявил о создании центра компетенций по разработке программных решений под отечественные процессоры. Первая задача, которую нам пришлось решать как нам разграничить серверные ресурсы между сотрудниками занимающимися портированием и разработкой, организовать демонстрационные стенды, а, в перспективе, при росте нагрузок, ещё и управлять такими ресурсами как память и процессорное время.
Традиционно эту задачу решают средствами виртуализации, но, к сожалению, наши процессоры еще не поддерживают её. Альтернативным решением является контейнеризация. Изучив доступные варианты, которые можно реализовать на ОС Эльбрус, мы остановились на 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 для случаев когда требуется посмотреть как это будет работать у пользователя
ну и мы уже начали работу по автоматизации, там тоже поле не паханое и очень интересное.
D1abloRUS
Можно было и закончить на этом
ky0
Ага. Скроллю, скроллю - думаю, может какие-то неожиданные тентакли у LXC выросли, или утилиту какую крутую написали отечественные сумрачные гении... ан нет. Тогда, собственно, зачем?