Постараемся ответить на эти вопросы и рассказать, как безболезненно мигрировать с Docker на Podman.
Как работает Docker
Начнем с того, что проясним, как работает Docker, чтобы понять, почему появились Podman и Buildah. Как вы знаете, Docker-команды работают только тогда, когда запущен демон-процесс Docker. Идея с демоном, похоже, была в том, чтобы собрать в одном месте все крутые вещи, которые делает Docker, а заодно организовать полезные API для работы с ним на будущее. Как показано на рисунке ниже, демон Docker содержит в себе весь функционал, необходимый для выполнения следующих задач:
- Pull- и push-операции при работе с реестром образов;
- Создание копий образов в локальном хранилище контейнеров и добавление слоев (layers) в эти контейнеры;
- Фиксация изменений (commit) в контейнерах и удаление контейнерных образов из локального репозитория на хосте;
- Запрос к ядру ОС на запуск контейнера в соответствующем пространстве имен, cgroup, и т. д.
В сущности, Docker-демон берет на себя всю работу с реестрами, образами, контейнерами и ядром. А вы просто говорите ему, что делать через интерфейс командной строки (CLI).
Мы здесь не будем взвешивать плюсы и минусы такого подхода, когда все собрано в одном демон-процессе. В его пользу можно привести множество аргументов, и во времена появления Docker он вполне имел смысл. Однако по мере активного использования Docker к нему стали возникать вопросы, например, такие:
- Единственный процесс означает единственную точку отказа;
- Демон-процессу принадлежат все дочерние процессы (запущенные контейнеры);
- При вылете демона дочерние процессы остаются сиротами;
- Сборка контейнеров имеет дыры в безопасности;
- Для выполнения любых операций Docker пользователю (ям) нужны полные права root.
Были и другие претензии. С этим можно не соглашаться или говорить, что эти недостатки уже устранены, но мы не собираемся спорить. Разработчики Podman считают, что им удалось решить многие из этих проблем, и если вы хотите воспользоваться преимуществами Podman, то эта статья для вас.
Суть Podman в том, чтобы взаимодействовать с реестром образов, с контейнерами и хранилищем образов, а также с ядром Linux не через демона, а напрямую через процесс runC, который отвечает за запуск контейнеров.
Теперь, когда мы частично выяснили мотивы разработчиков Podman, пора обсудить, что переход на Podman означает для пользователя. И здесь надо усвоить и прояснять (мы сделаем это ниже) следующее:
- Podman заменяет собой Docker. При этом запускать какой-то демон-процесс, наподобие демона Docker, больше не нужно;
- Знакомые вам Docker-команды точно так же работают и в Podman;
- Podman хранит контейнеры и образы не в том же месте, что и Docker;
- Образы Podman и Docker совместимы;
- В Kubernetes-средах Podman способен на большее, чем Docker;
- А также мы разберем, что такое Buildah и зачем он нужен.
Установка Podman
Если вы используете Docker, вы можете удалить его, когда решите сделать свитч. Тем не менее, вы можете оставить Docker, пока будете пробовать Podman. Есть несколько полезных уроков и отличное демо, которые, возможно, полезно прочитать и посмотреть для начала, чтобы вы могли лучше понять процесс перехода. Один пример в демонстрации требует Docker, чтобы показать совместимость.
Для установки Podman на Red Hat Enterprise Linux 7.6 или более поздней версии используйте следующее; если вы используете Fedora, то замените yum на dnf:
# yum -y install podman
В Podman используются те же команды, что и в Docker
Podman создавался так, чтобы на него было легко перейти с Docker. Поэтому все знакомые вам по Docker команды точно так же работают и в Podman. Более того, утверждается, что сценарии с вызовом Docker должны нормально работать, если создать соответствующий синоним (alias), вот так: alias docker=podman – просто попробуйте. Конечно, перед этим надо остановить Docker (systemctl stop docker). Кроме того, можно поставить пакет podman-docker, который сделает за вас все необходимые преобразования. Он просто кладет в /usr/bin/docker скрипт, который запускает Podman с теми же аргументами, что используются в Docker.
Привычные по Docker команды, типа pull, push, build, run, commit, tag, и т. д. – все они есть и в Podman. Подробнее см. руководство по Podman. Важное отличие в том, в Podman у некоторых команд появились добавляющие удобства флаги, например, флаги --all (-a) для команд podman rm и podman rmi, которые многие найдут весьма полезными.
Кроме того, Podman можно запускать от имени обычного пользователя, без прав root. Правда, пока это работает только в Fedora и с Podman 1.0, а в RHEL должно появиться начиная с версий 7.7 и 8.1. Это стало возможным благодаря усовершенствованиям в защите userspace. Запуск от имени обычного пользователя означает, что по умолчанию Podman хранит образы и контейнеры в домашнем каталоге пользователя, подробнее мы рассмотрим это в следующем разделе. Узнать больше о том, как запускать Podman без root-прав, можно из статьи Дэна Уолша (Dan Walsh) How does rootless Podman work?.
Podman и контейнерные образы
Когда вы в первый введете команду podman images, то скорее всего будете обескуражены, так как не увидите ни одного Docker-образа, которые уже были загружены на компьютер ранее. Дело в том, локальный репозиторий Podman располагается в папке /var/lib/containers, а не в каталоге /var/lib/docker. Это сделано не просто так, а в рамках новой структуры хранения, отвечающей стандартам OCI (Open Containers Initiative).
В 2015 году Docker, Red Hat, CoreOS, SUSE, Google и другие тренд-сеттеры в области Linux- контейнеров создали Open Container Initiative, независимый орган для управления спецификациями стандартов на формат контейнерных образов и среду их исполнения. В рамках OCI на GitHub были созданы проекты containers/image и containers/storage.
Поскольку Podman может запускаться без root-прав, ему требуется отдельное место для записи образов. Поэтому репозиторий Podman расположен в домашнем каталоге пользователя ~/.local/share/containers. Это помогает избежать ситуации, когда в /var/lib/containers могут писать все подряд, и в отношении других, опасных с точки зрения безопасности практик. Кроме того, теперь у каждого пользователя есть свой, отдельный набор контейнеров, так что на хосте могут спокойно работать сразу несколько пользователей одновременно. Закончив работу, пользователи могут выполнить push-отправку в общий реестр, чтобы сделать свои образы доступными остальным.
При переходе с Docker на Podman знание новых путей расположения контейнеров пригодится при отладке, а также когда вы захотите очистить локальный репозиторий командой rm -rf /var/lib/containers, чтобы начать все заново. Впрочем, перейдя на Podman, вы, скорее всего, начнете использовать вместо этой команды новую опцию -all для команд podman rm и podman rmi.
Совместимость контейнерных образом между Podman и другими средами исполнения
Несмотря на различное расположение локальных репозиториев, и Docker, и Podman создают контейнерные образы, совместимые со стандартом OCI. Podman может в обе стороны (push и pull) использовать популярные реестры контейнеров, такие как Quay.io или Docker Hub, а также частные реестры. Например, с помощью Podman можно скачать и запустить последний образ Fedora из Docker Hub. Если не указывать реестр, Podman по умолчанию выполняет поиск в реестрах, перечисленные в файле registries.conf., придерживаясь указанного в этом файле порядка. Изначально, первым в этом файле указан реестр Docker Hub.
$ podman pull fedora:latest
$ podman run -it fedora bash
Образы, которые были загружены в реестр с помощью Docker, можно скачивать и запускать с помощью Podman. Например, если мы с помощью Docker создали образ myfedora и загрузили его в свой репозиторий Quay.io (ipbabble), то затем его можно скачать с помощью Podman, вот как:
$ podman pull quay.io/ipbabble/myfedora:latest
$ podman run -it myfedora bash
Podman позволяет легко и изящно перемещать образы между каталогами /var/lib/docker и /var/lib/containers с помощью команд push и pull, например:
$ podman push myfedora docker-daemon:myfedora:latest
Понятно, что, если в этом примере опустить docker-daemon, то push-отправка пойдет в Docker Hub. Если же указать quay.io/myquayid/myfedora, то образ будет загружен в реестр Quay.io (здесь myquayid – это имя нашей учетной записи на Quay.io):
$ podman push myfedora quay.io/myquayid/myfedora:latest
Если вы решите, что готовы отказаться от Docker, то для его удаления просто завершите работу демона, а затем удалите пакет Docker с помощью менеджера пакетов. Но перед этим обязательно убедитесь, что загрузили во внешний (не локальный) реестр все нужные вам образы, созданные с помощью Docker, чтобы потом их можно было оттуда скачать. Либо вы можете с помощью Podman скачать их из локального репозитория Docker в локальный же OCI-репозиторий Podman. Например, в RHEL перенос образа fedora делается вот так:
# systemctl stop docker
# podman pull docker-daemon:fedora:latest
# yum -y remove docker # optional
Podman упрощает переход на Kubernetes
Podman предлагает целый ряд дополнительных – по сравнению с Docker – функций, которые пригодятся разработчикам и ИТ-операторам при работе с Kubernetes, в частности, полезные команды, которых просто нет Docker. Если вы знакомы с Docker и рассматриваете переход на Kubernetes/OpenShift в качестве контейнерной платформы, то Podman придется очень кстати.
Podman может сгенерировать YAML-файл Kubernetes на базе работающего контейнера с помощью команды podman generate kube. А при отладке запущенных pod’ов помимо стандартных команд для работы с контейнерами можно также использовать команду podman pod. Подробнее о том, как Podman помогает перейти на Kubernetes, можно узнать из статьи Брента Боде (Brent Baude) Podman can now ease the transition to Kubernetes and CRI-O.
Buildah – что это и зачем
Buildah появился раньше, чем Podman. И это иногда обескураживает пользователей Docker: «Чего это апологеты Podman вдруг заговорили про Buildah? Podman что, не умеет выполнять сборку?».
Спешим успокоить, Podman умеет, и делает это точно так же, как Docker. То есть, сборку можно выполнять либо с помощью Dockerfile и команды podman build, либо можно запустить контейнер, внести необходимые изменения и затем зафиксировать их (выполнить commit), создав новый тег в контейнерном образе. В нашей трактовке Buildah – это расширенный набор команд для создания и управления контейнерными образами, и поэтому он обеспечивает гораздо более тонкий контроль при работе с образами. Podman’овская команда build частично содержит в себе функционал Buildah и использует для сборки тот же программный код, что и сам Buildah.
Самый эффективный способ использовать Buildah – это писать сценарии Bash для создания образов, примерно так же, как вы пишете для Dockerfile.
Что касается хронологии появления Buildah и Podman, то события происходили примерно следующим образом. Когда Kubernetes научился работать с CRI-O, созданной на основе стандарта OCI для сред исполнения контейнеров, Docker-демон стал не нужен. То есть, больше не надо было устанавливать Docker на все узлы Kubernetes-кластера, чтобы запускать в нем pod’ы и контейнеры. Kubernetes теперь может вызывать CRI-O, а та – уже напрямую RunC, которая, в свою очередь, запускает контейнерные процессы. Однако, если мы при этом хотим использовать один и тот же кластер Kubernetes не только для запуска, но и для сборки контейнеров (как, например, в OpenShift), то нам понадобится новый инструмент для сборки, который бы не зависел от Docker-демона и, как следствие, не требовал бы установки Docker. Кроме того, такой инструмент, созданный на базе проектов containers/storage и containers/image, устранил бы риски безопасности, связанные с открытым сокетом Docker-демона при сборке, а эти риски беспокоят многих пользователей Docker.
И таким новым инструментом стал Buildah (название читается как «билда» и пародирует бостонской акцент руководителя этого проекта Дэна Уолша (Dan Walsh) при произношении слова «builder»). Дополнительные сведения о Buildah можно найти на сайте buildah.io, а также в блогах и руководствах по ссылкам в конце этой статьи.
Есть еще пара деталей, которые надо усвоить, если вы хотите использовать Buildah:
- Он обеспечивает более точный контроль при создании слоев образа (image layers). В частности, позволяет сделать то, чего давно хотели многие пользователи контейнеров –зафиксировать (commit) сразу множество изменений с помощью всего одного слоя.
- Buildah’вский run и Podman’овский run – это разные вещи. Поскольку Buildah предназначен для сборки образов, его команда run, по сути, аналогична команде RUN в Dockerfile. Уильям Генри, один из разработчиков Buildah, вспоминает, как возникло это решение: «Я как-то ныл, что какой-то порт или mount работает совсем не так, как я ожидал. Дэн Уолш (@rhatdan) все взвесил и сказал, что Buildah вообще не должен работать с контейнерами подобным образом. Все, больше никаких сопоставлений портов и никакого монтирования томов. Убираем эти флаги и вместо них используем buildah run для запуска команд, которые нужны при сборке контейнерных образов, например, так: buildah run dnf -y install nginx».
- Buildah может создавать образы с нуля (scratch-образы). То есть образы, в которых ничего нет, буквально. Действительно, если посмотреть в хранилище контейнеров, созданное в результате выполнения команды buildah from scratch, то там будет пустой каталог. Это весьма полезно с точки зрения создания суперлегковесных образов, содержащих только те пакеты, которые необходимы для запуска приложения.
Зачем нужна сборка с нуля? Давайте сравним девелоперский образ Java-приложения с его же образом для продакшн-среды или для среды-симулятора (staging environment). На этапе разработки в образе могут присутствовать компилятор Java, Maven и другие инструменты, необходимые разработчику. Но при переводе в продакшн в образе должны остаться только Java runtime и ваши пакеты. И, кстати, чтобы убрать лишнее, вовсе не нужен менеджер пакетов, наподобие DNF/YUM, и даже Bash не понадобится – все можно сделать через CLI-интерфейс Buildah, как показано на рисунок ниже, где слева находится традиционный многослойный контейнер, а справа однослойный scratch-образ. Подробнее см. Building a Buildah Container Image for Kubernetes и Buildah introduction demo.
Возвращаясь к хронологии. Итак, Kubernetes научился работать с CRI-O и runC, а для сборки мы сваяли Buildah – все, от Docker на Kubernetes-хосте можно отказываться? Нет, еще остается отладка. Как решать проблемы с контейнерами, если на хосте нет соответствующих инструментов? Не ставить же на него Docker, иначе мы опять возвращаемся к демону и все усилия были зря. И тут на сцену выходит Podman.
То есть Podman решает сразу две проблемы. Во-первых, он позволяет ИТ-операторам инспектировать контейнеры и образы с помощью хорошо знакомых команд. А во-вторых, он дает эти же инструменты разработчикам. В результате, все пользователи Docker – и разработчики, и операторы – могут перейти на Podman и спокойно выполнять те задачи, для которых они раньше использовали Docker, а также решать еще целый ряд новых задач.
Нужные ресурсы:
- Сайт проектов Podman.io и Buildah.io.
- Проекты на github.com/containers (подключайтесь, изучайте исходники и следите за тем, находится в разработке:
- libpod (Podman);
- buildah;
- image (код для работы с контейнерными образами OCI);
- storage (код локального хранилища образов контейнеров).
Полезные ссылки:
- Containers without daemons: Podman and Buildah available in RHEL 7.6 and RHEL 8 Beta
- Podman: Managing pods and containers in a local container runtime
- Managing containerized system services with Podman (Управление контейнерами podman с использованием systemd)
- Building a Buildah Container Image for Kubernetes
- Podman can now ease the transition to Kubernetes and CRI-O
- Security Considerations for Container Runtimes (Видеозапись выступления Дэна Уолша на KubeCon 2018)
- IoT edge development and deployment with containers through OpenShift: Part 1 (Сборка и тестирование контейнеров ARM64 на платформе OpenShift с использованием sing podman, qemu, binfmt_misc и Ansible)
Комментарии (29)
Nikobraz
12.09.2019 13:59Podman предлагает целый ряд дополнительных – по сравнению с Docker – функций
А подробнее? Есть ли хоть одна веская причина сменить докер на подман? Я не увиделphozzy
12.09.2019 18:32Вот хорошая серия статей на эту тему:
- https://mkdev.me/en/posts/dockerless-part-1-which-tools-to-replace-docker-with-and-why
- https://mkdev.me/en/posts/dockerless-part-2-how-to-build-container-image-for-rails-application-without-docker-and-dockerfile
- https://mkdev.me/en/posts/dockerless-part-3-moving-development-environment-to-containers-with-podman
mkpankov
13.09.2019 10:50Ну справедливости ради в первой статье тоже дурацкие причины.
"Увидеть альтернативы", "разобраться в контейнерах" и "подготовиться к будущему" это причины поковырять технологию в свободное время, а не переходить в продакшене.
Непонятно почему они не приводят как причину увеличение безопасности — контр-меру от выхода из контейнера и получение рута на хосте, т.к. демон под рутом.
alexbers
13.09.2019 09:41Rootless режим. Полезен в hpc-кластерах, чтобы пользователи могли использовать контейнеры для воспроизведения результатов вычислительных экспериментов. Правда, чтобы добавить поддержку MPI пришлось написать скрипт https://github.com/alexbers/mpiexec-docker.
VasikAlexey
12.09.2019 15:14Или не особенно знаком с терминологией, или обычно ИТ-оператор соответсвует первому уровню хелпдеска?
mkpankov
13.09.2019 10:47Они подразумевают под этим Operations, тех кто эксплуатирует систему после завершения разработки.
phozzy
12.09.2019 18:27Контейнер с
buildah
собирает контейнер сbuildah
, чтобы собрать контейнер сbuildah
,…
https://gitlab.com/containertools/containertools
VolCh
13.09.2019 06:02А насколько обычно отстают они в плане синтаксиса Dockerfile? Поддерживается ли экспериментальный синтаксис типа проброса ssh и монтирования кэшей? Чем отличается их scratch от стандартного 'FROM scratch'?
gecube
13.09.2019 14:04Как будто вышеперечисленный синтаксис сильно необходим. Здорово, что докер шагает вперёд. Но в принципе — все необходимое для работы с образами уже есть. Не хватает только зрелого тулинга, чтобы собирать контейнеры без докера.
VolCh
13.09.2019 15:50Ну, прокидывание ssh-тоннеля в билдер бывает очень для установки зависимостей из приватного репозитория пакетов или git репозитория. Кєширование каталогов менеджера пакетов (хоть системных типа atp, хоть платформенных типа composer или npm) может кардинально уменьшить время билда.
gecube
13.09.2019 16:23Есть ответ простой — собирай докеры так, чтобы это было ненужно. Тот же гит можно скачать СНАРУЖИ докера, положить в каталог контекста, да и тупо секурнее это.
В общем — пускай кэшированием занимается не докер, причем непонятно как, а внешняя система сборки.VolCh
13.09.2019 17:40Вот как раз от внешней системы сборки хочется избавиться, чтобы тупо сделать
git clone repo app docker build -t app docker run app
и чтобы это было эффективно
gecube
13.09.2019 19:25Это утопия. Идеалистичные мысли. Очень вредные.
Как минимум тем, что у тебя лок на системе сборке как докер. А если тебе нужно собирать попросту apk/deb/rpm или нативные бинари?
С другой стороны, инкапсуляция сборочного конвейера в отдельные докер-контейнеры — очень мощный механизм, но работает это так:
docker run -e USER=$(id -u) -e GROUP=$(id -g) --rm -v $PWD:/in -v $PWD/out:/out my_super_puper_compiler
и в в текущем каталоге в подкаталоге /out получаешь артефакты сборки.
Которые при необходимости можно передать в следующий докер для мутации.
Мы так голанг собирали. Самая малость — что нужно побороть проблемы с правами на файлы
Т.е. еще раз переформулирую — использовать сборочный конвейер в виде мультистейдж докерфайла на этапе docker build разработчик отрубает себе обе руки — и потому что окончательным артефактом может быть ТОЛЬКО докер-контейнер, и потому что он лишает себя кучи плюшек (типа кэширования файлов в самом каталоге проекта).
VolCh
13.09.2019 19:39Ну почему утопия, если работает? Вот если объявят эксперимент неудачным надо будет думать.
И особо не страшен лок на докере как билдере, если билдим артефакты для докера.
Ну и проблемы с правами внутри контейнеров мне лично встречались или по невнимательности, или по неверным предположениям о том, как права настроены в базовом образе. Из последнего на этой неделе как раз официальный golang образ, который без плясок не хотел качать пакеты под непривилегированным пользователем. Предыдущий раз — зимой.
gecube
14.09.2019 18:35Ну и проблемы с правами внутри контейнеров мне лично встречались или по невнимательности, или по неверным предположениям о том, как права настроены в базовом образе. Из последнего на этой неделе как раз официальный golang образ, который без плясок не хотел качать пакеты под непривилегированным пользователем. Предыдущий раз — зимой.
Ага, конечно. Речь скорее не про права ВНУТРИ контейнеры, хотя этот фактор тоже имеет место, а скорее то, что докер при прокидывании с хоста каталогов ставит им владельца root с идущими от этого последствиями. Это все можно пофиксить с кровью, но придется все используемые образы перепиливать и оборачивать запуск контейнеров в шелл-скрипты, которые делают все "как надо"
mkpankov
13.09.2019 21:05Вы сейчас описали практически как vagga работает — только без демонов и командной строки из 5 опций на пустом месте ;)
sandello
13.09.2019 08:43Что с docker-compose?
mkpankov
13.09.2019 10:45В этой статье пишут, что его нет
gecube
13.09.2019 14:04А компоуз и не нужен. Используйте… Ансибл.
mkpankov
13.09.2019 15:02Одного для одного другое для другого.
Вы ансиблом супервайзите сервисы в продакшене?gecube
13.09.2019 16:24Погодите — что значит ансибл супервайзит?
Почему Вы думаете, что компоуз супервайзит? Если компоуз всего лишь обертка к докер-апи (т.е. убирает необходимость самому вводить docker volume create, docker run и пр.).
Если мы рассматриваем именно вопрос ЗАПУСКА и доставки контейнеров, то ансибл на голову выше компоуза. Я неоднократно писал почему так, но если нужно — могу повториться.
Я уж не говорю, что зачастую в проде докер не нужен....
mkpankov
13.09.2019 10:38С т.з. adoption хорошо что они совместимы с докером. С другой стороны, в той же vagga есть супер-полезные вещи, которых в мейнстрим-контейнерах нет и видимо ещё долго не будет:
- Авто-версионирование и очистка старых образов/контейнеров. Заниматься этой уборкой в докере абсолютно осточертело.
- Прокидывание прокси с хоста — зачем в докере эти пляски с такой тривиальной вещью, абсолютно непонятно.
- В vagga сборка идёт серьёзно быстрее за счёт некоторых трюков, например libeatmydata.
- Командно-ориентированный процесс вместо контейнеро-ориентированного. Контейнеры стартуют за миллисекунды. В конфиге описываются команды, а контейнеры под них поднимаются/опускаются автоматически.
nrcmn
На 7.7 (Maipo) podman (podman-0.12.1.2-2.git9551f6b.el7.x86_64) не хочет менять GraphRoot для non root пользователя с ~.local/share/containers/storage на что-то другое, если менять storage.conf и libpod.conf. Это как-то лечится?