↓ Перейти к основному содержимому
  1. Posts/
  2. Podman/

Quadlet и Podlet в Podman - как перестать писать длинные podman run и завести контейнеры под systemd

··1801 слово·9 минут· loading · loading · ·
Stilicho2011
Автор
Stilicho2011
Пишу о homelab, self-hosting, автоматизации и open-source решениях
Оглавление
Podman - This article is part of a series.
Part : This Article

Quadlet и Podlet в Podman
#

Контейнеры без Kubernetes и Docker Compose
#

Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).

Когда я только переезжал с Docker Compose на Podman, у меня в голове была небольшая путаница с двумя очень похожими по звучанию терминами - Quadlet и Podlet. Звучат почти одинаково, оба связаны с контейнерами, оба всплывают в одном контексте - и первое время я, чего греха таить, путал их местами. Разница на деле принципиальная: Quadlet - это встроенный в Podman формат описания контейнеров через systemd, а Podlet - отдельная утилита, которая помогает эти описания генерировать, а не писать руками с нуля. В этой статье разберу оба инструмента подробно, покажу примеры конфигураций и сравню такой подход с привычным Docker Compose.

Если вы еще не читали общий обзор самого Podman, лучше начать с него - там подробнее про daemonless-архитектуру, rootless-режим и общую логику проекта: Podman - современная альтернатива Docker.


1. Quadlet
#

Что такое Quadlet
#

Quadlet - это встроенный в Podman механизм, позволяющий описывать контейнеры, поды, сети, volume’ы и образы декларативно, обычными systemd unit-файлами специального формата. При старте системы systemd сам транслирует такие файлы в полноценные .service-юниты и запускает их через Podman - ничего генерировать вручную не требуется, достаточно daemon-reload.

Quadlet появился как развитие идеи podman generate systemd, только вместо императивного “сгенерируй юнит из уже запущенного контейнера” здесь все наоборот - вы декларативно описываете желаемое состояние, а systemd приводит систему к этому состоянию сам, в том числе после перезагрузки хоста. Сам podman generate systemd при этом официально объявлен устаревшим: его не удаляют, но развивать больше не будут, и документация прямо отправляет всех к Quadlet.

Типы Quadlet-файлов
#

РасширениеЧто описывает
.containerотдельный контейнер
.podпод - группу контейнеров с общей сетью
.volumeименованный volume
.networkсеть
.imageобраз, который нужно заранее подтянуть
.buildсборку образа из Containerfile
.kubeразвертывание из Kubernetes YAML (podman kube play)
.artifactOCI-артефакт

Где размещаются Quadlet-файлы
#

  • /etc/containers/systemd/ - системные (root) юниты;
  • ~/.config/containers/systemd/ - пользовательские, rootless-юниты.

Пример .container-файла
#

[Container]
Image=docker.io/library/nginx:latest
ContainerName=nginx
PublishPort=8080:80
Volume=nginx-data:/usr/share/nginx/html:Z

[Service]
Restart=always

[Install]
WantedBy=multi-user.target

Пример .pod-файла
#

Если нужно объединить несколько контейнеров в один под с общей сетью, для этого есть отдельный тип юнита .pod:

# web-pod.pod
[Pod]
PublishPort=8080:80

А сами контейнеры затем подключаются к этому поду через ссылку на .pod-файл:

# web-app.container
[Container]
Image=myapp:latest
Pod=web-pod.pod

[Service]
Restart=always
# web-cache.container
[Container]
Image=docker.io/library/redis:latest
Pod=web-pod.pod

[Service]
Restart=always

Все контейнеры, привязанные к одному поду, разделяют общий сетевой namespace и видят друг друга через localhost - точно так же, как если бы под создавался вручную командой podman pod create.

Управление Quadlet-юнитами
#

Здесь есть деталь, на которой спотыкаются почти все (и я в том числе): из файла nginx.container systemd генерирует юнит с именем nginx.service, и все команды работают именно с ним, а не с исходным файлом:

systemctl daemon-reload
systemctl start nginx.service
systemctl status nginx.service
journalctl -u nginx.service -f

И вторая деталь: привычный systemctl enable здесь не сработает. Сгенерированные юниты systemd считает временными, поэтому автозапуск при загрузке включается только секцией [Install] в самом .container-файле - генератор Quadlet сам применяет ее при каждом daemon-reload, по сути делая за вас то, что обычно делает enable.

С этого момента контейнер - полноценный systemd-сервис: автозапуск при загрузке через [Install], управление зависимостями через After=/Requires=, единый журнал через journalctl, штатный Restart= вместо самодельных скриптов-обвязок.

Rootless-юниты - три отличия
#

Если файл лежит в ~/.config/containers/systemd/, то есть сервис rootless, нужно помнить три вещи:

  • все команды выполняются с ключом --user: systemctl --user daemon-reload, systemctl --user start nginx.service, journalctl --user -u nginx.service;
  • в секции [Install] указывается WantedBy=default.target, а не multi-user.target - у пользовательского экземпляра systemd своя цель загрузки;
  • без “linger” пользовательский systemd запускается только тогда, когда вы залогинились, и останавливается вместе со всеми вашими контейнерами, когда вы вышли из последней сессии. Чтобы rootless-сервисы стартовали при загрузке хоста и жили независимо от SSH-сессий, это нужно один раз включить:
