Тщательно изучите краеугольный камень контейнерной технологии: пространство имен (ниже).

Linux Docker Kubernetes
Тщательно изучите краеугольный камень контейнерной технологии: пространство имен (ниже).

Всем привет, меня зовут Чжан Цзиньтао.

В настоящее время технология контейнеров и технология виртуализации, о которых мы упоминали (независимо от уровня абстракции технологии виртуализации), могут обеспечить изоляцию и ограничение на уровне ресурсов.

Для технологии контейнеров она реализует ограничения и изоляцию на уровне ресурсов и опирается на технологии cgroup и namespace, предоставляемые ядром Linux.

Давайте сначала суммируем роль этих двух технологий:

  • Основная роль cgroup: управлять выделением и ограничением ресурсов;
  • Основная роль пространства имен: инкапсулировать абстракцию, ограничение, изоляцию, чтобы процессы в пространстве имен имели свои собственные глобальные ресурсы;

Это серия статей, друзья, которым интересна эта серия, могут проверить:

В этой статье мы продолжим разговор о пространствах имен.

Тип пространства имен

Давайте сначала взглянем на типы пространств имен, которые были представлены вам в предыдущей статье.Cgroup , IPC, NetworkиMount4 типа пространств имен. Давайте перейдем к остальным.

имя пространства имен Используемые флаги - Флаг контролировать содержимое
Cgroup CLONE_NEWCGROUP Корневой каталог cgroup Корневой каталог cgroup
IPC CLONE_NEWIPC System V IPC, очереди сообщений POSIX, семафоры, очереди сообщений
Network CLONE_NEWNET Сетевые устройства, стеки, порты и т. д.
Mount CLONE_NEWNS Точки монтирования
PID CLONE_NEWPID Идентификаторы процессов Идентификаторы процессов
Time CLONE_NEWTIME Загрузочные и монотонные часы
User CLONE_NEWUSER Идентификаторы пользователей и группПользователи и группы пользователей
UTS CLONE_NEWUTS Имя хоста и доменное имя NIS

PID namespaces

Мы знаем, что в системе Linux каждый процесс будет иметь свой собственный независимый PID, и пространство имен PID в основном используется для изоляции номера процесса. То есть один и тот же идентификатор процесса может содержаться в разных пространствах имен PID.

Номер процесса в каждом пространстве имен PID начинается с 1. В этом пространстве имен PID его можно вызвать, вызвавfork(2), vfork(2)иclone(2)Дождитесь системных вызовов для создания других процессов с отдельными PID.

Для использования пространства имен PID требуется поддержка ядра.CONFIG_PID_NSопции. следующее:

(MoeLove) ➜ grep CONFIG_PID_NS /boot/config-$(uname -r)
CONFIG_PID_NS=y

процесс инициализации

Все мы знаем, что в системе Linux есть специальный процесс, так называемый процесс init, то есть процесс с PID 1.

Мы уже говорили, что номер процесса в каждом пространстве имён PID начинается с 1, так каковы же его характеристики?

Во-первых, процесс 1 в пространстве имен PID является родителем всех потерянных процессов.

Во-вторых, если этот процесс завершится, ядро ​​вызоветSIGKILLСигнал для завершения всех процессов в этом пространстве имен.Эта часть связана с изящным завершением/плавным обновлением приложений в Kubernetes.(Партнеры, которые заинтересованы в этой части, могут оставить сообщение для связи. Если вам интересно это содержание, я могу написать специальную статью, чтобы рассказать об этом)

Наконец, начиная с версии ядра Linux v3.4, если это происходит в пространстве имен PIDreboot()системный вызов, процесс инициализации в пространстве имен PID немедленно завершится.Это довольно специфический прием, который можно использовать для работы с выходами из контейнера на сильно загруженных машинах.

Иерархия пространств имен PID

Пространство имен PID поддерживает вложенность.За исключением начального пространства имен PID, остальные пространства имен PID имеют пространство имен PID своего родительского узла.

Другими словами, пространство имен PID также является древовидной структурой, и все пространства имен PID в этой структуре можно проследить до пространства имен предка PID. Конечно, эта глубина не безгранична, так как в версии ядра Linux v3.7 максимальная глубина дерева ограничена 32.

Если эта максимальная глубина будет достигнута, он выброситNo space left on deviceошибка.(Я столкнулся с этим, когда пытался вложить контейнеры раньше)

Процессы видны друг другу в пределах одного и того же (и родственного) пространства имен PID.

Но если процесс находится в дочернем пространстве имен PID, то процесс не может видеть процесс на верхнем уровне (то есть в родительском пространстве имен PID).

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

Итак, можно ли запланировать процессы на разные уровни пространства имен PID?

