Архитектура Docker
TL;DR: Docker = CLI → Daemon → containerd → runc → ядро Linux. Контейнер — это обычный процесс, изолированный namespaces и ограниченный cgroups. Не VM.
Docker — это не монолитное приложение, а платформа, работающая по клиент-серверной архитектуре. Она абстрагирует управление примитивами ядра Linux (namespaces, cgroups) для запуска процессов в изолированных окружениях.
Понимание архитектуры необходимо для отладки проблем с правами доступа, сетью и производительностью, а также для понимания отличий Docker от виртуальных машин.
Client-Server Модель
Работа Docker строится на взаимодействии трех компонентов:
- Docker Client (
docker): Утилита командной строки (CLI), с которой взаимодействует пользователь. Клиент не запускает контейнеры самостоятельно; он конвертирует команды (например,docker run) в REST API запросы. - Docker Host (Daemon
dockerd): Фоновой процесс, работающий на хост-системе. Он слушает запросы от клиента, управляет объектами (образы, контейнеры, сети, тома) и делегирует задачи низкоуровневым рантаймам. - Registry: Хранилище образов (Docker Hub, GHCR, Private Registry).
Docker Socket и безопасность
Взаимодействие между Клиентом и Демоном происходит через сокет.
- UNIX Socket (
/var/run/docker.sock): Основной канал связи. Файл принадлежит пользователюrootи группеdocker.
Security Warning: Любой пользователь, включенный в группу
docker, фактически получает полные праваrootна хосте. Через сокет можно запустить привилегированный контейнер (--privileged), смонтировать корневую файловую систему хоста (-v /:/host) и изменить любые системные файлы.
Rootless Mode (режим без root)
Для минимизации рисков безопасности современный Docker поддерживает Rootless mode.
- Принцип: Daemon и контейнеры запускаются от имени обычного пользователя, без использования
sudo. - User Namespaces: Используется маппинг UID/GID. Внутри контейнера процесс может “думать”, что он
root(UID 0), но ядро Linux отображает его на обычного пользователя (например, UID 1000) на хосте. - Изоляция: Если злоумышленник совершит побег из контейнера (Container Breakout), он окажется на хосте с правами обычного пользователя, что предотвращает компрометацию всей системы.
Стек выполнения (The OCI Stack)
Начиная с версии 1.11, Docker перешел на модульную архитектуру, основанную на стандартах OCI (Open Container Initiative). Демон dockerd больше не создает контейнеры напрямую.
1. containerd (High-Level Runtime)
Индустриальный стандарт управления жизненным циклом контейнеров.
- Роль: Управляет образами (pull/push), хранилищем и сетевыми интерфейсами.
- Задача: Получить команду от
dockerdи подготовить всё необходимое (слои файловой системы, спецификацию OCI Bundle) для запуска. containerdиспользуется и в Kubernetes (через CRI), что делает Docker и K8s совместимыми на уровне образов.
2. runc (Low-Level Runtime)
Референсная реализация спецификации OCI Runtime.
- Роль: Непосредственное взаимодействие с ядром Linux.
- Задача: Создать системный процесс, применив к нему пространства имен (namespaces) и лимиты (cgroups).
- После запуска контейнера процесс
runcзавершается, передавая управление процессу приложения. Это позволяет обновлять Docker/containerd без остановки запущенных контейнеров.
3. containerd-shim
Прослойка между containerd и процессом контейнера.
- Позволяет
runcзавершиться после запуска контейнера (daemonless containers). - Держит открытыми потоки ввода-вывода (STDIN/STDOUT/STDERR).
- Отслеживает код выхода (exit code) контейнера и сообщает его демону.
Примитивы ядра Linux
Docker не использует виртуализацию железа (как VMware или KVM). Изоляция достигается средствами ядра Linux.
Namespaces (Пространства имен)
Обеспечивают изоляцию видимости. Процесс в контейнере “думает”, что он единственный (или главный) в системе.
PID: Свое дерево процессов. PID 1 внутри контейнера изолирован от PID 1 хоста.NET: Свой сетевой стек (интерфейсы, IP, порты, iptables).MNT: Изолированная файловая система (mount points).IPC: Изоляция межпроцессного взаимодействия (Shared Memory).UTS: Свое имя хоста (hostname).USER: Маппинг UID/GID (позволяет быть root внутри контейнера, но обычным пользователем снаружи).
Cgroups (Control Groups)
Обеспечивают изоляцию ресурсов.
- Ограничивают потребление CPU, RAM, Disk I/O.
- Позволяют демону убить контейнер при превышении лимита памяти (OOM Killer).
Capabilities
Docker по умолчанию запускает контейнеры с урезанным набором привилегий root. Механизм Linux Capabilities позволяет дробить права суперпользователя.
- Например, контейнеру разрешено открывать порты (
NET_BIND_SERVICE), но запрещено менять системное время (SYS_TIME) или загружать модули ядра.
Подводные камни
| Заблуждение | Реальность |
|---|---|
| «Docker — это лёгкая VM» | Контейнеры делят ядро с хостом. Уязвимость в ядре = компрометация всех контейнеров |
| «Контейнер изолирован полностью» | Без user namespaces root в контейнере = root на хосте |
| «Docker socket безопасен» | Доступ к /var/run/docker.sock = полный root на хосте |
| «Можно обновить Docker без последствий» | Благодаря shim контейнеры продолжают работать при обновлении daemon/containerd |