Как создать систему Linux, которая запускает одно приложение?

17

Я пытаюсь запустить приложение Linux, и все, что я хочу запустить - это одно приложение без загрузки. Мне нужна сеть и все (без дисплея, периферии и т. Д.). Я не хочу, чтобы другие приложения работали, чтобы приложение, которое я запускаю, имело 100% ЦП. Это возможно?

dschatz
источник
Он не сможет захватить 100% ресурсов процессора, поскольку вашей ОС все еще нужны некоторые ресурсы.
n0pe
@MaxMackie Очевидно, но я бы хотел, чтобы ОС вступала во владение только от имени приложения (например, для сетевых целей).
dschatz
1
Вы понимаете, что даже с загруженной средой рабочего стола, но бездействующей, она не использует процессорное время, верно? И оперативная память, которую он использует, подлежит замене, если этого требуют другие приложения.
Псуси
@dschatz Было бы полезно, если бы вы включили больше деталей в свой вопрос. Например, рассказать нам больше о том, какое приложение вы хотите запустить, как вы хотите, чтобы оно работало, и какое оборудование вы используете.
NN
Если возможно, я хотел бы знать, почему вы этого хотите. Из того, что я понимаю, вы хотите удалить все из ОС (включая консоль) только для запуска вашего приложения. Повышение производительности будет незначительным, так какой смысл иметь всю эту работу?
nmat

Ответы:

13

Минимальная программа initrd CPIO hello world, шаг за шагом

введите описание изображения здесь

Скомпилируйте привет мир без каких-либо зависимостей, который заканчивается бесконечным циклом. init.S:

.global _start
_start:
    mov $1, %rax
    mov $1, %rdi
    mov $message, %rsi
    mov $message_len, %rdx
    syscall
    jmp .
    message: .ascii "FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n"
    .equ message_len, . - message

Мы не можем использовать sys_exit, иначе ядро ​​паникует.

Потом:

mkdir d
as --64 -o init.o init.S
ld -o init d/init.o
cd d
find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
ROOTFS_PATH="$(pwd)/../rootfs.cpio.gz"

Это создает файловую систему с нашим hello world at /init, которая является первой пользовательской программой, которую будет запускать ядро. Мы могли бы также добавить больше файлов, d/и они были бы доступны из /initпрограммы при запуске ядра.

Затем cdв дерево ядра Linux, сборка, как обычно, и запустить его в QEMU:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.9
make mrproper
make defconfig
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd "$ROOTFS_PATH"

И вы должны увидеть строку:

FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR

на экране эмулятора! Обратите внимание, что это не последняя строка, поэтому вам нужно посмотреть немного дальше.

Вы также можете использовать программы на C, если статически связываете их:

#include <stdio.h>
#include <unistd.h>

int main() {
    printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
    sleep(0xFFFFFFFF);
    return 0;
}

с:

gcc -static init.c -o init

Вы можете работать на реальном оборудовании с включенным USB /dev/sdXи:

make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX

Отличный источник на эту тему: http://landley.net/writing/rootfs-howto.html Также объясняется, как его использовать gen_initramfs_list.sh, это скрипт из дерева исходных текстов ядра Linux, помогающий автоматизировать процесс.

Следующий шаг: настройте BusyBox, чтобы вы могли взаимодействовать с системой: /unix/2692/what-is-the-smallest-possible-linux-implementation/203902#203902

Протестировано на Ubuntu 16.10, QEMU 2.6.1.

Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件
источник
3

Вы можете запустить ядро ​​с init=/path/to/myappпараметром, определенным в вашем загрузчике.

Михал Шрайер
источник
2
Это довольно экстремальное решение. Замена сценария запуска пользовательским приложением приведет к тому, что приложение будет работать без сети, без каких-либо файловых систем, кроме смонтированных rootfs (без sysfs, proc или tmpfs), и, возможно, некоторые узлы устройства не будут созданы.
опилки
2
@sawdust: полностью согласен. Но вопрос также был немного экстремальным ... :-)
Михал Шрайер
2

Похоже, вы пытаетесь установить киоск . Большинство руководств по Интернету фокусируются на веб-браузере, таком как Firefox, как на отдельном приложении, которое работает. Посмотрите на это руководство для идей.

Уильям Джексон
источник
2
Хм, я действительно просто пытаюсь запустить одно приложение с сетью. Я не хочу, чтобы X и как можно меньше других приложений работали. Я не вижу, как это ограничивает запуск всех ненужных демонов.
dschatz
может ли приложение работать без X, хотя?
Подмастерье Компьютерщик
2

Конечно, вы можете запустить только одно пользовательское приложение после загрузки ядра. Но у него не будет 100% ЦП, потому что будут некоторые другие процессы, связанные с ядром, которые должны существовать. Обычно это делается на устройствах со встроенным Linux, например, беспроводных маршрутизаторах. У меня также есть опыт из первых рук, делающий это для многопоточного приложения.

После загрузки ядра запускается сценарий инициализации или запуска. Читайте об уровнях запуска Linux и процессе init. Существуют различные схемы запуска, поэтому невозможно быть конкретным. Но Linux позволит вам точно настроить, какие приложения и демоны будут выполняться в вашей ситуации. За исключением файла запуска в корневом каталоге, файлы, которые необходимо изменить, находятся в / etc и, в частности, /etc/init.d

