Как Docker может запускать дистрибутивы с разными ядрами?
Как докеры могут запускаться на хосте Debian, может быть, OpenSUSE в контейнере? Он использует другое ядро с отдельными модулями. Кроме того, более старые версии Debian используют старые ядра, поэтому как запустить его на ядре версии 3. 10+? Старые ядра имеют только более старые встроенные функции, как старый менеджер может управлять новыми функциями? Что такое "трюк" в нем?
Ответы
Ответ 1
Как докеры могут запускаться на хосте Debian, может быть, OpenSUSE в контейнере
Поскольку ядро такое же и будет поддерживать механизм Docker для запуска всех этих изображений контейнеров: ядро хоста должно быть 3.10 или более, но его список системных вызовов довольно стабилен.
См. " Контейнеры для архитекторов: почему понимание пространства пользователя и пространства ядра ":
- Приложения содержат бизнес-логику, но полагаются на системные вызовы.
- После компиляции приложения набор системных вызовов, которые использует приложение (т.е. Полагается), встроен в двоичный файл (на языках более высокого уровня это интерпретатор или JVM).
- Контейнеры не абстрагируют потребность в пространстве пользователя и пространстве ядра для совместного использования общего набора системных вызовов.
- В контейнеризованном мире это пространство пользователя собрано и отправлено на разные хосты, начиная от ноутбуков и заканчивая производственными серверами.
- В ближайшие годы это вызовет проблемы.
Время от времени добавляются новые системные вызовы, а старые системные вызовы устаревают; это следует учитывать при рассмотрении жизненного цикла вашей инфраструктуры контейнера и приложений, которые будут работать в нем.
См. Также " Почему версия ядра не соответствует версии Ubuntu в контейнере Docker? ":
Внутри контейнера нет ядра. Даже если вы устанавливаете ядро, оно не будет загружаться при запуске контейнера. Сама цель контейнера - изолировать процессы без необходимости запуска нового ядра.
Ответ 2
Docker никогда не использует другое ядро: ядро всегда является ядром вашего хоста.
Если ядро вашего хоста "достаточно совместимо" с программным обеспечением в контейнере, который вы хотите запустить, оно будет работать; в противном случае это не так.
"Контейнеры" - это просто конфигурация процесса
Главное, что нужно понять, это то, что контейнер Docker не является виртуальной машиной: он не создает новую виртуальную машину для запуска программного обеспечения. Вместо этого Docker просто запускает процессы в вашей существующей ОС, аналогично тому, как вы просто запускаете процесс из командной строки.
Разница между контейнерным процессом и обычным процессом заключается в ограничениях, накладываемых на контейнерный процесс и изменения в том, как он видит окружающую среду вокруг него. (Они передаются любым дочерним процессам, запущенным контейнерным процессом.) Типичные ограничения и изменения включают в себя:
- Вместо того, чтобы использовать корневую файловую систему хоста, смонтируйте другую файловую систему в
/
(обычно ту, которая поставляется с образом контейнера). Части файловой системы хоста могут быть смонтированы под корневой файловой системой нового процесса, например, с помощью docker run -v/u/myprogram-data: /var/data/myprogram
так, чтобы когда контейнерный процесс docker run -v/u/myprogram-data: /var/data/myprogram
или записывал /var/data/myprogram/file
это читает/пишет /u/myprogram-data/file
в файловой системе хоста. - Создайте отдельное пространство процесса для контейнерного процесса, чтобы он мог видеть только себя и своих дочерних
ps
(с помощью ps
или аналогичных команд), но не мог видеть другие процессы, запущенные на хосте. - Создайте отдельное пространство имен пользователей, чтобы пользователи в контейнере отличались от пользователей на хосте: например, UID 1234 в контейнерном процессе не будет таким же, как UID 1234 для не контейнерных
- Создайте отдельный набор сетевых интерфейсов со своими собственными IP-адресами, часто используя "виртуальный маршрутизатор" и трансляцию адресов между ними и сетевыми интерфейсами хоста. (Например, хост, когда он получает пакет через порт 8080, перенаправляет его на порт 80 на интерфейсе виртуальной сети процессов контейнера.)
Все это делается средствами, встроенными в ядро; Вы можете сделать все это самостоятельно без Docker, если напишите программу для соответствующей настройки и установите соответствующие параметры при запуске нового процесса.
Совместимость
Так что же значит "достаточно совместимый"? Это зависит от того, какие запросы ядро делает от программы (системные вызовы) и какие функции она ожидает от ядра. Некоторые программы делают запросы, которые сломают вещи; другие нет. Например, на Ubuntu 18.04 (ядро 4.19) или аналогичном хосте:
-
docker run centos:7 bash
работает нормально. -
docker run centos:6 bash
завершается с ошибкой с кодом выхода 139, что означает, что он завершается сигналом нарушения сегментации; это потому, что ядро 4.19 не поддерживает то, что пыталась сделать сборка bash
. -
docker run centos:6 ls
работает нормально, потому что он не делает запрос, который ядро не может обработать, как это делал bash
.
Если вы попробуете docker run centos:6 bash
на старом ядре, скажем, 4.9 или более ранней, вы обнаружите, что он будет работать нормально. (По крайней мере, насколько я это проверял.)