Начнем с заключения,Планирование процессов в пространстве имен PID может быть только односторонним (от высокого до низкого).. который:

  • Процессы могут быть отправлены только из пространства имен родительского PID в пространство имен дочернего PID;
  • Процессы не могут быть отправлены из пространства имен дочернего PID в пространство имен родительского PID;

img

Рисунок 1. Описание процесса планирования с помощью setns(2)

Иерархические отношения пространства имен PID фактически определяютсяioctl_ns(2)Системный вызов используется для обнаружения и обслуживания (NS_GET_PARENT), который здесь не будет раскрываться. Итак, как достигается планирование в приведенном выше контенте?

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

Потоки должны находиться в одном и том же пространстве имен PID, чтобы гарантировать, что потоки в процессе могут взаимодействовать друг с другом. Это ведет кCLONE_NEWPIDне может быть сCLONE_THREADиспользовать одновременно. Но что, если несколько процессов, распределенных в разных пространствах имен PID, должны взаимодействовать друг с другом? Это можно решить с помощью общей очереди сигналов.

Кроме того, мы часто сталкиваемся/procВ каталоге много/proc/${PID}, где вы можете увидеть процессы в пространстве имен PID. В то же время этим каталогом также можно управлять напрямую путем монтирования. Например:

(MoeLove) ➜ mount |grep proc 
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

Есть ли способ узнать текущее максимальное количество PID?

Это также возможно, так как версия ядра Linux v3.3 добавила новый/proc/sys/kernel/ns_last_pidФайл, в котором записан идентификатор последнего процесса.

Когда необходимо выделить следующий идентификатор процесса, ядро ​​ищет самый большой неиспользуемый идентификатор для выделения, а затем обновляет информацию о PID в этом файле.

Time namespaces

Прежде чем говорить о пространстве имен времени, нам нужно поговорить оМонотонное время. Прежде всего, системное время, на которое мы обычно ссылаемся, относится к часам реального времени, то есть к отображению текущего времени машиной. Его можно настроить вперед или назад (понимается в связке со службой NTP). Монотонные часы представляют запись времени после определенного момента, это одностороннее обратное абсолютное время, и на него не влияют изменения системного времени.

Для использования пространства имен time требуется поддержка ядра.CONFIG_TIME_NSопции. Такие как:

(MoeLove) ➜ grep CONFIG_TIME_NS /boot/config-$(uname -r)
CONFIG_TIME_NS=y

time не виртуализирует часы CLOCK_REALTIME. Вам может быть интересно, почему ядро ​​поддерживает пространства имен времени? В основном для некоторых особых сценариев.

Все процессы в пространстве имен time совместно используют следующие два параметра, предоставляемые пространством имен time:

  • CLOCK_MONOTONIC - монотонное время, неустанавливаемые часы;
  • CLOCK_BOOTTIME (см. параметр ядра CLOCK_BOOTTIME_ALARM) - неустанавливаемые часы, включая время приостановки работы системы.

time может в настоящее время использовать только идентификатор CLONE_NEWTIME, вызываяunshare(2)системный вызов для создания. Процесс, который создает пространство имен времени, не зависит от вновь созданного пространства имен времени, и последующие дочерние процессы процесса будут помещены во вновь созданное пространство имен времени. Процессы в одном и том же пространстве имен времени совместно используют CLOCK_MONOTONIC и CLOCK_BOOTTIME.

Когда родительский процесс создает дочерний процесс, принадлежность пространства имен времени дочернего процесса будет показана в файле /proc/[pid]/ns/time_for_children.

(MoeLove) ➜ ls -al /proc/self/ns/time_for_children 
lrwxrwxrwx. 1 tao tao 0 12月 14 02:06 /proc/self/ns/time_for_children -> 'time:[4026531834]'

Файл /proc/PID/timens_offsets определяет монотонные часы и часы запуска для начального пространства имен времени и записывает смещения. (Если новое пространство имен времени еще не вступило в процесс, его можно изменить. Здесь оно не будет расширено. Заинтересованные друзья могут оставить сообщение в области обсуждения для обмена и обсуждения.)

Следует отметить, что в начальном пространстве имен времени все смещения, отображаемые в /proc/self/timens_offsets, равны 0.

(MoeLove) ➜ cat /proc/self/timens_offsets 
monotonic           0         0
boottime            0         0

Значения второго и третьего столбцов следующие:

  • Может быть отрицательным, единица измерения: секунда (с)
  • беззнаковое значение в наносекундах (нс)

Следующие интерфейсы часов связаны с этим пространством имен:

  • clock_gettime(2)

  • clock_nanosleep(2)

  • nanosleep(2)

  • timer_settime(2)

  • timerfd_settime(2)