Кстати, если вы не являетесь суперпрограммистом или не запустили удаленный GDB-сервер, вам понадобится какая-то консоль отладки (консоль ПК или последовательный порт) для вашего приложения. Это позволит вам получать уведомления о сбоях сегмента, ошибках шины и ошибках подтверждения. Так что планируйте иметь что-то вроде «периферийного» помимо «сетевого».

опилки
источник
1

Есть некоторые системные приложения, которые должны быть запущены, кроме них, конечно, вы можете выделить остальные ресурсы компьютера для этого приложения. Чтобы получить минимум, вы можете взглянуть на действительно маленькие дистрибутивы Linux, такие как TinyCore Linux и т. Д.

Также это будет зависеть от самого приложения, каких сервисов оно требует помимо сети и т. Д.

Я думаю, что если вы сможете предоставить более конкретную информацию, вы получите более подробный ответ.

Как то, что приложение и т. Д.

bakytn
источник
Мое приложение использует библиотеку pthread для выполнения многопоточной рабочей нагрузки (арифметические операции) и может быть проинструктировано выполнять различные вычисления на основе ввода из tcp / ip. Глядя на TinyCore Linux, он загружается в полноценную рабочую среду, которая мне не нужна.
dschatz
У TinyCore есть младший брат по имени MicroCore. Нет графического интерфейса, проверьте это.
n0pe
1
@MaxMackie Я на самом деле не хочу никакого интерфейса на самой машине вне стека tcp / ip. Приложение может блокировать порт и может управляться с помощью пакетов tcp, отправляемых на этот порт.
dschatz
1
Я бы порекомендовал среду с небольшим количеством запущенных сервисов ( зацените linuxhelp.blogspot.com/2006/04/… ) и вряд ли что-то кроме вашего приложения и его установленных зависимостей.
n0pe
1
@dschatz, тогда вам нужно взломать ядро, удалить все остальное и собрать в него свое приложение. нет баш нет больше ничего только ваше приложение .. лол.
Бакытн,
1

Если вы действительно хотите ничего, кроме ядра Linux, работы в сети и своего приложения, единственный способ сделать это - это:

  • Вам нужно будет сделать ваше приложение модулем ядра - убедитесь, что оно отлажено и хорошо протестировано. Этот модуль ядра должен был бы инициализировать то, что обычно делается через пользовательское пространство, например, устанавливать IP-адреса интерфейса и все такое хорошее.
  • Вам нужно будет загрузить и настроить ( make menuconfig) свое собственное ядро ​​и удалить все функции, не связанные с работой системы и работой в сети. Вы захотите отключить, чтобы заблокировать слой, я не знаю, как это сделать на последних ядрах через make menuconfig.
  • Затем вам нужно включить ваш модуль в ядро, чтобы он был частью ядра, а не загружаемым модулем. Скорее всего, вы отключите загружаемые модули на шаге выше. Если вы знаете достаточно C / C ++ для создания модуля ядра, это должно быть легко для вас.
  • Вам нужно изменить любую часть ядра, которая паникует, если initне сможет этого сделать, или быть готовой к выполнению 1 дополнительного процесса в пространстве пользователя.

Я знаю, что модули ядра могут создавать процессы - простое ps auxпоказало бы многие в типичной системе (все они в скобках). Вы, вероятно, хотите, чтобы ваш модуль создал процесс ядра. Чтобы избавиться от всех процессов, созданных ядром, кроме ваших, вам необходимо отключить потоки [ kthreadd], управление питанием [ pm], слой событий [ events] и другие.


Если вам нужна более практичная настройка процесса ядра + 1 пользовательского пространства, это возможно.

В Linux есть опция командной строки ядра init=- это то, что запускается ядром после завершения загрузки. Программа должна находиться на корневом устройстве, указанном с помощью root=или в initrd (загруженном вашим загрузчиком).

Если эта программа закроется, Linux начнет паниковать, поэтому убедитесь, что она никогда не завершится.

Во многих современных дистрибутивах Linux это настроено так, что initпрограмма в initrd выполняет некоторую дополнительную инициализацию пользовательского пространства перед запуском /sbin/initили /sbin/systemd. Вам нужно выяснить, что делает ваш дистрибутив здесь (информация о Debian здесь ) и найти, где вы можете указать конечную программу «handoff», и оттуда вы можете указать ей запускать ваше приложение вместо initили systemd.

systemdуправляет многими основными функциями, такими как создание /dev, установка имени хоста и другими вещами, поэтому, если вы проявите гибкость, вы можете вместо этого взглянуть на настройку systemdдля порождения отдельного процесса и, при необходимости, перезапустить его в случае сбоя. Если я не ошибаюсь, он в основном делает это для однопользовательского режима или режима восстановления - он запускает оболочку.

У вас будет запущено 2 процесса ( systemdи ваша программа), но система не будет паниковать, если ваша программа закроется или завершится сбоем.

Рассмотрим также просто облегченную установку Debian - у установки «netinst» не так много работы, кроме ядра, оболочки и пары сервисов - или рассмотрим OpenWRT / LEDE - у нее есть веб-сервер для Luci, работающий по умолчанию, и пара других услуг, но легко отключается.

LawrenceC
источник