Как Docker может запускать дистрибутивы с разными ядрами?

Как докеры могут запускаться на хосте Debian, может быть, OpenSUSE в контейнере? Он использует другое ядро с отдельными модулями. Кроме того, более старые версии Debian используют старые ядра, поэтому как запустить его на ядре версии 3. 10+? Старые ядра имеют только более старые встроенные функции, как старый менеджер может управлять новыми функциями? Что такое "трюк" в нем?

Ответ 1

Как докеры могут запускаться на хосте Debian, может быть, OpenSUSE в контейнере

Поскольку ядро такое же и будет поддерживать механизм Docker для запуска всех этих изображений контейнеров: ядро хоста должно быть 3.10 или более, но его список системных вызовов довольно стабилен.

См. " Контейнеры для архитекторов: почему понимание пространства пользователя и пространства ядра ":

  1. Приложения содержат бизнес-логику, но полагаются на системные вызовы.
  2. После компиляции приложения набор системных вызовов, которые использует приложение (т.е. Полагается), встроен в двоичный файл (на языках более высокого уровня это интерпретатор или JVM).
  3. Контейнеры не абстрагируют потребность в пространстве пользователя и пространстве ядра для совместного использования общего набора системных вызовов.
  4. В контейнеризованном мире это пространство пользователя собрано и отправлено на разные хосты, начиная от ноутбуков и заканчивая производственными серверами.
  5. В ближайшие годы это вызовет проблемы.

https://rhelblog.files.wordpress.com/2015/07/user-space-vs-kernel-space-simple-container.png?w=584&h=231

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

См. Также " Почему версия ядра не соответствует версии 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 или более ранней, вы обнаружите, что он будет работать нормально. (По крайней мере, насколько я это проверял.)