В целом пространства имен времени полезны в некоторых особых сценариях.

User namespaces

Пространства имен пользователей, как следует из названия, изолируют идентификаторы пользователей, идентификаторы групп и т. д.

Использование пространств имен пользователей требует, чтобы ядро ​​поддерживало опцию CONFIG_USER_NS. Такие как:

➜  local_time grep CONFIG_USER_NS /boot/config-$(uname -r)
CONFIG_USER_NS=y

Идентификатор пользователя и идентификатор группы процесса могут различаться внутри и вне пространства имен пользователя.

Например, пользователь и группа процесса в пользовательском пространстве имен могут быть привилегированным пользователем (root), но за пределами пользовательского пространства имен могут быть обычным непривилегированным пользователем. Это включает сопоставление пользователей, групп (uid_map, gid_map) и другой связанный контент.

Начиная с ядра Linux v3.5,/proc/[pid]/uid_mapи/proc/[pid]/gid_mapВ файле мы можем просмотреть содержимое сопоставления.

(MoeLove) ➜ cat /proc/self/uid_map 
         0          0 4294967295
(MoeLove) ➜ cat /proc/self/gid_map 
         0          0 4294967295

Пространство имен пользователя также поддерживает вложенность, которая создается с помощью флага CLONE_NEWUSER и системных вызовов, таких как unshare(2) или clone(2).Максимальный уровень вложенности — 32.

Если дочерний процесс, созданный fork(2) или clone(2), не имеет флага CLONE_NEWUSER, то же самое верно, дочерний процесс находится в том же пользовательском пространстве имен, что и родительский процесс. Древовидная связь также поддерживается через интерфейс системного вызова ioctl(2).

Однопоточный процесс может настроить свое пользовательское пространство имен с помощью системного вызова setns(2).

Кроме того, пространство имен пользователей имеет очень важное правило, а именно отношения наследования возможностей Linux. Я не буду распространяться о возможностях Linux, вот краткая запись:

  • Когда пространство имен пользователя, в котором находится процесс, имеет возможность в наборе эффективных возможностей, процесс имеет возможность.

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

  • Пользователь, создавший пространство имен пользователя, будет записан ядром как владелец, то есть будет иметь все возможности в пространстве имен пользователя.

Для Docker он может изначально поддерживать эту возможность, тем самым обеспечивая защиту среды контейнера.

UTS namespaces

Пространства имен UTS изолируют имена хостов и доменные имена NIS.

Использование пространств имен UTS требует поддержки ядром опции CONFIG_UTS_NS. Такие как:

(MoeLove) ➜ grep CONFIG_UTS_NS /boot/config-$(uname -r)
CONFIG_UTS_NS=y

В одном и том же пространстве имен UTS настройки и изменения, сделанные системными вызовами sethostname(2) и setdomainname(2), совместно используются и просматриваются всеми процессами, но для разных пространств имен UTS они изолированы друг от друга и невидимы.

Основной API пространств имен

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

clone(2)

Система вызывает clone(2) для создания нового процесса, который будет реализовывать соответствующие функции конфигурации одну за другой в соответствии с настройками CLONE_NEW* в параметрах. Конечно, этот системный вызов также реализует некоторые функции, независимые от пространства имен. Для систем с ядром ниже Linux 3.8 в большинстве случаев требуется возможность CAP_SYS_ADMIN.

unshare(2)

Система вызывает unshare(2), чтобы назначить процесс новому пространству имен, а также настраивает и реализует соответствующую функцию конфигурации в соответствии с настройками CLONE_NEW* в параметрах. Для систем ниже Linux 3.8 в большинстве случаев требуется возможность CAP_SYS_ADMIN.

setns(2)

Системный вызов setns(2) перемещает процесс в существующее пространство имен, что приводит к изменению содержимого каталога, соответствующего /proc/[pid]/ns. Дочерний процесс, созданный процессом, может настроить пространство имен, к которому он принадлежит, вызвав unshare(2) и setns(2). Обычно для этого требуется возможность CAP_SYS_ADMIN.

Некоторые ключевые описания каталогов

/proc/[pid]/ns/ каталог

У каждого процесса есть подкаталог /proc/[pid]/ns/, на содержимое которого влияет системный вызов setns(2). Пока файл в каталоге открыт, соответствующее пространство имен не может быть уничтожено. Система может изменить содержимое этих файлов, вызвав setns(2).

  • Linux 3.7 и более ранние версии — файлы жестко связаны;
  • Начиная с Linux 3.8 - файл существует в виде мягкой ссылки;
