![](https://webcf.waybackmachine.org/web/20220803153251/https://habrastorage.org/webt/4u/g2/x1/4ug2x1dot8v9zwvl27e_vmcffb8.jpeg)
Расширять традиционные практики администрирования Linux с помощью контейнеров — естественный путь развития. Podman без проблем интегрируется в Linux, но поддержка systemd — краеугольный камень этой интеграции. Команда VK Cloud Solutions перевела статью о том, как она работает.
Использование systemd и контейнеров
В Linux система systemd init часто используется для управления локальными службами: веб-серверами, сетевыми демонами и всеми их взаимозависимостями.
Есть два распространенных сценария совместного использования systemd и контейнеров:
Запуск systemd внутри контейнера. Как объясняет Дэн Уолш, сделать это с помощью Podman максимально просто: он автоматически настраивает в контейнере несколько mounts, и все — systemd готов к работе. Хотя это относительно незаметная функция Podman, ее появление стало огромным шагом вперед для запуска контейнеризированных рабочих нагрузок.
Раньше другие контейнерные инструменты не поддерживали systemd. Пользователям приходилось писать свои init-скрипты, а это возможный источник ошибок и дополнительная нагрузка на службы поддержки поставщиков ПО. Podman решает все эти проблемы. С помощью systemd можно устанавливать и запускать приложения в контейнерах, как и с помощью других инструментов. А поставщикам ПО не нужно разбираться с init-скриптами, «вышедшими из-под пера» пользователей.
Использование systemd для запуска и работы контейнеризированных приложений. systemd запускает контейнеризированное приложение и управляет им на протяжении его жизненного цикла. C Podman это делается проще с помощью команды
podman generate systemd
, которая генерирует юнит-файл systemd для конкретного контейнера или пода. Такое генерирование поддерживается в Podman начиная с версии 1.7. Со временем наша команда доработала функцию и создала юнит-файлы systemd, которые могут работать на других машинах, наподобие использования Kubernetes YAML или файла Compose. Тесная интеграция с systemd положила начало автообновлениям и простым откатам, реализованным начиная с версии Podman 3.4.Хотя в блогах можно найти множество статей о генерировании юнитов systemd для контейнеров, практически ничего не написано об их генерировании для подов. Но прежде чем углубиться в детали хочу напомнить, что такое под.
Что такое под
Под состоит из нескольких частей, и, думаю, Брент Боде лучше всех все объяснил на рисунке ниже:
![](https://webcf.waybackmachine.org/web/20220803153251/https://habrastorage.org/webt/v0/v3/yh/v0v3yhwmq_z7e9lylronjc6lc_s.png)
Под состоит из одного или более контейнеров. У группы есть общие контрольные группы (cgroups) и конкретные пространства имен, такие как пространство PID, сети и IPC. Благодаря общим cgroups для всех контейнеров действуют одни и те же ограничения ресурсов. Общие пространства имен упрощают коммуникацию контейнеров друг с другом, например, через localhost или взаимодействие процессов.
Есть и специальный infra-контейнер. Его основная задача — держать открытыми конкретные ресурсы, связанные с подом, например, порты, пространства имен или cgroups. Infra-контейнер — это верхнеуровневый контейнер пода, он создается раньше других контейнеров и уничтожается последним. Infra-контейнер используют при генерировании юнитов systemd для пода, так что не забывайте: этот контейнер работает на протяжении всей жизни пода. Это также означает, что без infra-контейнера (такого как
--infra=false
) нельзя генерировать юниты systemd для подов.И еще один немаловажный момент: для каждого контейнера выполняется по одному процессу
conmon
— это сокращение от container monitor, что точно выражает главную функцию этого процесса. Он также пересылает логи и выполняет чистку после завершения работы контейнера. Процесс conmon запускается до контейнера и дает среде его исполнения (например, runc
или crun
) указание создать и запустить контейнер. Его работу можно завершить с помощью кода завершения контейнера, что позволяет использовать его как основной процесс службы systemd.Генерирование юнитов systemd для пода
Podman генерирует только один системный юнит для контейнера. После установки для запуска, остановки и проверки службы можно использовать
systemctl
. Основной PID каждого юнита — это процесс conmon контейнера. Таким образом, systemd может читать код завершения работы контейнера и действовать в соответствии с настроенной политикой перезапуска. Узнать больше о юнитах можно из статей Запуск контейнеров в Podman и службы systemd в общем доступе и Улучшения systemd в Podman 2.0.Генерирование юнитов для пода очень похоже на запуск контейнера. У каждого контейнера в поде есть выделенный юнит systemd, а каждый юнит зависит от основного юнита systemd пода. Можно и дальше использовать
systemctl
для запуска, остановки и проверки основной службы пода; systemd возьмет на себя (пере)запуск и остановку служб контейнеров вместе с основной службой.В этом примере создается под с двумя контейнерами и генерируются юнит-файлы для пода, которые потом устанавливаются для текущего пользователя:
$ podman pod create --name=my-pod
635bcc5bb5aa0a45af4c2f5a508ebd6a02b93e69324197a06d02a12873b6d1f7
$ podman create --pod=my-pod --name=container-a -t centos top
c04be9c4ac1c93473499571f3c2ad74deb3e0c14f4f00e89c7be3643368daf0e
$ podman create --pod=my-pod --name=container-b -t centos top
b42314b2deff99f5877e76058ac315b97cfb8dc40ed02f9b1b87f21a0cf2fbff
$ cd $HOME/.config/systemd/user
$ podman generate systemd --new --files --name my-pod
/home/vrothberg/.config/systemd/user/pod-my-pod.service
/home/vrothberg/.config/systemd/user/container-container-b.service
/home/vrothberg/.config/systemd/user/container-container-a.service
Как и ожидалось, Podman создал три файла
.service
, по одному для каждого контейнера плюс один верхнеуровневый для пода. В приложении в конце статьи приведено содержание юнит-файлов целиком. Юниты, генерируемые для двух контейнеров, выглядят как стандартные юниты контейнеров плюс следующие зависимости systemd:BindsTo=pod-my-pod.service
: юнит контейнера «привязан» к юниту пода. Если остановить юнит пода, этот юнит тоже остановится.
After=pod-my-pod.service
: юнит контейнера запускается после юнита пода.
Если юниту контейнера не удается запуститься, то из-за зависимостей основной службы пода основной юнит основного пода тоже этого не сможет.
Это все, что нужно знать о генерировании юнитов systemd для подов в Podman.
Перезагрузив systemd через
systemctl --user daemon-reload
, можно запускать и останавливать pod.service
на свое усмотрение. Взгляните:# Reload the daemon
$ systemctl --user daemon-reload
# Start the pod service and make sure the service is running
$ systemctl --user start pod-my-pod.service
$ systemctl --user is-active pod-my-pod.service
active
# Make sure the pod and its containers are running
$ podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
6dd1090d4ca6 my-pod Running 2 minutes ago 85f760a5cfe5 3
user $ podman container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85f760a5cfe5 localhost/podman-pause:4.0.2-1646319369 5 minutes ago Up 5 minutes ago 6dd1090d4ca6-infra
44a7e60b9563 quay.io/centos/centos:latest top 5 minutes ago Up 5 minutes ago container-b
31f24bdff747 quay.io/centos/centos:latest top 5 minutes ago Up 5 minutes ago container-a
Отлично, все работает как надо. Можно использовать
systemctl
для запуска служб — Podman выводит список подов и их служб корректно. Заодно покажу вам, как останавливать службу пода:# Stop the pod service
$ systemctl --user stop pod-my-pod.service
# Make sure the pod and its containers are removed
$ podman pod ps -q
$ podman container ps -q
# Make sure the services are inactive
$ systemctl --user is-active pod-my-pod.service container-container-a.service container-container-b.service
inactive
inactive
inactive
качать
Podman генерирует юниты systemd для подов так же, как и для контейнеров. Зависимости между этими юнитами работают таким образом, что вам нужно взаимодействовать только с основным юнитом пода, а systemd будет запускать и останавливать юниты контейнеров.
Приложение
Podman генерирует следующие юнит-файлы для пода и двух контейнеров.
pod-my-pod.service
Description=Podman pod-my-pod.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=
Requires=container-container-a.service container-container-b.service
Before=container-container-a.service container-container-b.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/pod-my-pod.pid %t/pod-my-pod.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-my-pod.pid --pod-id-file %t/pod-my-pod.pod-id --name=my-pod --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-my-pod.pod-id
ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-my-pod.pod-id -t 10
ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-my-pod.pod-id
PIDFile=%t/pod-my-pod.pid
Type=forking
[Install]
WantedBy=default.target
container-container-a.service
[Unit]
Description=Podman container-container-a.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers
BindsTo=pod-my-pod.service
After=pod-my-pod.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --pod-id-file %t/pod-my-pod.pod-id --sdnotify=conmon -d --replace --name=container-a -t centos top
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all
[Install]
WantedBy=default.target
container-container-b.service
[Unit]
Description=Podman container-container-b.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers
BindsTo=pod-my-pod.service
After=pod-my-pod.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --pod-id-file %t/pod-my-pod.pod-id --sdnotify=conmon -d --replace --name=container-b -t centos top
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all
[Install]
WantedBy=default.target
Kubernetes aaS от VK Cloud Solutions можно попробовать бесплатно. Мы начисляем пользователям при регистрации 3 000 бонусных рублей и будем рады, если вы попробуете сервис и дадите обратную связь.
Что почитать по теме: