Авторские статьи

LXC 1.0: Более углублённое использование контейнера.


Статья 4 из 10, в которой речь пойдёт об LXC: запуск отличных от хоста архитектур, хуки, контейнер с андроидом.

Запуск других архитектур.

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

Но есть волшебный пакет qemu-user-static, который содержит кучу эмуляторов популярных архитектур: ARM, CRIS, i386, M68k (ColdFire), MicroBlaze, MIPS, PowerPC, SH4, SPARC и x86-64. Шаблон ubuntu знает как использовать qemu-user-static, если он установлен, и можно создать контейнер с архитектурой ARM так:
sudo lxc-create -t ubuntu -n p3 -- -a armhf

После довольного долгого bootstrap'а будет создан контейнер p3, который по большей части будет обеспечивать работу Ubuntu на armhf. По большей части потому, что эмуляция QEMU идёт с рядом ограничений. Самое серьёзное ограничение - софт не может использовать системный вызов ptrace() и netlink. Поэтому LXC поставит в контейнер часть софта с архитектурой хоста, а не ту что ему указали. В эту часть софта входят: upstart (из-за ptrace) и mountall, iproute, isc-dhcp-client (из-за netlink).

Хост file /bin/ls

/bin/ls: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), 
for GNU/Linux 2.6.24, ""BuildID[sha1]"" =e50e0a5dadb8a7f4eaa2fd715cacb9842e157dc7, stripped

Запуск контейнера
sudo lxc-start -n p3 -d
sudo lxc-attach -n p3

В контейнере root@p3:/# file /bin/ls

/bin/ls: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), 
for GNU/Linux 2.6.32, ""BuildID[sha1]"" =88ff013a8fd9389747fb1fea1c898547fb0f650a, stripped

Хуки.

Конфигурация контейнера не всегда может удовлетворить все случаи использования и поэтому введён ряд хуков. Хуки представляют собой исполняемые файлы с полным путём к нему, которые LXC будет вызывать в определённое время в жизненном цикле контейнера. Хукам от LXC передаются полезные переменные окружения, чтобы они легко понимали с каким контейнером их вызвали и что делать.

Список хуков (детали в lxc.conf(5))

  • lxc.hook.pre-start вызывается ДО завершения любых инициализаций.
  • lxc.hook.pre-mount вызывается ПОСЛЕ создания пространства имён mount, но ДО монтирования чего-либо.
  • lxc.hook.mount вызывается ПОСЛЕ монтирования, но ДО pivot_root.
  • lxc.hook.autodev идентично хуку mount, но вызывается, если используется autodev.
  • lxc.hook.start вызывается ПЕРЕД непосредственным вызовом /sbin/init.
  • lxc.hook.post-stop вызывается ПОСЛЕ остановки контейнера.
  • lxc.hook.clone вызывается когда клонируется контейнер.

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

  • lxc.network.script.up вызывается в сетевом пространстве имён ПОСЛЕ создания интерфейса.
  • lxc.network.script.down вызывается в сетевом пространстве имён ДО удаления интерфейса.

Для примера, укажем для контейнера p1 в его конфиге
lxc.hook.pre-start = /var/lib/lxc/p1/pre-start.sh

Создадим исполняемый файл /var/lib/lxc/p1/pre-start.sh
#!/bin/sh
echo "arguments: $*" > /tmp/test
echo "environment:" >> /tmp/test
env | grep LXC >> /tmp/test

После перезагрузки контейнера p1, должен создаться /tmp/test с содержимым:
arguments: p1 lxc pre-start
environment:
LXC_ROOTFS_MOUNT=/usr/lib/x86_64-linux-gnu/lxc
LXC_CONFIG_FILE=/var/lib/lxc/p1/config
LXC_ROOTFS_PATH=/var/lib/lxc/p1/rootfs
LXC_NAME=p1

Контейнер с Андроидом.

Часто интересуются вопросом, а возможен запуск Android в LXC контейнере? Кратко: да. Однако не всё так просто и смотря что хочется с ним сделать.

Первое, что нужно сделать для запуска Андроида, нужны загруженные модули для построения и запуска контейнера. Предположим, что вы создали контейнер android с архитектурой armhf и нужно подправить его конфигурационный файл и добавить строки:
lxc.rootfs = /var/lib/lxc/android/rootfs
lxc.utsname = armhf

