Как работают namespaces в Docker?
Виртуализация контейнеров, как в Docker, возможна благодаря механизму изоляции, который использует ядро Linux. Одним из ключевых компонентов этой изоляции являются namespaces. Namespaces в Docker обеспечивают изоляцию ресурсов между контейнерами и хостом, что позволяет каждому контейнеру работать как отдельное окружение, не взаимодействуя напрямую с другими контейнерами или с основной операционной системой.
Виртуализация контейнеров, как в Docker, возможна благодаря механизму изоляции, который использует ядро Linux. Одним из ключевых компонентов этой изоляции являются namespaces. Namespaces в Docker обеспечивают изоляцию ресурсов между контейнерами и хостом, что позволяет каждому контейнеру работать как отдельное окружение, не взаимодействуя напрямую с другими контейнерами или с основной операционной системой.
В этом руководстве мы рассмотрим, что такое namespaces, как они работают в Docker, и какие типы namespaces используются для создания контейнеров.
Что такое namespaces?
Namespaces — это технология, встроенная в ядро Linux, которая позволяет изолировать определённые ресурсы для групп процессов. Используя namespaces, Linux может "разделить" различные системные ресурсы между процессами, так что они видят только свою ограниченную часть системы. Это ключевой компонент контейнеризации, потому что он создаёт иллюзию, что каждый контейнер работает в своей собственной операционной системе.
Применение namespaces позволяет контейнерам:
- Иметь собственное файловое пространство.
- Иметь свои сетевые интерфейсы.
- Иметь свои идентификаторы процессов.
- Изолировать ресурсы, такие как устройства и IPC (межпроцессорное взаимодействие).
Типы namespaces, используемые в Docker
Docker использует несколько различных типов namespaces для изоляции контейнеров от хоста и друг от друга. Каждый тип namespace отвечает за изоляцию определённого ресурса.
1. Mount (mnt) namespace
Mount namespace обеспечивает изоляцию файловой системы. В каждом контейнере есть своё собственное файловое пространство, которое включает в себя корневой каталог, примонтированные тома и другие файловые ресурсы. Контейнеры видят только ту файловую систему, которая была им предоставлена, и не могут получить доступ к файловой системе хоста напрямую.
Это позволяет Docker предоставлять каждому контейнеру уникальное файловое пространство, при этом обеспечивая возможность монтировать внешние тома для обмена данными с хостом.
Пример:
Когда контейнер запускается, Docker создаёт новый mount namespace, в котором примонтирована корневая файловая система контейнера:
docker run -it ubuntu /bin/bash
Этот контейнер будет иметь своё собственное изолированное файловое пространство, где можно устанавливать или удалять файлы без воздействия на хост.
2. Process ID (pid) namespace
PID namespace изолирует процессы внутри контейнера. Это значит, что каждый контейнер имеет свою собственную нумерацию процессов, которая не пересекается с нумерацией процессов на хосте или в других контейнерах. В результате контейнер видит только свои процессы, и процессам внутри контейнера не видны процессы, запущенные на хосте или в других контейнерах.
Пример:
Запустив контейнер и посмотрев список процессов внутри контейнера с помощью команды ps
, вы увидите только процессы, относящиеся к этому контейнеру:
docker run -it ubuntu /bin/bash
ps aux
Контейнер не видит процессы хоста и других контейнеров, что повышает безопасность и изоляцию.
3. Network namespace
Network namespace изолирует сетевые интерфейсы, маршруты и сетевые устройства (такие как виртуальные сетевые интерфейсы) для каждого контейнера. Это позволяет контейнерам иметь свои собственные сетевые интерфейсы и маршруты, не взаимодействуя с сетевыми настройками хоста.
Каждый контейнер в Docker по умолчанию получает свой собственный виртуальный сетевой интерфейс и IP-адрес, который изолирован от хоста и других контейнеров, если они не подключены к одной и той же сети Docker.
Пример:
При запуске контейнера Docker создаёт отдельный сетевой namespace и подключает его к основной сети Docker через виртуальные интерфейсы.
docker run -it ubuntu /bin/bash
ip addr
Эта команда покажет сетевые интерфейсы, доступные внутри контейнера, включая его уникальный IP-адрес.
4. UTS (UNIX Time-Sharing) namespace
UTS namespace изолирует имя хоста и доменное имя (hostname и domain name) для каждого контейнера. Это позволяет контейнеру иметь собственное имя хоста, которое может отличаться от имени хоста системы.
Это полезно для работы с сервисами, которым требуется определённое имя хоста. Вы можете задавать имя хоста для контейнера при его запуске.
Пример:
При запуске контейнера можно указать имя хоста с помощью флага --hostname
:
docker run -it --hostname mycontainer ubuntu /bin/bash
В этом контейнере команда hostname
покажет mycontainer
как имя хоста, что изолирует его от имени хоста основной системы.
5. IPC (Interprocess Communication) namespace
IPC namespace изолирует механизмы межпроцессного взаимодействия, такие как общая память и семафоры. Это позволяет контейнерам использовать свои собственные механизмы IPC, не влияя на IPC других контейнеров или хоста.
IPC namespace полезен для изоляции взаимодействий между процессами, чтобы контейнеры не могли вмешиваться в IPC других контейнеров или хоста.
6. User namespace
User namespace позволяет изолировать идентификаторы пользователей и групп внутри контейнера от хоста. Это значит, что внутри контейнера можно запускать процессы от имени пользователя root
, но на хосте этот пользователь будет отображаться как пользователь с более низкими привилегиями.
Эта возможность повышает безопасность контейнеров, так как позволяет запускать контейнеры от имени пользователя root
без риска влияния на хост.
Пример:
Для запуска контейнера с включённым user namespace можно использовать следующую команду:
docker run --userns-remap=default -it ubuntu /bin/bash
Это создаст маппинг идентификаторов пользователей между хостом и контейнером, изолировав права доступа.
Как посмотреть namespaces, используемые контейнером
Вы можете увидеть, какие namespaces используются контейнером, с помощью команды lsns
, доступной в утилите util-linux
, или команд nsenter
и docker inspect
.
Пример использования docker inspect
для просмотра информации о контейнере:
docker inspect <название_контейнера>
Команда выведет полную информацию о контейнере, включая идентификаторы namespaces, используемые контейнером.
Заключение
Namespaces — это основа изоляции контейнеров в Docker. Они позволяют каждому контейнеру работать в изолированном окружении, где он видит только свои собственные ресурсы, такие как файловая система, процессы, сеть и другие системные компоненты. Используя различные типы namespaces, Docker обеспечивает высокий уровень безопасности и изоляции для контейнеров, делая их отличным выбором для работы с приложениями в изолированных окружениях.