Статья 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.
Немає коментарів:
Дописати коментар