Всем привет, меня зовут Дмитрий Желудков, я архитектор по эксплуатации в одной корпорации, а ещё один из авторов курса учебного центра Слёрм «Docker для админов и разработчиков». Сегодня мы заглянем под капот и разберёмся, на каких китах держится вся эта магия.

Зачем это знать?

На незаданный вопрос я смело отвечу: чтобы перестать бояться. Когда вы понимаете, что происходит внутри, вы перестаёте воспринимать Docker как «волшебный чёрный ящик», который просто работает. Вы начинаете грамотно диагностировать проблемы, осознанно выбирать инструменты и, в конечном счёте, строить более надёжные и эффективные системы. Это знание — суперсиньор-скилл, который отделяет «админа, который умеет в докер» до «архитектора, который понимает, как это работает».

Слоёный пирог: из чего на самом деле состоит Docker

Давайте разберёмся, что происходит, когда вы даёте команду docker run nginx.

1. Docker CLI и Демон: начало пути

Вы вводите команду в терминале. Эту команду подхватывает Docker CLI (клиент) и через REST API передаёт её Docker Daemon (dockerd) — главному управляющему, который и выполняет всю тяжёлую работу.

2. Контейнерный рантайм: containerd в игре

Демон сам не умеет запускать контейнеры. Для этого у него есть более низкоуровневый помощник — containerd. Его главная задача — управлять жизненным циклом контейнеров: загружать образы, создавать, запускать и удалять контейнеры. В 2017 году containerd был выделен из состава Docker в самостоятельный проект и передан под опеку Cloud Native Computing Foundation (CNCF).

3. OCI и runc: стандарт и его исполнитель

Containerd, в свою очередь, обращается к runc. Это и есть тот самый фундамент — легковесная утилита, которая непосредственно создаёт и запускает контейнеры. Runc — эталонная реализация стандарта OCI (Open Container Initiative).

Историческая справка: OCI — это организация, созданная для выработки единых стандартов на форматы контейнерных образов и рантаймов. Это был ответ индустрии на доминирование Docker. Стандартизация позволила создать экосистему взаимозаменяемых компонентов. Итак, цепочка выглядит так:

docker run → Docker CLI → Docker Daemon (dockerd) → containerd → runc → контейнер

Магия под капотом: namespaces, cgroups и OverlayFS

А что же делает runc? Вот тут начинается самая соль! Представьте, что runc — это такой супер-прораб на стройке контейнера. У него нет своих материалов, но он мастерски использует то, что ему предоставляет ядро Linux. Он берет три кита и строит из них нашу «песочницу»:

1. Namespaces (пространства имён) – виртуальные миры

Это не просто «изоляция», это создание параллельной реальности для вашего приложения. Каждый namespace — это своя маленькая вселенная:

PID namespace: контейнер думает, что его процесс — это PID 1, король и бог, и не подозревает о существовании других процессов на хосте.

Network namespace: к контейнера своя собственная сеть — свой localhost, свои сетевые интерфейсы, свои порты. Когда вы биндите порт 80 в контейнере, он не конфликтует с портом 80 на хосте — потому что это разные миры!

Mount namespace: создает иллюзию, что у контейнера своя корневая файловая система /, хотя на самом деле это всего лишь папка на диске.

Контейнер живет в этой матрице и искренне верит, что он один на всей машине.

2. Cgroups (контрольные группы) – регуляторы аппетита

Помните того коллегу, который всегда доедает всю пиццу в офисе? Так вот, cgroups — это тот самый мудрый менеджер, который говорит: «Вася, тебе пол-пиццы, и ни кусочка больше!»

Конкретно:

CPU: «Ты можешь использовать только 2 ядра из 16, больше не положено»

Memory: «Вот тебе 512 МБ RAM, превысил — получил OOM Killer»

I/O: «Дисковые операции не больше 100 MB/s, чтобы другим тоже досталось»

Без cgroups ваш «скромный» контейнер мог бы безнаказанно сожрать все ресурсы сервера.

3. Union File Systems (OverlayFS) – слоёный пирог файловых систем

А это вообще магия оптимизации! Представьте, что вы делаете презентацию:

Базовый образ (Ubuntu) — это ваша стандартная тема оформления слайдов

RUN apt-get install — вы добавляете новый слайд поверх

COPY . /app — добавляете еще один слайд

Когда вы запускаете 10 контейнеров, они все используют одну и ту же базовую тему (читай — слой), но у каждого поверх свои уникальные слайды. Экономия места — колоссальная! А если один контейнер что-то меняет в файле — он просто создаёт свою копию в верхнем writable-слое, не трогая оригинал.

CRI-O: Kubernetes говорит: «Нам не нужен весь Docker»

С появлением Kubernetes началась настоящая головная боль. Представьте: kubelet — это такой суровый прораб на стройке кластера. Ему нужно управлять сотнями рабочих (контейнеров), но каждый рабочий говорит на своем диалекте — Docker, containerd, rkt... Беспорядок!

И тогда родился CRI (Container Runtime Interface) — универсальный переводчик, этакий «технический английский» (хотя напрашиваеться больше ассоциация про «пиджин») для общения прораба с любым контейнерным рантаймом.

Но наш старый добрый Docker оказался тем самым упрямым работягой, который говорит только на своем наречии. «CRI? Не, не слышал». Пришлось городить костыль под названием dockershim — этакого личного переводчика specifically для Docker. Работало, но было криво, сложно и постоянно ломалось.

Сообщество посмотрело на это безобразие и сказало: «Так, стоп! Давайте сделаем рантайм, который из коробки говорит на языке CRI — без костылей, без лишних телодвижений».