sudo loginctl enable-linger $USER

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

Команда podman quadlet
#

В свежих версиях Podman появился отдельный набор команд для работы с Quadlet, чтобы не раскладывать файлы по директориям руками:

podman quadlet install nginx.container   # положить файл в нужную директорию
podman quadlet list                      # какие Quadlet-юниты есть и в каком они состоянии
podman quadlet rm nginx.container        # удалить юнит

Это удобно, но не обязательно: Quadlet по-прежнему отлично работает и с файлами, которые вы положили в каталог сами.

Автообновление контейнеров
#

Отдельная приятная возможность, которую почему-то редко упоминают: Quadlet умеет автоматически обновлять контейнеры. Достаточно добавить в секцию [Container] одну строку:

[Container]
Image=docker.io/library/nginx:latest
AutoUpdate=registry

и включить штатный таймер (для rootless-сервисов - с тем же ключом --user):

systemctl enable --now podman-auto-update.timer

По умолчанию таймер срабатывает раз в сутки, в полночь: проверяет, не появилась ли в реестре новая версия образа с тем же тегом, и если появилась - скачивает ее и перезапускает сервис. А если после обновления сервис не смог запуститься, Podman откатывает его на предыдущий образ. Важное условие: имя образа должно быть указано полностью, вместе с реестром (docker.io/library/nginx:latest, а не просто nginx:latest), иначе Podman не поймет, где проверять обновления. Это не замена осознанному обновлению по версиям, но для сервисов на плавающих тегах вроде :latest или :stable - очень удобная штука. Если же вы предпочитаете обновлять все руками, но хотите знать, когда выходят новые версии, - посмотрите на Diun.

Преимущества Quadlet
#

  • нативная интеграция с systemd - никаких обходных путей и самодельных обвязок;
  • автозапуск и восстановление после сбоя штатными средствами systemd;
  • управление зависимостями между сервисами (например, “запускать после того, как поднялась сеть”);
  • единое централизованное логирование через journalctl;
  • полная поддержка rootless-режима.

Ограничения Quadlet
#

  • требует systemd - на системах без него (некоторые embedded-дистрибутивы, часть Alpine-окружений) не работает;
  • рассчитан на один хост - никакой кластеризации;
  • не заменяет Kubernetes, если вам действительно нужны autoscaling, service discovery на несколько узлов и HA.

2. Podlet
#

Что такое Podlet
#

Podlet - это отдельная утилита на Rust, которая не входит в состав самого Podman, но плотно с ним используется. Задача Podlet простая и полезная: избавить вас от необходимости писать Quadlet-секции руками, если под рукой уже есть рабочая команда podman run/docker run или файл docker-compose.yml.

Важно: Podlet не создает контейнеры и не является рантаймом - он только генерирует текст готового Quadlet-файла, который затем нужно сохранить в нужную директорию и подхватить через systemctl daemon-reload.

Генерация из команды
#

Самый простой сценарий - взять существующую команду запуска и просто заменить podman run/docker run на podlet podman run:

podlet podman run -d -p 8080:80 -v nginx-data:/usr/share/nginx/html:Z --name nginx nginx:latest

На выходе - готовый .container-файл со всеми нужными секциями [Container], [Service], [Install], который остается сохранить в ~/.config/containers/systemd/ или /etc/containers/systemd/.

Генерация из docker-compose.yml
#

Это, пожалуй, самый практически полезный режим при миграции с Docker Compose:

podlet compose docker-compose.yml

По умолчанию Podlet создаст по отдельному .container-файлу на каждый сервис. Если хочется, чтобы связанные сервисы жили в одном поде с общей сетью, это нужно попросить явно флагом --pod - тогда Podlet сгенерирует .pod-файл и привяжет к нему все .container-файлы. Есть и третий вариант, --kube, - на выходе получится .kube-файл и Kubernetes YAML, если вы заодно присматриваетесь к кластеру:

podlet compose --pod docker-compose.yml

Генерация из уже работающего объекта
#

Если контейнер, под, сеть или volume уже созданы вручную и работают, Podlet может “снять” с них Quadlet-конфигурацию:

podlet generate container nginx

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

Зачем нужен Podlet на практике
#

  • резко упрощает миграцию с Docker и Docker Compose - не нужно вручную разбираться в синтаксисе всех секций Quadlet;
  • снижает число ошибок при ручном написании unit-файлов (забытый [Install], неверная секция Volume= и подобное);
  • ускоряет сам процесс перехода - для типового проекта результат Podlet чаще всего нужно только слегка донастроить, а не писать с нуля.

3. Quadlet и Podlet вместе
#

