Pull to refresh

Comments 36

А когда мы сможем отказать от docker в kubernetes и заменить его на podman?
Краткий ответ — никогда

Более развернутый ответ — для того чтобы использовать программу как container engine в kubernetes эта программа должна иметь отдельный сокет для работы по интерфейсу CRI. Чтобы управлять этим сокетом программа должна быть запущена как демон. Потому придется превратить podman обратно в демон, как docker.

Потому существует строгое разделение — podman для работы на пользовательских машинах (где демон только мешает и в большинстве случаев требует привелегий) и CRI-O — легковесный демон для работы с Kubernetes и специально заточенный под него. В итоге обе программы используют общий набор библиотек (libpod, containers/images) для работы.
Ну так через libpod и cri-o можно запускать поды на базе podman
Пока нет, они используют общий список имаджей, но фактически информацию о контейнерах хранят в разных местах (планируется объединить)
запрос на создания OCI-совместимой среды исполнения systemd-nspawn.

О чём идет речь, не могли бы вы пояснить? Слова все известные, но смысл ускользает.

Сейчас и docker и podman являются фактически обертками над runc, который собственно занимается созданием нужных неймспейсов. Разница в том, что в docker runc «впилен» в сам пакет докера, а в podman этот рантайм идет отдельно — и его можно заменять (к примеру, в Fedora 31 можно использовать crun).
Кроме того, общение с runc происходит по стандартному протоколу, который регулируется runtime spec. С недавних пор этот протокол поддерживает systemd-nspawn, а значит его можно использовать вместо run
docker engine уже давно отделен от containerd, а у containerd, в свою очередь, runc тоже рантайм, который можно заменить, на тот же runv (https://github.com/hyperhq/runv) или любой OCI совместимый.
Если под
впилен
имелось ввиду то, что, runc у докера идет в базе — то да, тут все верно

А, верно, я был уверен что привязать другой рантайм в докере труднее, а всё просто, спасибо

Что-то я его в новых убунтах не вижу. Оно RH-specific?

Тогда печально, потому что у докера один из сейлпоинтов — в универсальности. Улучшать докер для отдельного дистрибутива бесперспеткивно.

Первый аргумент зачем очень странный. Какая нужда запускать сервисы в общем контейнере?

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


Когда контейнеры используются разработчиком — то же самое, скачать образ со всем необходимым dev-окружением намного проще, чем скачать три образа и настроить их связи.

И после таких статей и советов приходит к тебе подрядчик вот с таким решением, когда в одном контейнере упаковано все, а у тебя кубер. И совершенно непонятно, как это запускать без переделки: ни логов нормально не собрать, ни масштабировать невозможно. А подрядчик переделывать не хочет, он ведь разработчик, ему так удобнее и его совершенно не интересует, как это потом должно в эксплуатации работать.

А вы что заказывали-то? Коробочное решение или что-то, что вы сможете масштабировать?


Если первое — то сами и виноваты. Если второе — ну так пропишите в договоре-то в какой форме вы решение принимать будете.

Стандартная ситуация, когда заказывает начальство, а мы (эксплуатация) видим только конечный результат, на который повлиять уже не можем, но должны отвечать за бесперебойную работу сервиса под любой нагрузкой.
а не взламывая свою собственную init-службу.

Извините, это перевод? Что подразумевалось? Или имелось в виду — hacking как "разрабатываю свою init-систему"?

Если контейнеры надо запускать при загрузке системы, то можно просто вставить соответствующие команды Podman в юнит-файл systemd, тот запустит сервис и будет его мониторить. Podman использует стандартную модель ветвления при исполнении (fork-exec). Иначе говоря, контейнерные процессы являются дочерними по отношению к процессу Podman’а, поэтому systemd легко может их мониторить.

Docker использует модель клиент-сервер, и CLI-команды Docker тоже можно размещать прямо в юнит-файле. Однако после того, как Docker-клиент подключается к Docker-демону, он (клиент) становится просто еще одним процессом, обрабатывающим stdin и stdout. В свою очередь, systemd понятия не имеет о связи между Docker-клиентом и контейнером, который работает под управлением Docker-демона, и поэтому в рамках этой модели systemd принципиально не может мониторить сервис.


Каким образом нужно запускать Podman контейнер, чтобы его процессы были видны в systemctl status?

Например, предложенный в официальной документации способ запуска приводит к тому, что systemd видит только сам процесс, запустивший контейнер, а именно "/usr/bin/podman start -a NAME". Точно так же ведёт себя Docker, если его запустить с ключом "-a". Как же systemd может мониторить процессы контейнера, если не видит их?

а зачем? Я проверил — systemd не мониторит, мониторит conmon


root     26061  4.6  0.3 1418228 54512 ?       Ssl  11:58   0:00 /usr/bin/podman start -a redis_server
root     26140  0.0  0.0  78012  1892 ?        Ssl  11:58   0:00 /usr/bin/conmon --api-version 1 -s -c 6e88c46f8c452e058c1bcfda8a77a9e1c36243d24a3149f16e5db1a7cba2f2a8 -u 6e88c46f8c452e058c1b
999      26153  6.6  0.0  40700  4552 ?        Ssl  11:58   0:00  \_ redis-server *:6379

проблема когда ты пытаешься одновременно управлять И системд, И подманом — там реально чего-то не то происходит.
Разница с докером именно в том, что докер стартанул, плюнул запрос в АПИ и клиент умер. Тут же подман бежит ровно столько, сколько нужно — пока сервис живет.

В статье написано, что systemd может мониторить процессы контейнера. Мой вопрос, не о том, зачем это в принципе нужно, а о том, как именно этого добиться.

Если под мониторингом подразумевается, что systemd видит процесс «podman start -a», который запускает контейнер, то это ничем не отличается от docker, процесс которого не завершается и systemd его видит, если запустить «docker start -a».

Не совсем понятно какую задачу хотите решить.
Ведь нужно не просто мониторить дерево процессов (хотя conmon с этим худо-бедно вроде справляется), а еще смотреть на хелсчеки контейнера — и как они интегрируются с systemd — открытый вопрос (пока не проверял, но есть подозрение, что пока никак).
Про forking — вижу, сами догадались.

Задача — выяснить технические детали реализации в Podman. Более развёрнуто ответил ниже.
systemd видит только сам процесс, запустивший контейнер, а именно "/usr/bin/podman start -a NAME". Точно так же ведёт себя Docker, если его запустить с ключом "-a".

На первый взгляд — да, но самим контейнером управляет докер-демон — настраивает ему cgroup и другое. docker start -a здесь только команда демону запустить контейнер.


В случае podman будет создан новый slice, который непосредственно управляет контейнером. Если его остановить то остановится сам контейнер.

Возможно, нашел правильный ответ в документации github.com/containers/libpod/blob/master/docs/podman-generate-systemd.1.md

Вся магия в Type=forking и PIDFile=xxx.
[Service]
...
ExecStart=/usr/bin/podman start de1e3223b1b888bc02d0962dd6cb5855eb00734061013ffdd3479d225abacdc6
Type=forking
PIDFile=/run/user/1000/overlay-containers/de1e3223b1b888bc02d0962dd6cb5855eb00734061013ffdd3479d225abacdc6/userdata/conmon.pid
...


В данном примере podman запускается без параметра "-a", то есть сам процесс, запустивший контейнер, завершается и systemd видит дерево процессов самого контейнера.

К сожалению, проверить не удалось, так как текущая версия conmon из CentOS 7.7 не создаёт PID файл. Но в любом случае, теперь картинка сложилась.

Кстати, для docker есть wrapper, который позволяет добиться того же результата, но другим способом, через манипуляции с cgroups контейнера github.com/ibuildthecloud/systemd-docker

Тут дело даже не в pid-файлах, а в дереве процессов. В случае podman systemd всегда знает запущен контейнер или остановлен. В случае docker systemd знает только запущен или остановлен клиент, а про контейнер не знает ничего.

Только что проверил. Если запускать podman systemd unit через "/usr/bin/podman start -a NAME" и docker systemd unit через "/usr/bin/docker start -a NAME", то в результате будет одинаковое поведение systemd сервиса.

Да, «под капотом» Podman и Docker контейнеры запустятся совершенно по разному, но с точки зрения systemd, сервис — это один процесс, который подключен к STDIN, STDOUT и STDERR дескрипторам процесса контейнера. Если podman или docker контейнер завершается с ошибкой, то systemd сервис так же завершится с ошибкой. Если podman или docker контейнер завершается успешно, то systemd сервис так же завершится успешно. В этом смысле поведение systemd сервиса одинаковое.

При использовании github.com/containers/libpod/blob/master/docs/podman-generate-systemd.1.md в случае Podman или github.com/ibuildthecloud/systemd-docker в случае Docker, systemd сервисом будет не один процесс, инициировавший запуск контейнера, а всё дерево процессов самого контейнера.

Для чего это нужно — вопрос отдельный. Мне были интересны технические детали реализации в Podman. Как мы выяснили, там это реализовано через создание процессом conmon PID файла, из которого systemd сам узнаёт PID контейнера и дерево процессов контейнера.

А в каких именно сценариях поведение оказалось одинаковое? Меня вот интересуют вот эти:


  1. Запустите сервис-контейнер, прибейте демон докера (dockerd кажется, но могу ошибаться), после чего попробуйте определить статус сервиса-контейнера через sysctl.


  2. Запустите сервис-контейнер, прибейте демон докера, после чего остановите сервис-контейнер через sysctl. Когда демон докера запустится снова, в каком состоянии сервис-контейнер окажется?


  3. Просто прибейте процесс docker и дождитесь пока systemd попытается его перезапустить.



А если во всех этих случаях поведение окажется одинаковым — предлагаю рассмотреть как будет работать зависимость сервисов друг от друга при падении демона докера, во всех вариантах (контейнер зависит от контейнера, контейнер зависит от простого демона, простой демон зависит от контейнера).

Запустите сервис-контейнер, прибейте демон докера (dockerd кажется, но могу ошибаться), после чего попробуйте определить статус сервиса-контейнера через sysctl.

Можете включить опцию в конфиге демона, которая не убивает контейнеры при смерти docker демона. Но опция достаточно стремная.


--live-restore                          Enable live restore of docker when containers are still running

https://docs.docker.com/engine/reference/commandline/dockerd/
https://docs.docker.com/config/containers/live-restore/
или я неправильно понял ее?


sysctl

небольшое замечание. Не sysctl, а systemctl


предлагаю рассмотреть как будет работать зависимость сервисов друг от друга при падении демона докера, во всех вариантах

Никак. Потому что ее на уровне докер-демона нет. Он стартует все пачкой, если стоит restart: always или unless-stopped

Можете включить опцию в конфиге демона, которая не убивает контейнеры при смерти docker демона. Но опция достаточно стремная.

Да нет, без неё поведение docker как раз больше похоже на поведение podman в видимой systemd части.


Никак. Потому что ее на уровне докер-демона нет. Он стартует все пачкой, если стоит restart: always или unless-stopped

Она есть на уровне systemd, и отслеживать зависимости — его прямая обязанность. Вот как раз использовать restart: always или unless-stopped в таких сценариях нельзя никак.

systemd в состоянии отслеживать, что контейнер готов, а не просто запущен, но без танцов с бубном?


Она есть на уровне systemd, и отслеживать зависимости — его прямая обязанность. Вот как раз использовать restart: always или unless-stopped в таких сценариях нельзя никак.

да, я просто уточняю.


Пока самый внятный способ интеграции docker & systemd — это либо через systemd-docker, либо ручками, но с run --rm, чтобы в случае сбоя контейнер удалился (может быть опасно для данных, но главное компоуз в системди не пихать).

systemd в состоянии отслеживать, что контейнер готов, а не просто запущен, но без танцов с бубном?

Да, если контейнер обучен кидать sd_notify. И как раз именно эта часть и работает только в podman.

Я про докер вообще-то говорил. Но ценность подмана именно а том, чтобы ничего не переделывать — вот есть хелсчек, этого должно быть достаточно. Никто не будет писать обработчик sd_notify в контейнере. Это же все опять переделывать на новый лад (((

На opensuse создает


linux-x1:~ # ls /var/run/containers/storage/btrfs-containers/
6e88c46f8c452e058c1bcfda8a77a9e1c36243d24a3149f16e5db1a7cba2f2a8  b2c87cf4ebb2a2e09ea6de6487360598da76f85f82a61d5f2c497733b6784d0b

linux-x1:~ # zypper if conmon

Retrieving repository 'openSUSE-Tumbleweed-Source' metadata .............................................................................................................................[done]
Building repository 'openSUSE-Tumbleweed-Source' cache ..................................................................................................................................[done]
Loading repository data...
Reading installed packages...

Information for package conmon:
-------------------------------
Repository     : openSUSE-Tumbleweed-Oss         
Name           : conmon                          
Version        : 2.0.1-1.1                       
Arch           : x86_64                          
Vendor         : openSUSE                        
Installed Size : 72.6 KiB                        
Installed      : Yes (automatically)             
Status         : up-to-date                      
Source package : conmon-2.0.1-1.1.src            
Summary        : An OCI container runtime monitor
Description    :                                 
    Conmon is a monitoring program and communication tool between a
    container manager (like podman or CRI-O) and an OCI runtime (like
    runc or crun) for a single container.
Мало что понял, честно говоря.
Раньше было чёткое разделение на системный контейнер и контейнер приложения. Docker был для контейнеров приложения, LXC/LXD/systemd-machined — для системных контейнеров.
Теперь, получается, можно запускать системные контейнеры через Podman, из Dockerfile, но при этом они несовместимы с Docker? И зачем такое нужно?

Ну, что значит несовместимы?
Есть формат образов, разработанный докером и отданный сообществу — OCI. Он поддерживается разными средами выполнения. По сути — это запакованная файловая система. Можно начать с того, что попросту там может оказаться бинарник не от Вашей платформы (не x86, а arm). Ну, да — может оказаться, что там внутри systemd, который с докером не очень дружит. И что? Сам стандарт не говорит о том, что там внутри. Я уж не говорю про то, что я натыкался на ситуации, когда образ докера не мог быть запущен докером (как правило — собранный более свежей версией типа 18.** на версиях времен мамонта из центоси).


Теперь, получается, можно запускать системные контейнеры через Podman, из Dockerfile, но при этом они несовместимы с Docker?

Учитывая, что podman/buildah предлагают альтернативный подход к сборке… То Ваши Докерфайлы никто не трогает )))


Я себе вижу две стороны медали.


  1. действительно увеличивается фрагментация образов — есть такие, есть сякие, есть третьи. И со всем этим придется разбираться.
  2. РедХат хочет свой блекджэк — им не дают покоя лавры Убунту (именно они продвигают lxc/lxd) и Докера (здесь все понятно). Нужно свое решение.
  3. Разработчикам действительно проще писать systemd юнит файл и запускать его везде одинаково. Тем более, если целевым вариантом поставки решения является не только докер. Как пример продуктов, которые могут быть запущены по-разному — gitlab, postgres, nginx и пр.
Sign up to leave a comment.