Как стать автором
Обновить

Комментарии 44

Было бы неплохо ещё в конец статьи добавить как это дело всё прибить если что-то внутри пойдёт не так. И как удалить, не снеся случайно половину хостовой системы. Докер как-то это сам делает, а тут есть риск появления упсь!-моментов у начинающих контейнероводов.
А за статью спасибо, небезынтересно было узнать как оно работает.

Согласен как-то с докером спокойней это делать тан как в докер есть готовые файловые системы и методы удаления и создания контейнера есть ещё более взрослый вариант то lxd

Интересно а кто нибудь еще помнит что такое Virtuozzo и позднее - OpenVZ и какое это отношение имеет с тем же cgroups/namespaces ?

Про них никто и не забывал, основа на том же Proxmox. Они не конкурируют с докером так как выполняют иную задачу.

Жаль что мало кто уделяет всему этому внимание, но кхе кхе. Есть отличный проект для этих нужд. Rurima. Скм и пользуюсь, может что-то можно будет подметить для себя в качестве запуска докера без докера.

Меня интересует несколько иной вопрос - вот у нас есть образа с alpine, void, arch, ubuntu - как они выглядят с точки зрения докера и исполняются в контексте конкретных дистров, а не как кусок хостовой системы.

А что именно непонятно? Установленный дистрибутив - это набор файлов, разложенных определённым образом в задуманные места. Внутри контейнера этот набор файлов выглядит прямо как набор файлов...

Ну, когда вы запускаете дистрибутив у него определённо идёт стадия загрузки, проверяются всякая переферия, поднимаются ramfs чтобы загрузить всякое, запускаются всякие стартовые программы. С точки зрения гостевой системы как это выглядит? Словно у нас уже прошли эти этапы и мы уже всё запустили и проинициализировали или он тоже честно стартует загрузку с шага загрузчика?

Этим занимается загрузчик и ядро. С точки зрения "хостовой" системы это выглядит точно так же, то есть никак. Потому что, грубо говоря, "хостовая" система - это chroot из initrd, а контейнер - это chroot из "хостовой" системы, опять же, очень условно.

Вы точно так же можете загрузиться с USB, сделать chroot в свой корень и пользоваться этой системой поверх того ядра, которое было на USB

В "гостевой" системе это выглядит как запуск бинарника. Всё. Этим бинарником может быть ваш исполняемый файл, bash, выполняющий скрипт, или даже init systemd (для podman). Последний несколько забавен, так как понимает, что запущен в контейнере, присасывается в хостовому systemd и льёт туда логи. Ну и безопасно позволяет остановить демоны внутри контейнера при остановке всего контейнера.

Стадии загрузки в контейнере нет, контейнер начинается сразу с запуска основного процесса (в дистрибутивах это обычно шелл).

Да блин, ну вы же комментируете статью, где рассказано как контейнеры запускаются! В какой момент автор поднимал ramfs и инициализировал периферию? Да ни в какой, он сразу /bin/sh в контейнере запустил! При этом он скачал busybox, а мог скачать образ дистрибутива - остальные шаги никак бы не поменялись.

А в чем прикол иметь образа с чем-то кроме того же busybox? Специфичный лэйаут файловой системы, конфигов и состава бинарей и shared либ?

Я бегло погуглил и некоторые причины есть.

Busybox is amazing, if you want small. If you want featurefull, GNU is way better.

Ну, то есть, например, есть программа, которую написал Вася, а есть ещё одна, который написал Петя. По функционалу они, практически, одинаковы, по внешнему виду тоже, но баги и уязвимости у каждого свои.

Лицензия. Это GPL и они уже несколько раз судились за нарушения.

Ну и то что вы перечислили - тоже.

Ну, кроме busybox всё-таки нужны ещё и либы, иначе ничего полезного вы не запустите. И пакетный менеджер, чтобы поставить те либы и инструменты, которых не оказалось в образе.

Всё это можно собрать из исходников. Тот же busyBox модульный и можно включить дополнительные компоненты, или убрать ненужные, втч пакетный менеджер - именно поэтому он так популярен для embedded платформ.

Вот делать нечего кроме как собирать чужой софт из исходников. Докер выбирают ради ускорения и упрощения CI/CD, а вы предлагаете дальше замедлять.

Плюс для сборки софта нужны инструменты, голым busybox его не собрать.

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

Я не совсем понимаю что вы хотите всем этим сказать. Инструменты сборки и пакетный менеджер внутри готового образа - это потенциальная угроза безопасности. Если что-то нужно собрать или поставить - используются multi-stage build.

На многих прошивках роутеров (например, Teltonika) идёт просто голый BusyBox, внутри которого один собранный бинарник, но там есть и веб-админка, и консоль.

Причём тут вообще прошивки роутеров? Вы используете докер на роутерах или где? И даже если используете - неужели вы думаете что только для роутеров он и годится?

multi-stage build - вещь хорошая, и используется постоянно, однако проблему не решает. Во-первых, пакетный менеджер вам всё равно понадобится, потому что зависимостей у каких-нибудь .NET или Java - до чёрта, и вручную все их копировать вам не захочется. А во-вторых, не каждый пакетный менеджер имеет ставить пакеты по отдельному префиксу, в котором не стоит он сам - а значит, и забрать их все автоматически в следующую стадию multi-stage build вы не сможете. Наконец, в-третьих, если вы так и сделаете, то быстро обнаружите насколько распухли все ваши образы.

Инструменты сборки и пакетный менеджер внутри готового образа - это потенциальная угроза безопасности

А пакетный менеджер на сервере - не угроза? Что именно может сделать злоумышленник внутри контейнера, чего не может сделать снаружи?