Так из инженерной лени и стремления к идеалу родился CRI-O. Представьте себе спринтера-олимпийца — никакого лишнего жира, только рельефные мышцы. Его единственная задача — молниеносно и идеально исполнять команды kubelet'а. Ни тебе сборки образов, ни крутых фич для разработчиков — только чистый, голый запуск контейнеров в Kubernetes.

Под капотом он использует проверенную классику: для запуска контейнеров — наш старый знакомый runc, для работы с образами — containers/image. CRI-O — это не новый движок, это гениальный минималистичный адаптер, который взял всё лучшее из эко��истемы контейнеров и заточил это исключительно под нужды Kubernetes.

CRI-O vs Docker: кто есть кто в нашем контейнерном королевстве

А теперь сравним более детально этих ребят.

Представьте, что Docker — это такой швейцарский армейский нож с двадцатью лезвиями, открывалкой, штопором и встроенным фонариком. Он универсален! Им можно и банку консервную в походе вскрыть, и винтик подкрутить, и даже перед друзьями покрасоваться. Он создан для разработчика, который хочет на своей машине сделать всё и сразу: собрать образ, запустить контейнер, посмотреть логи, настроить сеть — одна команда docker, и мир у ваших ног. За это удобство вы платите его некоторой «тяжеловесностью» и тем, что он тянет за собой кучу функций, которые в продакшене могут быть и не нужны.

А теперь смотрите на CRI-O. Это не нож, это — идеально отточенное скальпельное лезвие в руках хирурга-кубернета. У него одна-единственная задача: безупречно исполнять приказы Kubernetes. Ни тебе сборки образов, ни лишних команд — только чистая, минималистичная работа по запуску подов и контейнеров. Он легковесный, стремительный и заточен на безопасность. Его не существует вне Kubernetes, он — его продолжение.

Так в чём же принципиальная разница, если отбросить метафоры?

Философия: Docker — это универсальная платформа для всех, а CRI-O — специализированный инструмент для одной экосистемы (Kubernetes).

Архитектура: Docker — это монолитный «комбайн» (хотя внутри и состоит из компонентов), а CRI-O — это минималистичный модуль, который делает ровно то, что от него просят, и не грамма больше.

Управление: чтобы пообщаться с Docker, вы и��пользуете богатейшую команду docker. Чтобы пообщаться с CRI-O, вы в 99% случаев будете использовать команды kubectl, потому что он сам по себе — лишь послушный исполнитель.

Проще говоря: Docker — это ваш личный многофункциональный гараж, где вы и машину собираете, и ремонтируете, и тюнингуете. А CRI-O — это конвейерная линия на заводе, которая делает одну операцию, но делает её идеально, быстро и без лишних движений.

Вот и весь расклад. Не инструменты друг другу конкуренты, а разные философии для разных задач.

Историческая дорожная карта: как всё делилось

По-быстрому пробежимся, как всё развивалось, чтобы понимать, какого года документации стоит брать.

2013: Появление Docker. Изначально использовался LXC как рантайм по умолчанию.

2015: Docker создаёт собственную библиотеку libcontainer и заменяет LXC на runc, становясь более самостоятельным.

2017: Containerd выделяется из Docker Engine в отдельный проект и передаётся CNCF. Docker также разделяется на Community (CE) и Enterprise (EE) редакции.

2020: Появление поддержки Compose V2 в Docker Engine 20.10.

2022: Kubernetes 1.24 полностью удаляет dockershim, переводя экосистему на использование containerd и CRI-O.

2023: Docker 24.0 полностью отказывается от старого docker-compose (v1) в пользу нового docker compose (v2).

А для чего это всё?

Вот мы и подошли к главному выводу. Вся эта история с разделением, стандартизацией и появлением новых проектов вроде CRI-O — это не просто технические причуды. Это прямое отражение главных трендов в современной разработке и эксплуатации.

Заменяемость компонентов и микросервисная архитектура. Раньше у вас был монолитный Docker, теперь у вас есть набор независимых инструментов (Docker, containerd, runc, CRI-O), которые общаются через чётко определённые API (CRI, OCI). Вы можете создать свою собственную «сборку» контейнерной платформы, как из кубиков Лего, выбирая лучший инструмент для каждой конкретной задачи.

Специализация. CRI-O — идеальный пример специализации. Он не пытается быть всем для всех, как Docker. Он делает одну вещь — запускает контейнеры в Kubernetes, и делает это блестяще, будучи при этом легче и безопаснее.

Стандарты и открытость. Существование OCI и CRI означает, что ни одна компания (даже Docker Inc.) не может единолично управлять всей экосистемой. Это гарантирует здоровую конкуренцию, инновации и защищает инвестиции пользователей. Ваши образы, собранные по стандарту OCI, будут работать с любым совместимым рантаймом сегодня и в обозримом будущем.

Так что, разобравшись в том, что творится под капотом, вы видите не просто набор программ, а целую философию построения гибких, надёжных и открытых систем. Это и есть тот самый переход от работы «администратором Docker» к роли «инженера контейнерной платформы».

Приятного погружения в глубины! Надеюсь, теперь эта кроличья нора кажется вам не такой уж и тёмной.


Освоить Docker и научиться уверенно разворачивать, управлять и масштабировать приложения в реальных условиях можно на курсе «Docker для админов и разработчиков». На нём вы разберёте особенности использования Docker с различными языками программирования, научитесь безопасно работать с Docker-контейнерами и расширите пул доступных вам инструментов. Все подробности — по ссылке.

Комментарии (0)