(MoeLove) ➜ ls -l --time-style='+' /proc/$$/ns  
总用量 0
lrwxrwxrwx. 1 tao tao 0  cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx. 1 tao tao 0  ipc -> 'ipc:[4026531839]'
lrwxrwxrwx. 1 tao tao 0  mnt -> 'mnt:[4026531840]'
lrwxrwxrwx. 1 tao tao 0  net -> 'net:[4026532008]'
lrwxrwxrwx. 1 tao tao 0  pid -> 'pid:[4026531836]'
lrwxrwxrwx. 1 tao tao 0  pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx. 1 tao tao 0  time -> 'time:[4026531834]'
lrwxrwxrwx. 1 tao tao 0  time_for_children -> 'time:[4026531834]'
lrwxrwxrwx. 1 tao tao 0  user -> 'user:[4026531837]'
lrwxrwxrwx. 1 tao tao 0  uts -> 'uts:[4026531838]'

Если пространства имен двух процессов совпадают, то содержимое их каталога должно быть одинаковым.

Ниже приводится подробное описание файлов в этом каталоге:

имя файла начальная версия описывать
/proc/[pid]/ns/cgroup Linux 4.6 Пространство имен cgroup процесса
/proc/[pid]/ns/ipc Linux 3.0 Пространство имен IPC процесса
/proc/[pid]/ns/mnt Linux 3.8 Пространство имен монтирования процесса
/proc/[pid]/ns/net Linux 3.0 сетевое пространство имен процесса
/proc/[pid]/ns/pid Linux 3.8 Пространство имен PID процесса является постоянным на протяжении всего жизненного цикла процесса.
/proc/[pid]/ns/pid_for_children Linux 4.12 Пространство имен PID дочернего процесса, созданного процессом, не обязательно совпадает с /proc/[pid]/ns/pid.
/proc/[pid]/ns/time Linux 5.6 пространство имен времени процесса
/proc/[pid]/ns/time_for_children Linux 5.6 Пространство имен времени, в котором процесс создает дочерний процесс.
/proc/[pid]/ns/user Linux 3.8 пользовательское пространство имен процесса
/proc/[pid]/ns/uts Linux 3.0 пространство имен UTS процесса

/proc/sys/каталог пользователя

Файлы в каталоге /proc/sys/user записывают соответствующие ограничения для каждого пространства имен. Когда лимит будет достигнут, соответствующий вызов сообщит об ошибке ENOSPC.

имя файла Описание контента с ограниченным доступом
max_cgroup_namespaces Максимальное количество пространств имен cgroup, которое может создать каждый пользователь в пользовательском пространстве имен.
max_ipc_namespaces Максимальное количество пространств имен ipc, которое может создать каждый пользователь в пользовательском пространстве имен.
max_mnt_namespaces Максимальное количество пространств имен монтирования, которое может создать каждый пользователь в пространстве имен пользователя.
max_net_namespaces Максимальное количество сетевых пространств имен, которое может создать каждый пользователь в пользовательском пространстве имен.
max_pid_namespaces Максимальное количество пространств имен PID, которые каждый пользователь может создать в пространстве имен пользователя.
max_time_namespaces Linux 5.7 максимальное количество пространств имен времени, которое может создать каждый пользователь в пользовательском пространстве имен
max_user_namespaces Максимальное количество пространств имен пользователей, которое может создать каждый пользователь в пространстве имен пользователей.
max_uts_namespaces Максимальное количество пространств имен uts, которые каждый пользователь может создать в пространстве имен пользователя.

Жизненный цикл пространства имен

Жизненный цикл нормального пространства имен связан с завершением и уходом последнего процесса.

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

  • /proc/[pid]/ns/*Файл открывается или монтируется и не может быть уничтожен, даже если завершается последний процесс;

  • Пространство имен является многоуровневым, а подпространство имен все еще существует.Даже если последний процесс завершается, его нельзя уничтожить;

  • Пользовательское пространство имен имеет некоторые непользовательские пространства имен (такие как пространство имен PID и другие пространства имен), даже если последний процесс завершается, его нельзя уничтожить;

  • Для пространства имен PID, если оно совпадает с/proc/[pid]/ns/pid_for_childrenКогда есть ассоциативное отношение, даже если последний процесс завершается, он не может быть уничтожен;

Конечно, есть и другие ситуации, которые будут добавлены, когда у меня будет время.

Суммировать

В предыдущей статье и этой статье я в основном представил процесс разработки пространства имен Linux, основные типы, основные API и некоторые сценарии использования и применения.

Пространство имен — очень важная часть контейнерной технологии. В последующих сериях мы продолжим рассказывать вам о таких технологиях, как контейнеры и Kubernetes, так что следите за обновлениями.


Добро пожаловать, чтобы подписаться на мой публичный аккаунт статьи [MoeLove]

TheMoeLove