Причём тут вообще прошивки роутеров? Вы используете докер на роутерах или где? И даже если используете - неужели вы думаете что только для роутеров он и годится?

Смотрите - мой аргумент в этой ветке был, в первую очередь, про embedded-платформы и, да - роутеры. Я работал с Teltonika - там именно BusyBox в контейнере, но в комплекте с веб-админкой идёт и ModBus, и MQTT, и файрволл, и ещё дочерта софта. Почти всё собирается в единый бинарник.

Пакетный менеджер может отсутствовать. И, в принципе, должен бы отсутствовать - зачем в готовом имидже пакетный менеджер или gcc или какой-нибудь build-essentials - не будет же приложение в рантайме его вызывать? А вот если в контейнер пролезет через какие-то уязвимости троян - ему это может пригодиться.

Конечно же, вы можете использовать пакетный менеджер чтобы установить либы и всё остальное для multi-stage build - тот же BusyBox вы можете собрать хоть под Debian, хоть под RedHat.

Я уверен что вы всё это понимаете, просто у нас с вами какой-то странный спор.

Смотрите - мой аргумент в этой ветке был, в первую очередь, про embedded-платформы и, да - роутеры.

Вот я и не понимаю, причём тут вообще embedded-платформы?

Конечно же, вы можете использовать пакетный менеджер чтобы установить либы и всё остальное для multi-stage build - тот же BusyBox вы можете собрать хоть под Debian, хоть под RedHat.

BusyBox и собирать-то не нужно, у него собранный бинарник выложен. Вы лучше расскажите как на чистый образ поставить JRE со всеми зависимостями. И сколько времени вам потребуется на написание докерфайла.

Вот я и не понимаю, причём тут вообще embedded-платформы?

А я не понимаю при чём здесь JRE. Мы с вами сидим в ветке про BusyBox. Он широко применяется в embedded платформах.

BusyBox и собирать-то не нужно, у него собранный бинарник выложен

Он выложен для какой-то дефолтной конфигурации. Обычно он собирается для конкретных целей:

It is also extremely modular so you can easily include or exclude commands (or features) at compile time. This makes it easy to customize your embedded systems.

Ну, кажется пошарить либы не настолько большая проблема. Сделать условный ldd, скопировать so в контейнерный /usr/lib и в ус не дуть. Это очень скудно поясняет почему кому-то нужен образ с Fedora или Ubuntu, а другому Alpine за глаза.

обычно помимо либ надо еще россыпь полезных файлов из etc & usr/share, типа нужной таймзоны, корневых сертификатов и так далее

Вам ldd покажет только те разделяемые библиотеки, которые требуются для запуска. Те, которые догружаются во время работы, так просто не увидеть.

И не забывайте что некоторые странные программы используют утилиты командной строки. Не просто так проекты MinGW и Cygwin содержат, помимо библиотек, полные наборы утилит GNU - вызовы system("...") могут оказаться в кодовой базе в самых неожиданных местах.

Ни в чем, только удобство. Если нужно в систему поставить программу, то проще через менеджер контейнеров сделать.
У меня есть контейнер в котором только одна программа

FROM debian:bookworm-slim as builder
RUN mkdir /src
COPY ./ /src
RUN /src/mk.sh

FROM scratch
COPY --from=builder /app/TorrServer /
WORKDIR /
ENTRYPOINT [ "/TorrServer" ]

Для любителей есть ещё User Mode Linux, когда весь Linux в отдельный процесс пакуется который можно как обычный файл запускать :)

Это уже не контейнер. Потому что у полученной системы ядро таки свое - тот самый запущенный бинарник.

И что? Контейнер это не про ядро а про изоляцию программ. Вы же не ядра запускаете а программы. То что они все на одном ядре, так вы обычно на линуксовой машине линуксовые машины запускаете.

И что? Контейнер это не про ядро а про изоляцию программ.

Я так не считаю. Термины хорошо бы все-таки использовать в соответствии с тем, что они означают. А то так какой-нибудь Xen тоже контейнером называть что ли?

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

User Mode Linux всё-таки кооперативная виртуализация (она же паравиртуализация).

По названию статьи подумал, что кто-то открыл для себя podman или низкоуровневые среды выполнения контейнеров (OCI), такие как runc и crun.

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

Я тоже пишу свой аналог Docker, только без неймспейсов и cgroups, чтобы его можно было запускать на рутованных (chroot + overlayfs) и нерутованных (proot + аналог vfs) смартфонах. Возможно, добавлю опциональную поддержку cgroups, если удастся заставить их работать на моём смартфоне - они вроде есть, но в каком-то урезанном виде.

Мой проект называется nocker. Наверное на этой неделе залью на GitHub. Написан на чистом POSIX shell с минимальными зависимостями (wget, jq). Реализовал pull, run, start, exec, ps, rm, inspect и ещё несколько команд. Для моих задач не хватает только build и compose.

Уже получилось 1500 строк кода. Странно как у bocker с близким функционалом получилось уложиться всего в 120 строк. Надо поподробнее изучить его код и сравнить с моим.

Благая цель. Не поделитесь ссылкой на репозиторий?

Только что залил: https://github.com/devoln/nocker
Ещё не тестировал на самом Андроиде, и chroot-вариант тоже не особо тестировал. Пока разрабатываю, тестирую только в Ubuntu 24.04. chroot пока менее функционален, так как там не работает переназначение портов.
Буду тестировать на Android, когда реализую build хотя бы на уровне, достаточном, чтобы поднять мою несложную хоум-лабу.

Уважаемый автор, спасибо за познавательную публикацию. Буду рад если в будущем вы так же подробно разберете LXC контейнеры.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации