Въведение от преводача: На фона на масовото навлизане на различни контейнери в живота ни, може да бъде доста интересно и полезно да научим, от какви технологии всичко това е започнало. Някои от тях все още могат да бъдат използвани и днес, но не всички помнят (или знаят, ако не са били свидетели на бурното им развитие). Една от тези технологии е User Mode Linux. Авторът на оригинала е провел задълбочено проучване, за да разбере какво от старите разработки все още работи и какво не, и е събрал нещо като стъпка по стъпка инструкция за това как да си направите домашен UML през 2019 година. И да, поканихме за Хабр автора на оригиналния пост. , така че ако имате въпроси — задавайте на английски в коментарите.

User Mode в Linux всъщност е порт на ядрото на Linux върху самото себе си. Режимът позволява стартиране на полноценно ядро на Linux като потребителски процес и обикновено се използва от разработчици за тестване на драйвери. Но този режим е полезен и като инструмент за обща изолация, принципът на който е сходен с работата на виртуалните машини. Този режим осигурява по-голяма изолация от Docker, но по-малка от пълноценна виртуална машина, като KVM или Virtual Box.
Като цяло, User Mode може да изглежда странен и сложен за използване инструмент, но все пак има свои области на приложение. Това е пълноценно ядро на Linux, работещо от непривилегирован потребител. Тази характеристика позволява стартиране на потенциално ненадежден код без никакви заплахи за хост машината. А тъй като е пълноценно ядро, неговите процеси са изолирани от хост машината, а именно процесите, работещи в рамките на User Mode, няма да бъдат видими за хост система. Това не е като обичайния Docker контейнер, при който хост машината винаги вижда процесите вътре в хранилището. Погледнете този фрагмент от pstree от един от моите сървъри:
containerd─┬─containerd-shim─┬─tini─┬─dnsd───19*[{dnsd}]
│ │ └─s6-svscan───s6-supervise
│ └─10*[{containerd-shim}]
├─containerd-shim─┬─tini─┬─aerial───21*[{aerial}]
│ │ └─s6-svscan───s6-supervise
│ └─10*[{containerd-shim}]
├─containerd-shim─┬─tini─┬─s6-svscan───s6-supervise
│ │ └─surl
│ └─9*[{containerd-shim}]
├─containerd-shim─┬─tini─┬─h───13*[{h}]
│ │ └─s6-svscan───s6-supervise
│ └─10*[{containerd-shim}]
├─containerd-shim─┬─goproxy───14*[{goproxy}]
│ └─9*[{containerd-shim}]
└─32*[{containerd}]И сравнете това с pstree на ядрото на Linux в потребителски режим:
linux─┬─5*[linux]
└─slirpПри работа с Docker контейнери, мога да виждам от хоста имената на процесите, които са стартирани в гостуващата система. С Linux User Mode това е невъзможно. Какво означава това? Това означава, че инструментите за мониторинг, работещи чрез подсистемата за одит на Linux (Linux’s auditing subsystem) не виждат процесите, изпълнявани в гостуващата система. Но в някои ситуации тази особеност може да стане двуостра работа.
Целият пост по-долу е набор от изследвания и груби опити да се постигне желания резултат. За това ми се наложи да използвам различни стари инструменти, да чета изходния код на ядрото, да се занимавам с интензивна отладка на код, написан в епохата, когато все още ходех в начално училище, както и да се ровя в сборките на Heroku с помощта на специален бинарник в търсене на необходимите инструменти. Всичка тази работа доведе до това, че момчетата в IRC започнаха да ме наричат магьосница (magic). Надявам се, че този пост ще послужи на някого като надеждна документация за това как да направи същото, но вече с по-нови ядра и версии на ОС.
Настройка
Настройката на Linux User Mode се извършва в няколко етапа:
- инсталиране на зависимости на хоста;
- сваляне на ядрото на Linux;
- настройка на конфигурацията на ядрото;
- сборка на ядрото;
- инсталация на бинарника;
- настройка на файловата система на госта;
- определяне на параметрите за стартиране на ядрото;
- настройка на мрежата на госта;
- стартиране на гостуващото ядро.
Предполагам, че ако решите да опитате сами, вероятно ще правите всичко описано в някаква система, подобна на Ubuntu или Debian. Опитвах се да реализирам всичко по-гореописано в любимия си дистрибутив — Alpine, но нищо не се получи, вероятно поради факта, че ядрото на Linux има строга зависимост от glibc-isms за драйвери в потребителски режим. Планирам да съобщя за това в upstream, след като окончателно разбера проблема.
Инсталиране на зависимости на хоста
Ubuntu изисква поне следните пакети за компилиране на ядрото на Linux (при условие на чиста инсталация):
- 'build-essential'
- 'flex'
- 'bison'
- 'xz-utils'
- 'wget'
- 'ca-certificates'
- 'bc'
- 'linux-headers'
Можете да ги инсталирате с помощта на следната команда (с root права или с помощта на sudo):
apt-get -y install build-essential flex bison xz-utils wget ca-certificates bc
linux-headers-$(uname -r) Обърнете внимание, че стартирането на програмата за настройка на менюто за ядрото на Linux ще изисква инсталиране на libncurses-dev. Моля, уверете се, че той е инсталиран с помощта на следната команда (с root права или с помощта на sudo):
apt-get -y install libncurses-devИзтегляне на ядрото
Определете местоположението за изтегляне и последваща компилация на ядрото. За тази операция ще ви е необходимо около 1.3 GB пространство на твърдия диск, така че се уверете, че разполагате с него.
След това отидете на и вземете URL адреса за изтегляне на последната стабилна версия на ядрото. Към момента на писане на поста това е:
Изтеглете този файл, използвайки 'wget':
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz И го извлечете с помощта на 'tar':
tar xJf linux-5.1.16.tar.xzСега влезте в директорията, създадена при разархивирането на tarball:
cd linux-5.1.16Настройка на компилацията на ядрото
Системата за компилиране на ядрото е набор от с с множество потребителски инструменти и скриптове за автоматизация на процеса. За начало отворете интерактивната програма за настройка:
make ARCH=um menuconfig Тя частично ще проведе компилацията и ще ви изведе диалогово прозорче. Когато в долната част на прозорцето се появи ‘[Select]‘, ще можете да се захванете с настройките с клавишите Space или Enter. Навигацията в прозореца става, както обикновено, с клавишите стрелки «нагоре» и «надолу», а избора на елементи — «наляво» или «надясно».
Иконката вида —> означава, че сте в подменю, входът в което става с клавиша Enter. Изходът от него, очевидно, е чрез ‘[Exit]‘.
Включете следните параметри в ‘[Select]‘ и се уверете, че до тях е символ ‘[*]’:
Опции, специфичные для UML:
- Хост файловой системы
Поддержка сетей (включите это, чтобы меню появилось):
- Сетевые настройки:
- TCP/IP Сетевое взаимодействие
Устройства сети UML:
- Виртуальное сетевое устройство
- SLiRP транспорт Отсюда можно выходить, последовательно выбирая ‘[Exit]‘. Убедитесь, что в конце вам предложат сохранить конфигурацию и выберите ‘[Да]‘.
Рекомендую вам поэкспериментировать с параметрами сборки ядра после чтения этого поста. Благодаря этим экспериментам вы сможете лучше понять низкоуровневые механики ядра и влияние различных флагов на его сборку.
Сборка ядра
Ядро Linux — это большая программа, занимающаяся множеством задач. Даже при такой минимальной конфигурации на старом оборудовании его сборка может занять довольно много времени. Поэтому собирайте ядро с помощью следующей команды:
make ARCH=um -j$(nproc) Зачем? Эта команда указывает нашему сборщику использовать все доступные ядра и потоки процессора в процессе сборки. Команда $(nproc) в конце сборки подставляет вывод команды nproc, которая является частью coreutils в стандартной сборке Ubuntu.
После некоторого времени наше ядро будет собрано в исполняемый файл ./linux.
Инсталляция бинарника
Так как User Mode в Linux создает обычный бинарник, вы можете установить его так же, как любую другую утилиту. Вот как я это делала:
mkdir -p ~/bin
cp linux ~/bin/linux Также стоит убедиться, что ~/bin находится в вашем $PATH:
export PATH=$PATH:$HOME/binНастройка гостевой файловой системы
Создайте директорию для гостевой файловой системы:
mkdir -p $HOME/prefix/uml-demo
cd $HOME/prefix
Откройте alpinelinux.org и в найдите актуальную ссылку на скачивание MINI ROOT FILESYSTEM. На момент написания публикации это было:
http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gzСкачайте этот tarball, используя wget:
wget -O alpine-rootfs.tgz http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gzТеперь войдите в директорию гостевой файловой системы и распакуйте архив:
cd uml-demo
tar xf ../alpine-rootfs.tgzЭти действия создадут маленький шаблон файловой системы. Из-за особенностей работы системы устанавливать пакеты через диспетчер apk Alpine будет крайне сложно. Но данной файловой системы будет достаточно для оценки общей идеи.
Также нам потребуется инструмент для предотвращения потребления памяти нашего гостевого ядра.
wget -O tini https://github.com/krallin/tini/releases/download/v0.18.0/tini-static
chmod +x tiniСоздание командной строки ядра
В ядрото на Linux, както и в повечето други програми, има аргументи за команден ред, с които можете да се запознаете, като посочите ключа --help.
Сам —help
linux --help
User Mode Linux v5.1.16
наличен на http://user-mode-linux.sourceforge.net/
--showconfig
Печати конфигурационния файл, от който е генериран този UML бинарен файл.
iomem=,
Конфигурирайте като IO мемориен регион с име .
mem=
Това контролира колко "физическа" памет ядрото разпределя
за системата. Размерът се посочва като число, последвано от
едно от 'k', 'K', 'm', 'M', които имат очевидни значения.
Това не е свързано с количеството памет на хоста. То може
да бъде повече, и излишъкът, ако е използван, ще бъде просто разбит.
Пример: mem=64M
--help
Печати това съобщение.
debug
този флаг не е необходим, за да се стартира gdb на UML в skas режим
root=
Това всъщност се използва от общото ядро точно по същия
начин, както в която и да е друга ядрена. Ако конфигурирате няколко блокови
устройства и искате да стартирате от нещо различно от ubd0, ще
използвате нещо като:
root=/dev/ubd5
--version
Печати номер на версията на ядрото.
umid=
Това се използва, за да се зададе уникална идентичност на тази UML машина и
се използва за именуване на pid файла и сокета на управленската конзола.
con[0-9]*=
Свържете конзола или сериен ред към хост канал. Вижте
http://user-mode-linux.sourceforge.net/old/input.html за пълно
описание на този ключ.
eth[0-9]+=,
Конфигурирайте мрежово устройство.
aio=2.4
Това се използва, за да принуди UML да използва 2.4-стил AIO дори когато 2.6 AIO е
наличен. 2.4 AIO е един поток, който обработва едно искане по
време, синхронно. 2.6 AIO е поток, който използва 2.6 AIO
интерфейса, за да обработва произволен брой висящи искания. 2.6 AIO
не е наличен в tt режим, на 2.4 хостове или когато UML е построен с
/usr/include/linux/aio_abi.h не е наличен. Много дистрибуции не
включват aio_abi.h, така че ще трябва да го копирате от дерева
на ядро в /usr/include/linux, за да изградите AIO-способен UML
nosysemu
Изключва емилация на системни повиквания за ptrace (SYSEMU).
SYSEMU е патч за производителност, въведен от Лоран Вивиер. Променя
поведението на ptrace() и помага за намаляване на скоростите на
превключване на контекста на хоста.
За да работи, ви е необходим и патч на ядрото за вашия хост.
Вижте http://perso.wanadoo.fr/laurent.vivier/UML/ за допълнителна
информация.
uml_dir=
Мястото за разположение на pid и umid файловете.
quiet
Изключва информационните съобщения по време на стартиране.
hostfs=,,...
Използва се за задаване на параметрите на hostfs. Аргументът на кореновата директория
се използва, за да ограничи всички hostfs монтирания в зададеното
дървовидно структура на хоста. Ако това не е зададено, потребител
вътре в UML може да монтира всичко на хоста, до което има
достъп потребителят, който го стартира.
Единственият флаг, който в момента се поддържа, е 'append', който
указва, че всички файлове, отворени от hostfs, ще бъдат отворени в
режим на добавяне.Този флаг осветява основните параметри на стартирането. Нека стартираме ядрото с минимално необходимия набор от опции:
linux
root=/dev/root
rootfstype=hostfs
rootflags=$HOME/prefix/uml-demo
rw
mem=64M
init=/bin/shРедовете по-горе казват на нашето ядро следното:
- Да предположим, че кореновата файлова система е псевдо-устройство.
/dev/root. - Избери като драйвер на основната файлова система.
- Монтирайте гостуващата файлова система, която създадохме в root устройството.
- И да, в режим на четене и запис.
- Използвайте само 64 мегабайта оперативна памет (можете да използвате значително по-малко, в зависимост от това, което планирате да правите, но 64 МБ изглеждат оптималното количество).
- Ядрото автоматично стартира
/bin/shкатоinit-процес.
Изпълнете тази команда и трябва да получите нещо като следното:
Още един лист
Ограничения на сървърния дъмп:
меко - 0
твърдо - НЯМА
Проверка дали ptrace може да променя системните повиквания...ОК
Проверка за пач за емулация на системните повиквания за ptrace...ОК
Проверка за напреднал пач за емулация на системните повиквания за ptrace...ОК
Проверка на променливите на средата за временно директория...не са намерени
Проверка дали /dev/shm е на tmpfs...ОК
Проверка PROT_EXEC mmap в /dev/shm...ОК
Добавяне на 32137216 байта към физическата памет, за да се компенсира пропуск в exec-shield
Версия на Linux 5.1.16 (cadey@kahless) (gcc версия 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Неделя, 7 юли 2019 г. 18:57:19 UTC
Създадени 1 зонови списъци, групиране на мобилност. Общо страници: 23898
Команден ред на ядрото: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Хеш таблица на кеша за директории: 16384 (порядък: 5, 131072 байта)
Хеш таблица на кеша на inode: 8192 (порядък: 4, 65536 байта)
Памет: 59584K/96920K налична (2692K код на ядрото, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K резервирани, 0K cma-резервирани)
SLUB: HWalign=64, Поръчка=0-3, MinObjects=0, CPUs=1, Възли=1
NR_IRQS: 15
source на времето: таймер: маска: 0xffffffffffffffff макс. цикли: 0x1cd42e205, макс. idle_ns: 881590404426 нс
Калибриране на забавяне... 7479.29 BogoMIPS (lpj=37396480)
pid_max: по подразбиране: 32768 минимум: 301
Хеш таблица на кеша за монтиране: 512 (порядък: 0, 4096 байта)
Хеш таблица на кеша за точките за монтиране: 512 (порядък: 0, 4096 байта)
Проверка дали host ptys поддържат изход SIGIO...Да
Проверка дали host ptys поддържат SIGIO при затваряне...Не, активиране на решение
devtmpfs: инициализирано
random: get_random_bytes извикано от setup_net+0x48/0x1e0 с crng_init=0
Използване на 2.6 host AIO
source на времето: jiffies: маска: 0xffffffff максимални цикли: 0xffffffff, макс. idle_ns: 19112604462750000 нс
футекс хеш таблица: 256 (порядък: 0, 6144 байта)
NET: Регистрирано семейство протоколи 16
source на времето: Превключено на source на времето таймер
NET: Регистрирано семейство протоколи 2
tcp_listen_portaddr_hash хеш таблица: 256 (порядък: 0, 4096 байта)
TCP установена хеш таблица: 1024 (порядък: 1, 8192 байта)
TCP хеш таблица за свързване: 1024 (порядък: 1, 8192 байта)
TCP: Хеш таблиците конфигурирани (установени 1024 свързване 1024)
UDP хеш таблица: 256 (порядък: 1, 8192 байта)
UDP-Lite хеш таблица: 256 (порядък: 1, 8192 байта)
NET: Регистрирано семейство протоколи 1
конзола [stderr0] деактивирана
mconsole (версия 2) инициализирана на /home/cadey/.uml/tEwIjm/mconsole
Проверка на поддръжка на host MADV_REMOVE...ОК
работен набор: timestamp_bits=62 max_order=14 bucket_order=0
Блоков слой SCSI генерален (bsg) драйвер версия 0.4 зареден (основен 254)
планиратор на операции noop регистриран (по подразбиране)
планиратор на операции bfq регистриран
loop: модулът зареден
NET: Регистрирано семейство протоколи 17
Инициализирана стандартна конзола драйвер
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 1 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 2 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 3 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 4 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 5 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 6 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 7 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 8 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 9 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 10 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 11 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 12 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 13 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 14 : Конфигурацията е неуспешна
Използване на тип канал, който е конфигуриран извън UML
setup_one_line неуспех за устройство 15 : Конфигурацията е неуспешна
Конзолата е инициализирана на /dev/tty0
конзола [tty0] активирана
конзола [mc-1] активирана
Неуспешно инициализиране на ubd устройство 0 :Не може да се определи размерът на файла на устройството
VFS: Монтиране на корен (hostfs файловата система) на устройство 0:11.
devtmpfs: монтирано
Тази архитектура няма защита на паметта на ядрото.
Стартиране на /bin/sh като процес init
/bin/sh: не може да се получи достъп до tty; управлението на работата е изключено
random: бързо инициализиране завършено
/ # Манипулации по-горе ще ни дадат хоства система на минималном ниво, без такива неща, като /proc или присвоен хостнейм. За пример, опитайте да изпълните следните команди:
- uname -av
- cat /proc/self/pid
- hostname
За да излезете от хоства система, напишете exit или натиснете control-d. Това ще уби-оболочката с последващ kernel panic:
/ # exit
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
fish: “./linux root=/dev/root rootflag…” terminated by signal SIGABRT (Abort) Получихме този kernel panic поради факта, че ядрото Linux счита, че процесът на инициализация винаги е активен. Без него системата повече не може да функционира и спира. Но тъй като това е процес на потребителски режим, резултатът сам изпраща себе си в SIGABRT, което води до изход.
Настройка на хоства мрежа
А тук нещата започват да не вървят по план. Мрежата в User Mode Linux — това е мястото, където цялата концепция за ограничен «потребителски режим» започва да се разпада. На системно ниво мрежата обикновено е ограничена привилегированими режими на изпълнение по всички ни известни причини.
Поч. заб.: повече за различните варианти на работа с мрежата в UML може да се прочете .
Пътуване в slirp
Въпреки това, съществува древен и практически незаслужен инструмент на име , чрез който User Mode Linux може да взаимодейства с мрежата. Той работи приблизително като стек TCP/IP на ниво потребител и не изисква никакви системни разрешения за работа. Този инструмент е пуснат през 1995 година, а последната актуализация е от 2006 година. Slirp е много стар. През времето на липса на поддръжка и актуализации компилаторите толкова се развиха, че сега инструментът може да бъде описан само като .
И така, нека инсталираме Slirp от репозиторите на Ubuntu и опитаме да го пуснем:
sudo apt-get install slirp
/usr/bin/slirp
Slirp v1.0.17 (BETA)
Copyright (c) 1995,1996 Danny Gasparovski и други.
Всички права запазени.
Тази програма е защитена с авторски права, безплатен софтуер.
Моля, прочетете файла COPYRIGHT, който идва с пакета Slirp
за условията на авторските права.
IP адрес на хост Slirp: 127.0.0.1
IP адрес на вашите DNS: 1.1.1.1, 10.77.0.7
Вашият адрес е 10.0.2.15
(или каквото друго искате)
Напишете пет нули (0), за да излезете.
[автоопределяне SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]
SLiRP Готов ...
fish: "/usr/bin/slirp" е прекратен от сигнал SIGSEGV (Грешка в адресна граница)Ох, божички. Нека инсталираме отладчик за Slirp и да видим дали можем да разберем какво тук става:
sudo apt-get install gdb slirp-dbgsym
gdb /usr/bin/slirp
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/bin/slirp...Reading symbols from /usr/lib/debug/.build-id/c6/2e75b69581a1ad85f72ac32c0d7af913d4861f.debug...done.
done.
(gdb) run
Starting program: /usr/bin/slirp
Slirp v1.0.17 (BETA)
Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.
IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)
Type five zeroes (0) to exit.
[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]
SLiRP Ready ...
Program received signal SIGSEGV, Segmentation fault.
ip_slowtimo () at ip_input.c:457
457 ip_input.c: No such file or directory.Грешка появляется у нас в . Нека видим стека на грешки, може там нищо не помогне:
(gdb) bt full
#0 ip_slowtimo () at ip_input.c:457
fp = 0x55784a40
#1 0x000055555556a57c in main_loop () at ./main.c:980
so =
so_next =
timeout = {tv_sec = 0, tv_usec = 0}
ret = 0
nfds = 0
ttyp =
ttyp2 =
best_time =
tmp_time =
#2 0x000055555555b116 in main (argc=1, argv=0x7fffffffdc58) at ./main.c:95
No locals.Тук виждаме, че сривът настъпва по време на стартиране на основния цикъл, когато slirp се опитва да провери таймаутите. В този момент трябваше да се откажа от опитите за отстраняване на грешки. Но нека видим дали Slirp, компилиран от източници, ще работи. Свалих отново архива директно от сайта , защото да теглим нещо оттам през командния ред е болка:
cd ~/dl
wget https://xena.greedo.xeserv.us/files/slirp-1.0.16.tar.gz
tar xf slirp-1.0.16.tar.gz
cd slirp-1.0.16/src
./configure --prefix=$HOME/prefix/slirp
make Тук виждаме предупреждения за неопределени вградени функции, тоест за невъзможност да се свърже получаващият се бинарен файл. Изглежда, че между 2006 година и този момент gcc е спрял да създава символите, използвани в вградени функции на междинно компилирани файлове. Нека опитаме да заменим ключовата дума inline с празен коментар и да видим резултата:
vi slirp.h
:6
a
#define inline /**/
:wq
makeНе. И това не работи. Все още не може да се намерят символите на тези функции.
На този етап се предадох и започнах да търся в Github . Моята теория беше, че в някой от пакетите за компилиране на Heroku трябва да има необходимите за мен бинарни файлове. В крайна сметка търсенето ме отведе . Изтеглих и разархивирах uml.tar.gz и намерих следното:
total 6136
-rwxr-xr-x 1 cadey cadey 79744 Dec 10 2017 ifconfig*
-rwxr-xr-x 1 cadey cadey 373 Dec 13 2017 init*
-rwxr-xr-x 1 cadey cadey 149688 Dec 10 2017 insmod*
-rwxr-xr-x 1 cadey cadey 66600 Dec 10 2017 route*
-rwxr-xr-x 1 cadey cadey 181056 Jun 26 2015 slirp*
-rwxr-xr-x 1 cadey cadey 5786592 Dec 15 2017 uml*
-rwxr-xr-x 1 cadey cadey 211 Dec 13 2017 uml_run*Това е бинарен файл slirp! А той работи?
./slirp
Slirp v1.0.17 (BETA) FULL_BOLT
Copyright (c) 1995,1996 Danny Gasparovski и други.
Всички права запазени.
Тази програма е защитена с авторски права, безплатен софтуер.
Моля, прочетете файла COPYRIGHT, който подлежи на пакета Slirp
за условията и условията на авторските права.
IP адрес на хоста Slirp: 127.0.0.1
IP адрес на вашия DNS: 1.1.1.1, 10.77.0.7
Вашият адрес е 10.0.2.15
(или каквото и да искате)
Напишете пет нули (0), за да излезете.
[автооткриване SLIP/CSLIP, MTU 1500, MRU 1500]
SLiRP Готови ...
Не пада — така че трябва да проработи! Нека качим този бинарник в ~/bin/slirp:
cp slirp ~/bin/slirpВ случай, че създателят на пакета реши да го премахне, аз .
Настройка на мрежата
Сега нека настроим мрежата на нашето гостоприемно ядро. :
linux
root=/dev/root
rootfstype=hostfs
rootflags=$HOME/prefix/uml-demo
rw
mem=64M
eth0=slirp,,$HOME/bin/slirp
init=/bin/shСега нека активираме мрежата:
mount -t proc proc proc/
mount -t sysfs sys sys/
ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2 Първите две команди за настройка /proc и /sys са необходими за работа. ifconfig, която определя мрежовия интерфейс за връзка със Slirp. Командата route настройва таблицата за маршрутизиране на ядрото, за да принуди целия трафик да преминава през тунела Slirp. Нека проверим това с DNS заявка:
nslookup google.com 8.8.8.8
Сървър: 8.8.8.8
Адрес 1: 8.8.8.8 dns.google
Име: google.com
Адрес 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Адрес 2: 2607:f8b0:4006:81b::200e lga25s63-in-x0e.1e100.netРаботи!
Бележка: Изглежда, че оригиналната публикация е била написана на десктоп с проводна мрежова карта или друга конфигурация, която не изисква допълнителни драйвери. На лаптоп с WiFi 8265 от Intel обаче при настройка на мрежата се появява грешка.
/ # ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
slirp_tramp failed - errno = 2
ifconfig: ioctl 0x8914 failed: No such file or directory
/ #Очевидно, ядро не может связаться с драйвером сетевой карты. Попытка встроить прошивку в ядро ситуацию, к сожалению, не исправила. На момент публикации в такой конфигурации решение пока не найдено. В более простых конфигурациях (например, в Virtualbox) интерфейс поднимается корректно.
Давайте автоматизируем перенаправление с помощью следующего shell-скрипта:
#!/bin/sh
# init.sh
mount -t proc proc proc/
mount -t sysfs sys sys/
ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2
echo "networking set up"
exec /tini /bin/shИ отметим его исполняемым:
chmod +x init.shА затем внесем изменения в командную строку ядра:
linux
root=\/dev\/root
rootfstype=hostfs
rootflags=$HOME\/prefix\/uml-demo
rw
mem=64M
eth0=slirp,,$HOME\/bin\/slirp
init=\/init.sh
И повторим:
SLiRP Ready ...
networking set up
\/bin\/sh: can't access tty; job control turned off
nslookup google.com 8.8.8.8
Server: 8.8.8.8
Address 1: 8.8.8.8 dns.google
Name: google.com
Address 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Address 2: 2607:f8b0:4004:800::200e iad30s09-in-x0e.1e100.netСеть работает стабильно!
Docker-файл
Чтобы вам было проще все это проверить, я собрала , который автоматизирует большинство описанных шагов и должен обеспечить вам рабочую конфигурацию. Еще у меня есть , в которой есть все, что описано в посте. Но важно понимать, что тут я изложила только минимальную настройку.
Я надеюсь, что этот пост помог вам понять, как поднять гостевое ядро. Получился какой-то монстр, но публикация задумывалась как всеобъемлющее руководство на тему сборки, установки и настройки User Mode в Linux под современными версиями операционных систем этого семейства. Последующие действия должны включать в себя установку сервисов и прочего программного обеспечения уже внутри гостевой системы. Так как образы контейнеров Docker — это просто распакованные tar-архивы, вы должны быть в состоянии извлечь образ через docker export, а затем определить путь его установки в корне файловой системы гостевого ядра. Ну, а затем выполните shell-скрипт.
Отдельное спасибо Rkeene с #lobsters на Freenode. Без его помощи в отладке Slirp я бы не зашла так далеко. Я понятия не имею, как его система Slackware корректно работает со slirp, но мои системы Ubuntu и Alpine не приняли slirp и предложенный мне Rkeene бинарник. Но мне достаточно и того, что у меня работает хоть что-то.
Източник: habr.com
