изучаем контейнеры изнутри
Поговорим об истории контейнеров, попробуем сделать его руками, через команды Линукс, и поспорим о терминологии.
Почему надо отвыкать от слова докер и именовать грамотно - контейнер ?? Похожую ситуацию вспоминаю в древние времена, когда в постсоветскую действительность вдруг проникла фотокопировальная техника, почти сразу получившая имя ксерокс, глагольная форма, пардонс, “ксерить”. Доходило до абсурда: ксерокс марки кэнон!! Точно также, права на слово докер принадлежит компании Docker Inc., негоже поминать её всуе, по крайней мере не имея никакого корыстного интереса.
Дальнейшее повествование будет представлять собой взрывоопасную (для мозга) смесь моих еретических идей и нейрослопа от Gemini, именно так представляется Google AI mode, если его прямо об этом спросить, мой помощник, собеседник, и зачастую ментор, хотя я сам ещё совсем недавно был таковым в проекте h.carreers. Но стажёры, кому я помогал, освоили ИИ, запросы на занятия практически прекратились приблизительно год назад. Затем я сам вдруг обнаружил, что можно делать вполне серьёзные проекты даже не покупая токены, не гоняясь за модными моделями, пользуясь только общедоступным. Не хочу быть голословным, вот 2 примера.
- rpi5imager - скрипт и документация как вдохнуть новую жизнь в raspberry pi 5, пылившийся на полке, сделан в поисковой строке баузера. Для более сложного проекта,
- nft firewall для большой организации, воспользовался ассистентом от Яндекса на их аналоге гитхаба.
Да, возможности ИИ иногда пугают и создают небывалую конкуренцию. Но, чуть привыкнув, можно настроить весьма эффективное взаимодействие. В качестве ещё одного примера, приведу пошаговую, почти дословно, мою беседу с Gemini. Вижу её именно так - увидел интересный вопрос, задал в поисковой строке, попросил проверить и/или уточнить обрывки собственных знаний, и понеслось, не мог остановиться. Вопросы я всегда задаю на английском - не люблю переключать раскладку. Это также чуть выгоднее в случае платного сервиса, мне ассистент Яндекса рассказал: английский немного эффективнее в смысле токенов.
Началось моё приключение утром, за просмотром новостей, случайно наткнулся на пост на хабре. Да, идея интересная, результат получил сразу, но попросил кое-что уточнить. Поэтому порядок вопросов/ответов немного нарушен, также почистил ответы, попытался сделать связный рассказ.
Итак, продолжаем начатый спор о терминах, попросил уточнить, все мои вопросы помечены как ^# goo :, в маркдауне выглядят как “head 1”
goo : is the docker registered trademark as windows(C) ??
Да, Docker — это зарегистрированная торговая марка, точно так же, как и Windows. Владельцем этого товарного знака является коммерческая компания Docker, Inc. (ранее известная как dotCloud). Несмотря на то, что сама технология контейнеризации строится на базе открытых исходных кодов Linux (Open Source), само слово «Docker» и его логотип (кит, везущий контейнеры) жестко защищены законами о товарных знаках.
Вот несколько важных нюансов о том, как работает торговая марка Docker:
- Что защищено товарным знаком?
Зарегистрированная марка DOCKER® распространяется на:
- Программное обеспечение и утилиты для разработки (Docker Desktop, Docker Hub);
- Фирменное наименование и логотипы компании.
- Строгие правила использования бренда (Trademark Guidelines)
Компания Docker, Inc. очень ревностно защищает свое имя (по аналогии с тем, как Microsoft защищает Windows):
• Именование сторонних проектов: Вы не можете назвать свою собственную программу или сайт, например, «Docker-Manager». Правилами Docker Trademark Guidelines предписано использовать формулировки вроде «Manager for Docker» (Менеджер для Docker), чтобы у пользователей не возникало ощущения, будто ваш продукт официально одобрен или создан самой компанией Docker.
• Частичный ребрендинг: Из-за ограничений на торговую марку, когда базовый открытый исходный код Docker Engine был передан в проект сообщества (upstream), его пришлось переименовать в Moby.
- Разница между OSS (Open Source Software) и Лицензией на бренд
Ваш эксперимент по ручному созданию контейнера наглядно показывает эту границу:
• Ограничения cgroups, пространства имен и chroot — это свободные технологии ядра Linux, которые может использовать кто угодно.
• Формат образов OCI (Open Container Initiative) — это открытый стандарт.
Но бренд, экосистема и готовые бинарные сборки Docker — это собственность Docker, Inc. Именно поэтому для крупных коммерческих компаний использование, например, утилиты Docker Desktop стало платным по подписке, хотя ядро и низкоуровневые контейнеры остаются бесплатными.
goo : ok, still wonder - who is the author of docker concept ?? as you said above, the overlayfs put docker apart from lxc
Автором и создателем концепции Docker является франко-американский программист и предприниматель Соломон Хайкс (Solomon Hykes)
В 2008 году он основал в Париже компанию dotCloud, которая предоставляла услуги PaaS (Platform-as-a-Service). Внутри dotCloud разработчикам нужно было как-то изолированно и быстро запускать приложения клиентов на серверах. Для этого команда Соломона написала внутреннюю утилиту. В марте 2013 года на конференции PyCon Хайкс впервые показал эту утилиту миру и выложил её код в опенсорс под именем Docker. Проект произвел такой фурор, что вскоре всю компанию dotCloud переименовали в Docker, Inc.
Вы абсолютно правы: именно подход к файловой системе (включая использование OverlayFS) и изменил саму парадигму, проведя четкую черту между Docker и классическим LXC.
Главный концептуальный сдвиг: Контейнер Системы vs Контейнер Приложения
До Docker существовал проект LXC (Linux Containers) (выпущенный примерно в 2008 году), который тоже использовал пространства имен и cgroups. Но идеология была совсем другой:
- LXC — это «Системные контейнеры» (System Containers):
Цель LXC — дать вам полноценную, но легковесную виртуальную машину. Когда вы запускаете LXC, внутри стартует полноценная ОС: запускается процесс инициализации (init или systemd), поднимаются системные логи, cron, ssh и так далее. У каждого контейнера свой постоянный, тяжелый rootfs.
- Docker — это «Контейнеры Приложений» (Application Containers):
Соломон Хайкс перевернул эту логику. Он сказал: «Нам не нужна виртуальная операционная система. Нам нужно просто изолированно запустить один конкретный процесс (например, базу данных или веб-сервер) со всеми его зависимостями». В Docker контейнер живет ровно столько, сколько живет его главный запущенный процесс (PID 1).
Как OverlayFS разделил эти технологии
Изначально (в 2013 году) Docker первой версии работал поверх того самого LXC, используя его как движок для создания пространств имен. Но Docker добавил концепцию слоев (layers) и файловых систем типа UnionFS/OverlayFS.
• В LXC: если вам нужно 5 контейнеров Ubuntu, вы создаете 5 независимых копий файловой системы. Они занимают много места и ведут себя как обычные жесткие диски серверов.
• В Docker (благодаря слоям): базовый образ Ubuntu лежит в режиме Read-Only один раз на диске. Сверху с помощью OverlayFS накладывается микро-слой Read-Write для каждого контейнера.
Это позволило Соломону Хайксу внедрить концепцию Docker Hub и докеризации. Образы стали весить мало, их стало легко скачивать по слоям, пушить в сеть и мгновенно разворачивать на любой машине по принципу: «Собрано один раз — работает везде».
Уже в 2014 году Docker полностью отказался от LXC, написав собственную низкоуровневую библиотеку libcontainer (которая позже превратилась в стандарт runc), чтобы управлять пространствами имен, cgroups и слоями файловой системы напрямую через ядро Linux.
Этот вопрос я задал после прочтения эмоциональной статьи о Соломоне Хайксе
goo : i’m shocked - solomon hykes created docker, then docker inc., leaved it and organized cncf !! the farther of docker now competes with his child ??
Здесь есть очень важная историческая и юридическая деталь, которая немного меняет картину. Вы правы в своих эмоциях, но Соломон Хайкс не основывал CNCF самостоятельно и никогда не воевал со своим детищем.
На самом деле история раскола и создания CNCF — это классическая «Игра престолов» в мире Open Source, где Docker Inc. сначала пыталась узурпировать власть, но в итоге была вынуждена пойти на мирное соглашение с гигантами индустрии.
Вот как всё происходило в реальности:
- Кто на самом деле создал CNCF?
Фонд CNCF был создан в 2015 году консорциумом ИТ-гигантов во главе с The Linux Foundation, Google, Red Hat, IBM и… самой компанией Docker Inc. Да-да, Docker был одним из основателей фонда! Соломон Хайкс вошел в самый первый состав Технического комитета (TOC) CNCF в качестве представителя от Docker. Так что он не создавал CNCF «на стороне» назло Docker — он строил этот фонд как общую нейтральную площадку.
- В чем была драма и почему случился конфликт?
В 2014–2016 годах между Google (создателями Kubernetes) и Docker Inc. (где Соломон Хайкс был CTO) вспыхнула настоящая война за стандарты:
• Амбиции Docker: Docker Inc. хотела контролировать весь стек. Они создали собственный оркестратор Docker Swarm и агрессивно продвигали его, пытаясь сделать так, чтобы контейнеры можно было запускать только через технологии Docker.
• Ответ индустрии: Google, Red Hat и другие игроки испугались монополии одной коммерческой компании. Они сказали: «Технология контейнеров слишком важна, чтобы принадлежать одной Docker Inc.». Google пожертвовала Kubernetes в CNCF, сделав его общим достоянием.
В этот момент Docker Inc. оказалась под колоссальным давлением. Индустрия пригрозила полностью бойкотировать Docker и написать свой открытый движок с нуля.
- Великое перемирие и уход Соломона
Чтобы спасти экосистему от раскола, сторонам пришлось договориться. Под эгидой Linux Foundation был создан комитет OCI (Open Container Initiative), куда Docker передал стандарты образов и рантайм runc. Чуть позже Docker передал в CNCF свой главный движок — containerd.
Для Соломона Хайкса это был тяжелый период. Он был хакером и творцом, а компания Docker Inc. превратилась в огромную корпорацию, разрываемую маркетингом, инвесторами и политическими войнами с Google.
В 2018 году Соломон официально объявил, что полностью покидает Docker Inc., написав трогательное прощальное письмо:
«Проекту теперь нужны профессионалы корпоративного софта для масштабирования бизнеса, а я по своей натуре — просто хакер, который любит создавать инструменты для разработчиков».
Чем Соломон Хайкс занимается сейчас?
Он не конкурирует с Docker и не занимается оркестрацией в CNCF. Он вернулся к тому, что любит больше всего — к программированию с нуля.
В 2019 году он основал новый стартап Dagger.io. Это продвинутый движок для автоматизации CI/CD пайплайнов, который (по иронии судьбы) запускает шаги сборки внутри… контейнеров. Проекты Docker Inc. и Dagger сейчас являются технологическими партнерами, и Соломон регулярно выступает на конференциях, тепло общаясь с новой командой Docker.
Так что «отец контейнеров» не воюет со своим ребенком — он просто отдал его взрослеть в большую ИТ-семью (CNCF), а сам ушел воспитывать нового технологического «младенца».
goo : tell the story docker vs google
Это была одна из самых драматичных войн в истории Кремниевой долины — Битва за оркестрацию (2014–2017 годы). На кону стоял контроль над тем, как будет устроен весь современный интернет и облачные вычисления. С одной стороны стоял дерзкий, молодой стартап Docker Inc. во главе с Соломоном Хайксом. С другой — технологический левиафан Google, у которого за плечами был 10-летний опыт управления миллионами контейнеров внутри собственной поисковой системы.
Вот хроника этой войны, разложенная по этапам.
Акт 1: «Троянский конь» от Google (2014)
Когда в 2013 году Docker взорвал ИТ-индустрию, инженеры Google сразу поняли: это то, чего им не хватало. Внутри Google уже давно работала секретная система Borg, которая управляла всеми их серверами с помощью контейнеров, но она была слишком сложной и проприетарной.
Google предложила Docker Inc. сотрудничество. Инженеры Google помогали развивать Docker, но одновременно с этим они начали писать Kubernetes — опенсорсную версию своего Borg, адаптированную под контейнеры Docker.
В чем был подвох: Google создавала Kubernetes как открытый стандарт под эгидой независимого фонда (так и появился CNCF), чтобы объединить вокруг себя Red Hat, IBM и Microsoft. Цель была проста: сделать так, чтобы никто не мог монополизировать рынок контейнеров.
Акт 2: Docker принимает бой и создает Swarm (2015)
Руководство Docker Inc. быстро разгадало план Google. Они поняли, что если Kubernetes станет главным стандартом, то сам Docker превратится в «глупую утилиту» — низкоуровневый винтик под капотом чужой огромной системы. А инвесторы требовали от Docker миллиардных доходов. Тогда Docker Inc. решает создать собственного конкурента Kubernetes — Docker Swarm.
Столкновение философий (UX против Архитектуры)
| Критерий | Путь Docker (Swarm) | Путь Google (Kubernetes) |
|---|---|---|
| Философия | Простота и UX. Если ты знаешь, как запустить один контейнер, ты знаешь, как запустить кластер. | Промышленный масштаб. Сложная архитектура, рассчитанная на отказоустойчивость тысяч серверов. |
| Командная строка | Тот же самый CLI. Вместо docker run ты пишешь docker service create. | Совершенно новый, пугающий новичков инструмент kubectl. |
| Порог входа | Кластер собирался за 2 минуты одной командой docker swarm init. | В 2015 году развернуть K8s вручную было ночным кошмаром (т.н. Kubernetes the Hard Way). |
Акт 3: Роковая ошибка Docker (2016)
В 2016 году Docker совершает агрессивный маркетинговый ход: они «намертво» вшивают Docker Swarm прямо в движок Docker Engine (релиз 1.12). Они надеялись, что раз Docker установлен у каждого разработчика на планете, то люди автоматически начнут использовать Swarm в продакшене, проигнорировав Kubernetes.
Почему это привело к обратному эффекту:
Индустрия испугалась. Крупные корпорации (банки, ритейлеры, телекомы) увидели в этом попытку жесткой вендор-блокировки (Vendor Lock-in). Никто не хотел, чтобы критическая инфраструктура зависела от капризов и акций одного стартапа, который в любой момент мог сделать Swarm платным.
ИТ-гиганты сплотились вокруг Google. Red Hat бросила все силы на развитие Kubernetes. Крупные облачные провайдеры начали один за другим создавать управляемые сервисы Kubernetes (первым стал Google GKE, затем подтянулись AWS и Azure).
Акт 4: Капитуляция (2017)
Несмотря на великолепный UX и простоту Swarm, Kubernetes победил за счет своей архитектурной мощи. Он умел делать то, чего Swarm не мог: автоматически масштабировать узлы, гибко управлять дисками (Persistent Volumes), делать умный self-healing и предоставлять глубокую сетевую кастомизацию.
В октябре 2017 года на конференции DockerCon произошло историческое событие, которое официально завершило войну. Руководство Docker Inc. вышло на сцену и объявило: «В следующей версии Docker Desktop мы встраиваем поддержку Kubernetes». Это было признанием полного поражения. Docker Swarm не был удален, но он был переведен в разряд нишевых инструментов для маленьких проектов.
Итог войны: Кто выиграл?
В этой войне проигравших, как ни странно, не оказалось:
- Google выиграла стратегически. Они сделали Kubernetes стандартом де-факто для всего мира. Это позволило им успешно конкурировать с Amazon AWS, так как приложения теперь можно было легко переносить из любого облака в облако Google Cloud (ведь K8s везде одинаковый).
- Индустрия получила мощный, стандартизированный слой оркестрации (CNCF), защищенный от монополии.
- Docker Inc., хоть и проиграла войну серверов, смогла выжить. Они провели масштабную реструктуризацию, отказались от амбиций захватить дата-центры и сфокусировались на том, что у них получается лучше всего — на создании идеальных инструментов для локальной разработки (Docker Desktop, BuildKit), подписку на которые сейчас с удовольствием покупают миллионы компаний по всему миру.
Эта история отлично дополняет вашу рекомендацию студентам по поводу Podman! Ведь Podman — это, по сути, логическое продолжение идей той войны: утилита, которая убирает legacy-наследие «имперских амбиций» Docker и сразу создана для мира, в котором победил Kubernetes.
Хотите, мы сформулируем короткую историческую байку на 5 минут для вашей следующей лекции, чтобы объяснить студентам эту взаимосвязь?
goo : yes, want the fable story
🦊 Басня об Умном Ките и Мудром Борге (История для лекции)
Жил-был в ИТ-океане молодой и очень проворный Кит по имени Докер. Кит был невероятно силен: он умел подхватывать тяжелые программы, упаковывать их в аккуратные контейнеры и мгновенно перевозить с одного компьютера на другой. Разработчики обожали Кита. Они кричали: «Докер — наш спаситель! Больше никаких мучений с настройкой окружения!» Кит рос, толстел от похвалы и инвестиций, и вскоре нацепил на голову корону. Он решил: «Раз я управляю контейнерами на ноутбуках, то я должен править и всеми серверами в мире!» И построил Кит свой замок — Docker Swarm. Замок был простой, красивый, двери открывались одной командой. Кит заставлял всех строить только так, как нравилось ему самому, и грозился сделать проход в замок платным. В том же океане жил старый и суровый великан Google. Он уже десять лет правил миллионами контейнеров в своих подземных чертогах с помощью древнего заклинания Borg. Великан посмотрел на молодого Кита и понял, что тот хочет узурпировать власть над всем интернетом. Великан не стал воевать с Китом в открытую. Вместо этого он взял частицу своего мощного Borg’а, обернул её в красивую обертку и выпустил в мир под именем Кубернетис. Но главное — великан совершил мудрый маневр: он не оставил Кубернетис себе. Он отдал его независимому Ордену CNCF, сказав: «Этот инструмент принадлежит всему миру. Ни одна коммерческая компания не сможет диктовать вам свои условия». ИТ-гиганты и крупные банки испугались капризного Кита в короне и сплотились вокруг мудрого Великана. Они начали достраивать к Кубернетису мощные стены, автоматические лифты (Self-healing) и огромные хранилища (Persistent Volumes). Замок Кубернетиса стал сложным, как мегаполис, но надежным, как скала. Кит Докер злился, вшивал свой Swarm во все свои программы насильно, но время было упущено. В конце концов, в 2017 году Кит приплыл к стенам Кубернетиса, снял корону и сказал: «Твоя правда, Великан. Ты победил на серверах. Давай дружить». Кит остался жить на компьютерах у разработчиков, помогая им собирать контейнеры, а Кубернетис стал править всеми дата-центрами планеты. А пока они мирились, из тени деревьев на опушке леса вышел молодой и поджарый лис по имени Подман. Он посмотрел на Кита Докера и подумал: «Ты стал слишком толстым, legacy-зависимым и до сих пор носишь с собой тяжелый рюкзак-демон от старых амбиций. А мир уже принадлежит Кубернетису. Я буду помогать людям ходить к Кубернетису напрямую, без твоих посредников». И лис побежал вперед, увлекая за собой самых продвинутых инженеров.
💡 Мораль (для студентов):
Технологический мир не прощает монополии и закрытости. Docker совершил революцию, дав нам контейнеры, но проиграл войну за оркестрацию, потому что пытался контролировать всё в одиночку. Сегодня, изучая Podman и Kubernetes, мы учимся мыслить не масштабами одного «Кита», а масштабами всей глобальной и открытой облачной индустрии. Эту басню можно использовать как идеальное введение к лабораторной работе по Podman, которую мы оформили в прошлом шаге. Хотите, мы добавим этот текст в начало вашей методички podman_to_k8s_cheatsheet.md, чтобы она выглядела как законченная лекция?
goo : i see at https://github.com/docker is a big organization 33 persons and 156 repos. How many developers from that github org work directly or sponsored by Docker, Inc.
Цифра 33 человека на странице организации GitHub отображает исключительно тех сотрудников Docker Inc., которые вручную сделали свои профили публичными для этой конкретной организации. Реальный масштаб команды разработчиков и поддерживаемых специалистов значительно шире.
В экосистеме Docker разработчики разделены на три основные категории:
- Штатные инженеры Docker Inc. (Direct Employees)
В самой компании Docker Inc. работает порядка 500–600 сотрудников (по данным корпоративных отчетов и LinkedIn). Из них около 150–200 человек — это инженеры, программисты, архитекторы и специалисты по безопасности.
Они распределены по разным направлениям:
• Core Team: Разработка Docker CLI, Docker Compose и интеграций.
• Desktop & Hub Team: Разработка закрытых и коммерческих продуктов (Docker Desktop для Mac/Windows/Linux, Docker Hub).
• AI & Sandboxes (Новое направление): Команды, создающие среду для ИИ-агентов (проекты sbx, docker-agent).
- Независимые мейнтейнеры (Moby Project)
Большая часть открытого движка Docker живет в организации github.com. Это ядро контейнеризации.
• Здесь кодом управляют не только сотрудники Docker Inc., но и инженеры из Microsoft, Red Hat, IBM, Google, Intel и независимые разработчики со всего мира.
• Исторически вклад стороннего сообщества в core-репозитории Docker составляет более 60% от общего объема кода.
- Программа спонсорства Docker (DSOS)
Docker Inc. напрямую не платит индивидуальные зарплаты тысячам опенсорс-разработчиков через систему донатов, но у них действует масштабная программа Docker-Sponsored Open Source (DSOS):
• Программа поддерживает тысячи некоммерческих open-source проектов по всему миру.
• Вместо денег Docker спонсирует их инфраструктурой: предоставляет разработчикам этих проектов бесплатные коммерческие тарифы, безлимитное скачивание образов (без rate-limits), приоритетную поддержку и верифицированные бейджи (Verified Publisher) в Docker Hub. Это экономит сторонним командам огромные бюджеты на хостинг.
Почему на GitHub видно только 33 человека?
По умолчанию в GitHub членство сотрудников в организации является приватным (скрытым от посторонних глаз в целях безопасности, защиты от спама и хантинга). Те 33 профиля, которые вы видите (такие как @tonistiigi — создатель BuildKit, или @thaJeztah — ключевой мейнтейнер CLI) — это лишь публичные администраторы и тимлиды, которые открыли свой статус в профиле.
goo : pls, explain, how Docker Inc. works with cncf.io ?? I know they didn’t patented overlayfs, donated some container spec to OCI, communicate regarding hub.docker images repo security - what else ??
Взаимоотношения Docker Inc. и фонда CNCF (Cloud Native Computing Foundation) — это классический пример стратегии «coopetition» (сотрудничество + конкуренция).
Docker фактически создал фундамент для всего облачного рынка, но чтобы технология не принадлежала одной коммерческой компании (чего боялись гиганты вроде Google, Red Hat и IBM), Docker передал свои ключевые низкоуровневые компоненты в фонды OCI (Open Container Initiative) и CNCF. Помимо стандартов OCI и безопасности образов в Docker Hub, Docker Inc. и CNCF активно взаимодействуют по следующим ключевым направлениям:
- Передача и поддержка главного движка — containerd
Самый большой вклад Docker в CNCF — это передача проекта containerd (низкоуровневого демона, который управляет жизненным циклом контейнеров: скачивает слои, управляет хранилищем и запускает runc).
• Как это работает сейчас: containerd является проектом уровня Graduated в CNCF (высший статус стабильности). На нем работает весь современный Kubernetes (через CRI).
• Роль Docker: Инженеры Docker Inc. до сих пор остаются одними из главных контрибьюторов и мейнтейнеров containerd. То есть Docker развивает движок, который крутится на миллионах серверов под управлением Kubernetes по всему миру.
- Развитие технологий сборки образов — BuildKit
Docker создал BuildKit — современный, невероятно быстрый движок для сборки Docker-файлов (поддерживает параллельную сборку слоев, кэширование и мульти-архитектурные сборки).
• Связь с CNCF: Технологии BuildKit активно интегрируются в проекты CNCF. Например, проект Tekton (CI/CD инструмент в CNCF) или облачные системы сборки используют наработки BuildKit для компиляции безопасных контейнеров без необходимости запуска тяжелого Docker-демона (rootless builds).
- Безопасность цепочки поставок ПО (Software Supply Chain Security)
Проблема «отравленных» и уязвимых образов — одна из главных в облачной индустрии. Docker Inc. сотрудничает с CNCF над внедрением стандартов подписи и проверки контента:
• Notary (V2) и TUF: Docker совместно с CNCF развивает проект Notary (базирующийся на проекте The Update Framework / TUF из CNCF), который позволяет криптографически подписывать образы контейнеров.
• Генерация SBOM (Software Bill of Materials): Docker внедрил в свои утилиты стандарты генерации SBOM. Когда вы собираете контейнер, Docker автоматически создает манифест всех библиотек внутри, что напрямую сопряжено с инициативами CNCF по безопасности артефактов.
- Стандартизация облачной разработки — Cloud Buildpacks
Docker Inc. активно поддерживает проект CNCF Buildpacks (изначально созданный Heroku и Cloud Foundry).
• Эта технология позволяет компилировать исходный код приложения в готовый OCI-совместимый контейнер вообще без написания Dockerfile. Docker интегрирует поддержку Buildpacks в свои инструменты разработчика, упрощая создание стандартизированных облачных приложений.
Как разделены сферы влияния (Резюме)
| Сфера / Слой | За что отвечает CNCF/OCI | Что делает Docker Inc. |
|---|---|---|
| Стандарты (OCI) | Спецификация образов и среды запуска (runtime-spec). | Адаптирует свои инструменты под стандарты, гарантируя совместимость. |
| Инфраструктура (CNCF) | Оркестрация (Kubernetes), движки запуска (containerd). | Использует containerd внутри Docker Desktop, развивает код проекта. |
| Инструменты Разработчика | Популяризация подходов (Cloud Native Landscaping). | Создает UI/UX коммерческие продукты (Docker Desktop, Docker Dashboard). |
Простыми словами: CNCF отвечает за стандарты, безопасность и работу контейнеров под капотом огромных серверных кластеров (Data Centers), а Docker Inc. фокусируется на том, чтобы локальная разработка на компьютерах программистов оставалась удобной, быстрой и бесшовно интегрировалась в эти самые кластеры.
goo : which docker technologies still in use in k8s
Здесь кроется ключевое архитектурное заблуждение, с которым сталкиваются многие разработчики. Kubernetes не отказывался от containerd. Более того, containerd является абсолютным стандартом и дефолтным движком (Runtime) для большинства K8s-кластеров в мире (включая управляемые облака AWS EKS, Google GKE и Azure AKS).
Путаница возникает из-за того, что контейнерные движки делятся на два абсолютно разных уровня:
-
High-Level Runtime (Управляющий менеджер): Он скачивает образы из реестра, распаковывает слои OverlayFS и управляет сетью. Здесь правят containerd и CRI-O.
-
Low-Level Runtime (Исполнитель): Это крошечная утилита, которая берёт готовую папку, делает системные вызовы unshare, chroot, настраивает cgroups (ровно то, что вы делали вручную) и сразу завершает свою работу, оставляя процесс жить. Вот здесь и живут runc и упомянутый вами crun.
Они работают не вместо друг друга, а вместе (в связке).
Архитектурная матрешка Kubernetes
Когда вы деплоите Pod в Kubernetes, цепочка вызовов выглядит следующим образом:
```text
┌──────────┐ CRI (gRPC) ┌────────────────┐ OCI Spec ┌───────────────┐
│ kubelet │ ───────────────────> │ containerd │ ─────────────────> │ runc / crun │
└──────────┘ │ (High-Level) │ │ (Low-Level) │
└────────────────┘ └───────────────┘
│ │
Скачивает образ, Делает chroot,
выделяет IP-адрес namespaces, cgroups
- Kubelet (агент K8s на ноде) видит, что нужно запустить контейнер. Он отправляет запрос по протоколу CRI (Container Runtime Interface).
- containerd принимает этот запрос. Он идет в интернет, скачивает слои вашего образа, собирает их через OverlayFS в одну папку rootfs на диске и готовит конфигурационный файл config.json по стандарту OCI.
- Затем containerd вызывает Low-Level Runtime (например, runc или crun), передавая ему путь к этой папке и config.json.
- runc / crun за доли секунды «выпекает» контейнер в ядре Linux и мгновенно отключается. Контейнер продолжает работать сам по себе.
При чем здесь crun и почему о нем все говорят?
Исторически дефолтным исполнителем (Low-Level) для Docker и containerd всегда был runc (написанный на Go). Но сейчас в индустрии идет мощный сдвиг в сторону crun.
crun — это альтернатива runc, написанная чисто на языке C командой Red Hat. И вот почему он вытесняет runc на нижнем уровне:
• Феноменальная скорость и легкость: Поскольку runc написан на Go, внутри каждого запущенного контейнера «сидит» микро-оверхед самого рантайма Go. crun написан на си, он потребляет в разы меньше памяти и создает контейнеры значительно быстрее (измеряется в миллисекундах).
• Полноценная поддержка cgroups v2: crun изначально проектировался под современную вторую версию cgroups. К слову, в актуальных версиях Kubernetes (начиная с 1.35) поддержка старых cgroup v1 полностью удалена.
• Интеграция с WASM (WebAssembly): crun умеет из коробки запускать не только Linux-контейнеры, но и легковесные WASM-файлы без использования операционной системы внутри контейнера.
Что в итоге убрал Kubernetes?
Kubernetes полностью выбросил Docker Engine (компонент dockershim был удален в версии 1.24).
Раньше K8s приходилось делать цепочку: Kubelet -> Dockershim -> Docker API -> containerd -> runc. Это было громоздко. Теперь Kubernetes просто отрезал «лишнее» коммерческое лицо Docker с его утилитами сборки и обращается к containerd напрямую.
А вот внутри самого containerd системный администратор волен выбирать низкоуровневый движок: оставить классический runc или переключить одну строчку в конфиге на сверхбыстрый crun.
goo : pls, review recommendation i often give my students - replace docker with podman, the latter is compatible with former, but helps to migrate to kubernetes via kube manifests and some subset of orchestrator api. i.e. docker is deadend, while podman goes in right direction
Ваша рекомендация студентам абсолютно верна в своей технической сути, но формулировка «Docker — это тупик» (dead end) может быть излишне категоричной в 2026 году. Подобный радикализм полезен для того, чтобы встряхнуть студентов и заставить их отказаться от привычных догм, однако для будущих инженеров важно понимать тонкий баланс между локальной разработкой и продакшн-инфраструктурой.
Давайте разберем плюсы вашего подхода и добавим к нему важные архитектурные нюансы, которые помогут сделать вашу лекцию еще более глубокой.
Почему вы на 100% правы (Сильные стороны Podman)
Рекомендация переходить на Podman как на мост к Kubernetes — это отличный педагогический и практический прием. Вы даете им правильный вектор по следующим причинам:
- Концепция Подов (Pods):
Docker ничего не знает о «подах» — его минимальная единица это один контейнер. Podman изначально проектировался с пониманием архитектуры Kubernetes. Студенты могут запустить несколько контейнеров внутри одного пода локально, разделяя localhost и сетевое пространство точно так же, как это будет происходить в K8s.
- Прямая интеграция через Манифесты (podman kube):
Это главный убийца Docker в учебном процессе. Команды:
• podman kube generate — превращает запущенные локально контейнеры в чистокровный Kubernetes YAML.
• podman kube play — берет готовый манифест K8s и запускает его на локальном ПК без развертывания тяжелого локального кластера (вроде Minikube или Kind).
Это идеальный бесшовный мостик к оркестрации.
- удвоенная безопасность: Daemonless и Rootless
Docker исторически полагается на монолитный демон dockerd, работающий от имени root. Если демон упал — упали все контейнеры. Podman работает как обычная Linux-утилита (fork-exec модель). Он создает контейнеры как дочерние процессы текущего пользователя. Это приучает студентов к правильной модели безопасности с первого дня.
О чем важно предупредить студентов (Нюансы рынка)
Чтобы у студентов не возникло иллюзии, что Docker полностью стерт с лица земли, важно подсветить, где Docker все еще доминирует и почему он не совсем «тупик»:
-
Docker Desktop — это стандарт для macOS и Windows: Большинство студентов и разработчиков сидят не на чистом Linux, а на Mac или Windows. На этих ОС контейнеры запускаются внутри скрытой виртуальной машины Linux. Docker Desktop доведен в этом плане до идеала (файловый кэш VirtioFS, проброс портов, GUI, управление расширениями). У Podman есть Podman Desktop, но он исторически догоняет Docker по стабильности и удобству работы с виртуальными машинами (особенно на чипах Apple Silicon).
-
Экосистема локального тестирования (Testcontainers): В мире Java, Go, .NET безумно популярна библиотека Testcontainers (автоматический подъем баз данных в контейнерах во время прохождения интеграционных тестов). Она годами затачивалась под Docker socket. Поднять её на Podman можно, но это требует ручной настройки окружения и переменных (DOCKER_HOST), что иногда вызывает боль у новичков.
-
Docker ушел в сторону ИИ и внутренней изоляции (Sandboxes): Docker Inc. вовремя поняла, что проиграла войну за продакшн-сервера (где теперь безраздельно царят Kubernetes и containerd). Поэтому компания переключилась на локальную экосистему разработчиков и ИИ. Современный Docker — это инструменты сборки (BuildKit), оркестрация локальных сред (новые проекты Docker Sandboxes / sbx для безопасного запуска ИИ-агентов в изолированных микро-виртуальных машинах).
Сравнительный вердикт для лекции
Ваш совет можно визуализировать для студентов в виде следующей матрицы выбора:
| Критерий | Путь Docker | Путь Podman (Ваша рекомендация) |
|---|---|---|
| Конечная цель | Написать код, собрать образ, запустить приложение локально на ноутбуке. | Понять, как приложение будет жить в реальном Cloud Native продакшене. |
| Идеология | Минимализм: Один контейнер — один процесс. | Оркестрация: Группировка контейнеров в Поды (Pods). |
| Безопасность | Общий root-демон (потенциальная уязвимость). | Изолированные процессы пользователя (Rootless из коробки). |
| Переносимость | docker-compose.yml (проприетарный стандарт Docker). | Kubernetes YAML (мировой стандарт enterprise-инфраструктуры). |
Итог: Вы даете студентам великолепную долгосрочную инвестицию. Переход на Podman заставляет их сразу думать категориями Kubernetes (сетевые пространства пода, отсутствие root-прав, декларативные манифесты). Это превращает их из просто «разработчиков, умеющих запускать контейнер» в Cloud Native инженеров.
🚀 Шпаргалка: От Docker к Kubernetes через Podman, см. файл podman_to_k8s_cheatsheet.md
Эта памятка поможет вам переключить мышление с изолированных контейнеров (мировоззрение Docker) на концепцию оркестрации, управления подами и декларативных манифестов (мировоззрение Kubernetes).
1. Подменим имя (Алиасы и Совместимость)
Podman полностью совместим с CLI-командами Docker. Вы можете использовать привычный синтаксис.
- Быстрый переход для терминала:
alias docker=podmanПосле этого все команды вроде
docker run,docker ps,docker imagesбудут автоматически выполняться через Podman.
2. Главное отличие: Создание локального Пода (Pod)
В Docker контейнеры изолированы друг от друга и связываются через Docker Networks. В Podman (как и в Kubernetes) минимальной единицей является Pod — группа контейнеров, разделяющих один IP-адрес и пространство localhost.
Шаг А: Создаем пустой Под и пробрасываем в него порты
podman pod create --name my-learning-pod -p 8080:80
Шаг Б: Запускаем контейнеры внутри этого Пода
Теперь нам не нужно пробрасывать порты для каждого контейнера отдельно. Мы просто помещаем их внутрь пода с помощью флага --pod:
# 1. Запускаем веб-сервер Nginx в наш под
podman run -d --pod my-learning-pod --name web-server docker.io/library/nginx:alpine
# 2. Запускаем утилиту curl в том же поде, чтобы проверить связь через localhost
podman run --rm --pod my-learning-pod docker.io/library/curlimages/curl curl http://localhost:80
Контейнеры внутри одного пода видят друг друга через localhost, как процессы на одном компьютере.
3. Магия миграции: Генерация манифестов для Kubernetes (podman kube)
Вместо написания сложных YAML-файлов для Kubernetes вручную, вы можете спроектировать архитектуру приложения локально в Podman, а затем выгрузить её.
Конвертация запущенного Пода в Kubernetes YAML:
podman kube generate my-learning-pod > k8s-deployment.yaml
Что произойдет под капотом:
Podman создаст валидный, чистокровный манифест Kubernetes (типа Pod или Deployment), содержащий описание всех контейнеров, портов и переменных окружения, готовый к деплою в реальный кластер (Minikube, GKE, AWS EKS).
4. Обратная совместимость: Запуск манифестов Kubernetes локально
Если у вас уже есть готовый манифест Kubernetes, вам не нужно разворачивать тяжелый локальный кластер (Minikube / Kind), чтобы протестировать его. Podman умеет читать их «из коробки».
Запуск K8s-манифеста на локальном ПК:
podman kube play k8s-deployment.yaml
Удаление всего стека, описанного в манифесте:
podman kube down k8s-deployment.yaml
5. Таблица перевода концепций для студентов
| Задача | Как делали в Docker (Тупиковый путь) | Как делаем в Podman ➡️ Kubernetes (Правильный путь) |
|---|---|---|
| Управление процессами | Демон dockerd с правами root. |
Бездемонная модель (Daemonless), запуск от обычного пользователя (Rootless). |
| Связь между контейнерами | docker network create + имена контейнеров. |
Создание пода podman pod create + общее пространство localhost. |
| Локальный мульти-контейнер | docker-compose up (Файлы .yaml не подходят для продакшна K8s). |
podman kube play k8s-pod.yaml (Манифест на 100% совместим с продакшном). |
| Просмотр подов | Концепция отсутствует | podman pod ps |
| Посмотреть логи всего пода | Приходилось смотреть логи каждого контейнера отдельно. | podman pod logs my-learning-pod (Агрегирует логи всех контейнеров пода). |
💡 Педагогический совет для практической работы:
Дайте студентам задание:
- Развернуть связку из двух контейнеров (например, Frontend на Nginx + Backend на Python/Node) внутри одного пода через
podman pod create. - Сгенерировать файл
k8s-deployment.yamlс помощьюpodman kube generate. - Отредактировать полученный файл (например, изменить количество реплик) и запустить его заново через
podman kube play.
Самый первый вопрос, с которого началась беседа, оказался в самом конце. Google уже на втором вопросе вычислил что я русскоязычный, его первый ответ не стал переводить.
goo : let’s make container experiment - use linux namespaces, cgroups, chroot, but neither docker nor podman to create oci (open container initiative) image
Reference Guide: Building a Linux Container from Scratch
This reference architecture provides the foundational steps to create an isolated container using low-level Linux kernel primitives (namespaces, cgroups, and chroot) completely bypassing high-level engines like Docker or Podman.
Step-by-Step Implementation
Step 1: Prepare the Root Filesystem (chroot Preparation)
Before isolating processes, you need an isolated root directory containing essential system binaries. You can extract a minimal distribution like Alpine Linux or use debootstrap for Ubuntu/Debian.
# Create a dedicated working directory
mkdir -p ~/container-root/rootfs
cd ~/container-root
# Option A: Download and extract a minimal Alpine rootfs
wget https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-minirootfs-3.18.3-x86_64.tar.gz
tar -xf alpine-minirootfs-3.18.3-x86_64.tar.gz -C ./rootfs/
# Option B: Bootstrap an Ubuntu system (Debian/Ubuntu hosts)
# sudo debootstrap focal ./rootfs http://archive.ubuntu.com/ubuntu/
Step 2: Establish Resource Boundaries (cgroups v2)
Linux Control Groups (cgroups) handle resource accounting and limitation. Assuming a system running modern cgroups v2, you can restrict the memory and CPU usage of your container process manually by creating a sub-directory in the cgroupfs tree:
# Define your custom cgroup scope
sudo mkdir /sys/fs/cgroup/my-experimental-container
# Limit maximum memory to 500MB
echo "524288000" | sudo tee /sys/fs/cgroup/my-experimental-container/memory.max
# Limit CPU usage (e.g., max 20% of a single CPU core)
echo "20000 100000" | sudo tee /sys/fs/cgroup/my-experimental-container/cpu.max
Step 3: Instantiate Namespaces and Pivot Root (unshare & chroot)
The unshare utility lets you detach a process from host namespaces. You will spin up a new shell isolated across PID (processes), UTS (hostname), NET (networking), MOUNT (filesystems), and IPC (inter-process communication) boundaries.
Execute the following wrapper command as root:
sudo unshare --uts --pid --net --mount --ipc --fork \
chroot ./rootfs /bin/sh
Step 4: Finalize the Internal Container Environment
Now that you are inside the isolated container shell, you need to populate critical internal pseudofilesystems, assign the container’s PID to your cgroup, and give it an independent hostname.
Run these commands inside the chroot shell:
# 1. Mount the container-specific proc filesystem (isolates 'ps' and process tree)
mount -t proc proc /proc
# 2. Attach this shell's PID to your pre-configured cgroup boundary
# (From inside the namespace, this shell is PID 1, but we target its global PID via proc)
echo 1 > /sys/fs/cgroup/my-experimental-container/cgroup.procs 2>/dev/null || true
# 3. Assign an independent container hostname
hostname custom-container
# Verify your isolation
ps aux
hostname
Technical Comparison Matrix
| Dimension | Native Linux Experiment | High-Level Engine (Docker / Podman) |
|---|---|---|
| Image Standard | Hand-crafted tarball / raw directories | Content-addressable OCI layers & configuration manifests |
| Process Isolation | Manual unshare system calls |
Managed via containerd and runc |
| Storage Engine | Manual mounts or manual OverlayFS scripts |
Automated overlay2 storage drivers |
| Resource Constraints | Manual string injection into /sys/fs/cgroup/ |
CLI arguments flag abstraction (--cpus, -m) |
goo : i wonder - why we need overlayfs ?? we use builtin linux features and created a universal .tgz archive able to work on any linux, the simplest lxc implementation.
Вы затронули важный вопрос. Действительно, созданный вами .tgz архив — это полностью рабочий корневой образ (rootfs), готовый для запуска простейшего контейнера. Для базовых экспериментов этого более чем достаточно.
Однако, когда масштаб проекта увеличивается, одного архива становится мало. OverlayFS (или слоистая файловая система) нужна для решения трех критических проблем: скорости запуска, экосистемы памяти и сохранения неизменяемости (immutability).
Вот главные причины, почему в контейнеризации используют OverlayFS:
- Мгновенный запуск без копирования данных
Если у вас есть образ диска размером 1 ГБ, и вы хотите запустить 10 копий этого контейнера:
• Без OverlayFS: Вам придется физически скопировать этот 1 ГБ архив 10 раз (создав 10 разных папок). Это займет много времени и потратит ресурс вашего SSD.
• С OverlayFS: Вы монтируете одну и ту же базовую папку (Read-Only) 10 раз, создавая для каждой копии лишь крошечный пустой слой для записи (Read-Write). Запуск всех 10 контейнеров происходит мгновенно, так как физического копирования файлов не происходит.
- Колоссальная экономия места на диске
Поскольку базовая операционная система (например, ваш распакованный архив Alpine или Ubuntu) используется всеми контейнерами совместно, они не дублируют одни и те же системные файлы.
• Если 100 контейнеров используют один базовый образ, они будут делить эти данные между собой.
• Каждый контейнер тратит память диска только на те файлы, которые он сам изменил или создал в процессе работы.
- Гарантия чистой среды (Неизменяемость / Immutability)
OverlayFS разделяет файлы на два слоя:
- Нижний слой (LowerDir): Ваш базовый архив. Он монтируется в режиме «только для чтения». Контейнер физически не может его испортить или удалить из него файлы.
- Верхний слой (UpperDir): Слой изменений. Если процесс внутри контейнера попытается перезаписать системный файл (например, /etc/hosts), OverlayFS применит механизм Copy-on-Write (копирование при записи). Она скопирует этот файл в верхний слой и изменит его там. Когда контейнер завершает работу, вы можете просто удалить верхний слой (папку изменений), и ваш базовый образ останется идеально чистым, готовым к следующему запуску.
Архитектура OverlayFS «на пальцах»
Когда вы смотрите внутрь контейнера с OverlayFS, вы видите объединенное пространство (Merged), но на диске хоста это выглядит так:
┌─────────────────────────────────────────────────────────┐
│ Объединенный вид (Merged) │ <── То, что видит процесс
└─────────────────────────────────────────────────────────┘ внутри контейнера
│ │
▼ ▼
┌───────────────────────────┐ ┌───────────────────────────┐
│ Верхний слой (Upper) │ │ Нижний слой (Lower) │
│ Только новые/измененные │ │ Базовый rootfs из .tgz │ <── Общий для всех
│ файлы (Read-Write) │ │ (Read-Only) │ контейнеров
└───────────────────────────┘ └───────────────────────────┘
Как это сделать руками в вашем эксперименте?
Если вы захотите добавить OverlayFS в свой проект без Docker, это делается одной стандартной командой Linux перед вызовом chroot:
# Создаем структуру директорий
mkdir lower upper work merged
# Распаковываем ваш .tgz в lower (базовый слой)
tar -xf alpine-minirootfs.tar.gz -C ./lower
# Монтируем overlayfs в папку merged
sudo mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged
# Теперь запускаем контейнер, используя в качестве rootfs папку merged!
sudo unshare --uts --pid --net --mount --ipc --fork chroot ./merged /bin/sh
После выхода из контейнера папка lower останется абсолютно нетронутой, а все изменения вы найдете в папке upper.