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

#docker

Вопрос:

Как docker может работать на хосте Debian, возможно, на openSUSE в контейнере? Он использует другое ядро с отдельными модулями. Кроме того, в более старых версиях Debian использовались более старые ядра, так как же запустить его в версии ядра 3.10 ? Старые ядра имеют только старые встроенные функции, как старый дистрибутив может управлять новыми функциями? Что в этом «подвоха»?

Ответ №1:

Docker никогда не использует другое ядро: ядро всегда является ядром вашего хоста.

Если ядро вашего хоста «достаточно совместимо» с программным обеспечением в контейнере, который вы хотите запустить, оно будет работать; в противном случае оно не будет работать.

«Контейнеры» — Это Просто Конфигурация Процесса

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

Разница между контейнерным процессом и обычным процессом заключается в ограничениях, накладываемых на контейнерный процесс, и изменениях в том, как он видит окружающую среду вокруг себя. (Они передаются любым дочерним процессам, запущенным контейнеризованным процессом.) Типичные ограничения и изменения включают:

  • Вместо того, чтобы использовать корневую файловую систему хоста, смонтируйте другую файловую / систему (обычно поставляемую с изображением контейнера). Части файловой системы хоста могут быть смонтированы под корневой файловой системой нового процесса, например, с помощью docker run -v /u/myprogram-data:/var/data/myprogram так, чтобы, когда контейнеризованный процесс считывает или записывает /var/data/myprogram/file , это считывает/записывает /u/myprogram-data/file в файловой системе хоста.
  • Создайте отдельное пространство процесса для контейнеризованного процесса, чтобы он мог видеть только себя и своих дочерних процессов (с ps помощью или аналогичных команд), но не мог видеть другие процессы, запущенные на хосте.
  • Создайте отдельное пространство имен пользователей, чтобы пользователи в контейнере отличались от пользователей на хосте: например, UID 1234 в контейнеризованном процессе не будет таким же, как UID 1234 для неконтейнеризованных
  • Создайте отдельный набор сетевых интерфейсов со своими собственными IP-адресами, часто используя «виртуальный маршрутизатор» и преобразование адресов между ними и сетевыми интерфейсами хоста. (Например, хост, когда он получает пакет на порту 8080, перенаправляет его на порт 80 в виртуальном сетевом интерфейсе процессов контейнера.)

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

Совместимость

Так что же означает «достаточно совместимый»? Это зависит от того, какие запросы программа делает к ядру (системные вызовы) и какие функции, как она ожидает, будет поддерживать ядро. Некоторые программы делают запросы, которые могут что-то нарушить, другие-нет. Например, на 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 или более раннее, вы обнаружите, что оно будет работать нормально. (По крайней мере, насколько я это проверял.)

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

1. Отличное объяснение. Прояснил для меня многое о том, как работает докер.

2. Это отличный ответ! Ответил на многие мои вопросы о докере.

3. Недавно я услышал выражение, которое прекрасно подводит итог этому имо: «Докер-это просто набор ядер Linux». Ссылаясь на пространства имен, группы …

4. Отличные примеры, проясняющие большую часть путаницы.

5. @erikbozic, если быть более точным: это ядро Linux, которое «контейнеризирует» процессы, а Docker-это система, которая позволяет создавать, хранить и отзывать конфигурации процессов ядра Linux. (А также удобно хранит изображения файловой системы.)

Ответ №2:

Как docker может работать на хосте 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=584amp;h=231

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

См. Также «Почему версия ядра не соответствует версии Ubuntu в контейнере Docker?«:

Внутри контейнера нет ядра. Даже если вы установите ядро, оно не будет загружено при запуске контейнера. Само назначение контейнера состоит в том, чтобы изолировать процессы без необходимости запускать новое ядро.

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

1. Я думаю, что вышесказанное не дает полного ответа на этот вопрос. Хотя я полностью согласен с тем, что ссылки на ссылки дают хорошее объяснение того, почему контейнеры не создают собственное ядро, мы могли бы на самом деле захотеть создать контейнер, который, возможно, зависит от конкретной версии ядра. Я думаю, что docker даже при запуске на хосте Linux может иметь режим, в котором вы можете выбрать версию ядра.

2. Эта диаграмма неверна и вводит в заблуждение: часть «контейнер» вообще не находится в пространстве пользователя. Конфигурация контейнера изменяет то, как ядро реагирует на системные вызовы, например , если вы open("/etc/passwd", O_RDONLY) , какой из многих файлов, известных ядру, фактически открыт? С точки зрения пользовательского пространства процесс не отличается от «неконтейнеризованного» процесса.