Ответ
Docker для изоляции и управления контейнерами использует низкоуровневые возможности ядра Linux:
-
Namespaces (Пространства имён): Обеспечивают изоляцию. Каждый контейнер получает свои собственные изолированные экземпляры.
- PID namespace: Изолирует дерево процессов.
- Network namespace: Изолирует сетевые интерфейсы, таблицы маршрутизации, порты.
- Mount namespace: Изолирует точки монтирования файловой системы.
- IPC namespace: Изолирует межпроцессное взаимодействие (очереди сообщений, сегменты разделяемой памяти).
- UTS namespace: Изолирует hostname и domain name.
- User namespace: Изолирует UID/GID, позволяет отображать root внутри контейнера в непривилегированного пользователя на хосте.
-
Control Groups (cgroups): Ограничивают и отслеживают использование ресурсов.
- cpu, cpuacct: Ограничивают долю CPU и ведут учёт его использования.
- memory: Ограничивают использование оперативной памяти и подкачки.
- blkio: Контролируют операции ввода-вывода на блочных устройствах.
- pids: Ограничивают количество процессов.
-
Union File Systems (OverlayFS): Создают слоистые образы. Каждая инструкция в Dockerfile (
FROM,RUN,COPY) создаёт новый слой. OverlayFS объединяет их в единое представление для контейнера, что обеспечивает эффективность хранения и быстроту развёртывания. -
Container Runtime (runc): Это легковесная утилита, которая непосредственно запускает контейнер, используя перечисленные выше технологии. Docker Engine (или containerd) вызывает
runcдля создания контейнера.
Пример проверки namespaces для запущенного контейнера:
# На хосте найти PID процесса в контейнере
ps aux | grep <процесс_в_контейнере>
# Посмотреть, в каких namespaces работает процесс
ls -la /proc/<PID>/ns/
# Вывод: cgroup ipc mnt net pid user uts
# Каждая ссылка ведёт на уникальный идентификатор namespace.