lxc.network.type = none

lxc.devttydir = lxc
lxc.tty = 4
lxc.pts = 1024
lxc.arch = armhf
lxc.cap.drop = mac_admin mac_override
lxc.pivotdir = lxc_putold

lxc.hook.pre-start = /var/lib/lxc/android/pre-start.sh

lxc.aa_profile = unconfined

Самое главное тут - хук /var/lib/lxc/android/pre-start.sh. В нём должны быть строки

#!/bin/sh
mkdir -p $LXC_ROOTFS_PATH
mount -n -t tmpfs tmpfs $LXC_ROOTFS_PATH
cd $LXC_ROOTFS_PATH
cat /var/lib/lxc/android/initrd.gz | gzip -d | cpio -i
# Create /dev/pts if missing
mkdir -p $LXC_ROOTFS_PATH/dev/pts

Когда стартует LXC контейнер Android, его initrd распаковывается в tmpfs (аналог андроидного ramfs). Android Init стартует, монтирует нужные разделы и запускает свои сервисы. Так как мы указали неограниченный (unconfined) AppArmor, то без ограничений cgroup контейнер будет обладать многими правами и даже может привести к краху хост-машины. Нужны знания об устройстве Android и не бояться вносить изменения в init скрипты. Нельзя дать единый рецепт, поскольку многое зависит от: версия Андроида, что вы хотите реализовать, используемые устройства. Но самое главное, что всё реализуемо и можно многое почерпнуть из проекта Ubuntu Touch, где в LXC контейнере работает Андроид над низкосистемными вещами и для использования закрытых видеодрайверов.

Последнее замечание. У Андроид init скрипт НЕ /sbin/init, поэтому запуск контейнера с Android нужно выполнять так: sudo lxc-start -n android -- /init

LXC на Android.

Выше было рассказано, как в Ubuntu хост создать контейнер LXC, а в нём Android. Можно на Андроид хосте создать LXC контейнер и туда посадить Ubuntu. LXC портирована на bionic (Android C library) и, хотя это не полный эквивалент версии с glibc, но достаточно хорошо работает.

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

Всегда новый LXC для использования на платформе Android можно найти по адресу:
http://qa.linuxcontainers.org/master/current/android-armel/lxc-android.tar.gz

Гарантируется работа с Android >= 4.2, но и старые версии должны работать без проблем. Для того чтобы всё заработало, требуется конфигурация вашего ядра и lxc-checkconfig должен отобразить совместимость с LXC или отсутствие оной. К сожалению, вероятнее всего ответ - нет! Тогда нужны исходники ядра для вашего устройства и, добавив нужные параметры ядра, скомпилировать и обновить ядро.

Это страшно звучит, но на практике всё не так сложно. Особенно, если используется альтернативный ROM типа Cyanogen. После проделанной работы над ядром, нужно просто распаковать скачанный тарбол в корень (/) вашего устройства. Ваш контейнер с Ubuntu на архитектуре ARM нужно скопировать в /data/lxc/containers/имя-контейнера и запустить ./run-lxc lxc-start -n имя-контейнера

Несколько секунд и должно появиться приветствие с запросом логина и пароля.


Предыдущая статья LXC 1.0: Продвинутое использование контейнера.
Следующая статья LXC 1.0: Хранилище контейнеров.

Дополнительные материалы:
Серия статей LXC 1.0. от Стефана Грабера.
Андроид программы в Ubuntu.
Перевёрнутая модель Ubuntu Touch. Теперь Андроид в контейнере LXC.
Зачем и как будет использоваться Android в Ubuntu Touch.

Дата последней правки: 2023-12-28 14:21:20

RSS vasilisc.com   


Разделы

Главная
Новости
Ворох бумаг
Видео Linux
Игры в Linux
Безопасность
Статьи об Astra Linux
Статьи о FreeBSD
Статьи об Ubuntu
Статьи о Snappy
Статьи об Ubuntu Phone
Статьи о Kubuntu
Статьи о Xubuntu
Статьи о Lubuntu
Статьи об Open Source
Карта сайта