Проще всего запомнить разницу так: Quadlet - это формат, который выполняется, а Podlet - это инструмент, который его пишет за вас. Они не конкурируют и не заменяют друг друга - это разные слои одного и того же процесса.

Docker Compose / podman run
        │
        ▼
     Podlet   ← генерирует Quadlet-файлы
        │
        ▼
    Quadlet   ← декларативный формат
        │
        ▼
     systemd  ← превращает Quadlet в .service и запускает
        │
        ▼
     Podman   ← реально запускает контейнеры/поды

На практике типичный рабочий процесс выглядит так: берете существующий docker-compose.yml, прогоняете его через podlet compose (с --pod, если сервисам нужна общая сеть), получаете набор .container/.pod-файлов, кладете их в ~/.config/containers/systemd/, делаете systemctl --user daemon-reload - и с этого момента все живет как обычные systemd-сервисы. Только не забудьте про loginctl enable-linger, иначе после перезагрузки “обычные systemd-сервисы” будут ждать, пока вы залогинитесь.


4. Сравнение с Docker Compose
#

КритерийDocker ComposeQuadlet (+ Podlet)
Требует демонДаНет
RootlessОграниченноПо умолчанию
Автозапуск при старте системыЧерез restart-политику (restart: always), которую исполняет сам dockerd после своего запускаНативно, через systemd [Install]
Интеграция с systemdОтсутствуетПолная
Централизованные логиЧерез docker compose logsЧерез journalctl, вместе со всеми остальными сервисами системы
Формат конфигурацииYAML (docker-compose.yml)INI-подобные systemd-юниты
Один хостДаДа

Отдельно стоит понимать: Quadlet - это не прямая замена Docker Compose один в один, а скорее иной подход к тому же результату - вместо одного YAML-файла, который парсит отдельный инструмент (docker compose/podman-compose), вы получаете набор systemd-юнитов, которые распознает сама операционная система. Для тех, кто и так привык управлять сервисами через systemctl, это выглядит естественнее, чем держать в системе параллельный слой оркестрации compose-файлов.


5. Практические сценарии
#

Homelab. Nextcloud, медиасерверы (Jellyfin, Plex), reverse proxy (Traefik, Caddy, nginx), мониторинг (Prometheus, Grafana) - типичный набор self-hosted сервисов, которые прекрасно живут как Quadlet-юниты и переживают перезагрузку хоста без дополнительных скриптов.

VPS / выделенный сервер. Веб-приложения, приватные API, раннеры CI/CD - там, где нужен один надежный хост без затрат на поддержку кластера.

Edge / IoT. Минимальное потребление ресурсов, rootless-режим по умолчанию и простое сопровождение особенно ценны на слабом железе.


6. Когда Quadlet - не то, что нужно
#

Если вам требуется:

  • горизонтальное автомасштабирование под нагрузкой;

  • HA-кластер из нескольких физических узлов;

  • multi-region deployment с распределением нагрузки между дата-центрами,

  • значит, вы уже выросли из задач одного хоста, и здесь нужен полноценный Kubernetes. Quadlet отлично закрывает потребности single-node инфраструктуры, но сознательно не пытается конкурировать с оркестрацией на уровне кластера.


7. Итог
#

  • Quadlet - декларативный формат, который превращает контейнеры, поды, сети и volume’ы Podman в обычные systemd-сервисы.
  • Podlet - инструмент, который генерирует Quadlet-файлы из podman run, docker-compose.yml или уже работающих объектов, экономя время на ручном написании синтаксиса.
  • Вместе они дают безопасную, минималистичную single-node платформу без демона и без Kubernetes - для большинства self-hosted сценариев этого более чем достаточно.

Docker Compose - привычно, Podman - безопасно, Quadlet - декларативно и по-systemd’овски, Podlet - экономит время на переходе, Kubernetes - когда одного хоста уже мало. Выбор конкретного инструмента должен определяться реальной задачей, а не модой. А о том, с какими подводными камнями придется столкнуться на этом пути, я отдельно написал в статье Podman - обратная сторона медали.


Полезные ссылки:

Podman - This article is part of a series.
Part : This Article

Related

Docker vs Podman vs Kubernetes - подробное сравнение контейнерных технологий

··1452 слов·7 минут· loading · loading
Сравниваем Docker, Podman и Kubernetes: архитектура, безопасность, накладные расходы и реальные сценарии применения - от homelab до production-кластеров.

Podman - современная альтернатива Docker

··2376 слов·12 минут· loading · loading
Podman - контейнерный движок без демона, ориентированный на безопасность и rootless-режим. Разбираем историю проекта, архитектуру, отличия от Docker, поды, Quadlet и Podlet - и когда есть смысл переходить.

Podman - обратная сторона медали, о каких недостатках стоит знать заранее

··2528 слов·12 минут· loading · loading
Разбираем реальные ограничения Podman: сеть и порты в rootless-режиме, неполная совместимость с Docker Compose, виртуальная машина на macOS/Windows вместо демона, отсутствие оркестрации на несколько хостов, менее зрелая экосистема и более высокий порог входа для новичков.