Поиск по сайту:

Как запустить контейнеры Podman под Systemd с помощью Quadlet


Quadlet — это бесплатный инструмент с открытым исходным кодом, написанный на C, который позволяет нам создавать и запускать контейнеры Podman под Systemd. Этот инструмент позволяет нам объявлять контейнеры, тома, сети и их отношения, используя специальные модули Systemd.

В этом руководстве мы узнаем, как использовать Quadlet для создания контейнеров, сетей и томов Podman, а также как создавать стеки из нескольких контейнеров.

В этом уроке вы узнаете:

  • Как создавать контейнеры, тома и сети с соответствующими модулями Systemd
  • Как создать стеки из нескольких контейнеров с помощью Quadlet

Базовый пример: создание контейнера MariaDB.

В этом первом базовом примере мы определяем модуль для сервера базы данных MariaDB. Вот как это выглядит:

[Unit]
Description=MariaDB container

[Container]
Image=docker.io/mariadb:latest
Environment=MYSQL_ROOT_PASSWORD=rootpassword
Environment=MYSQL_USER=testuser
Environment=MYSQL_PASSWORD=testpassword
Environment=MYSQL_DATABASE=testdb

[Install]
WantedBy=multi-user.target

С помощью этих нескольких строк мы определили контейнер на основе последнего официального образа MariaDB, доступного на Dockerhub. Как видите, «.container» — это специальный тип модуля Systemd. Уникальной особенностью этого типа юнитов является раздел «Контейнер», в котором мы можем указать параметры, эквивалентные тем, которые мы можем передать в командную строку Podman. Единственная обязательная опция в разделе «Контейнер» — это Image, чтобы указать базовое изображение для контейнера.

Если мы хотим, чтобы контейнер запускался от имени пользователя root, мы сохраняем файл в каталоге /etc/containers/systemd; чтобы запустить его от имени нашего непривилегированного пользователя, вместо этого мы сохраняем его в ~/.config/containers/systemd. В этом примере мы будем использовать последний подход и сохраним наш модуль «.container» как ~/.config/containers/systemd/mariadb-service.container. Чтобы позволить systemd сгенерировать сервис на основе контейнера, мы запускаем следующую команду:

$ systemctl --user daemon-reload

После запуска команды мы можем просмотреть сгенерированный сервис, запустив:

$ systemctl --user cat mariadb-service

Чтобы запустить контейнер, как и любой другой сервис, мы можем запустить:

$ systemctl --user start mariadb-service

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

$ podman ps

Команда возвращает следующий вывод, который подтверждает, что контейнер запущен и работает:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
151226b10a1c docker.io/library/mariadb:latest mariadbd 59 seconds ago Up About a minute systemd-mariadb-service

Как вы, возможно, заметили, по умолчанию контейнер назван в честь юнит-файла «.container» плюс префикс «systemd-» (в данном случае systemd-mariadb-service). Однако, чтобы явно присвоить имя контейнеру, мы можем передать его как значение опции ContainerName внутри раздела «[Container]».

Создание единицы «объема»

Мы используем тома для сохранения данных контейнеров. В этом случае мы хотим, чтобы данные нашей базы данных сохранялись, даже если мы удалим контейнер systemd-mariadb-service. Мы определяем именованный том в соответствующем модуле «.volume». В приведенном ниже примере мы предоставляем только описание тома. Параметры, специфичные для тома, можно указать в разделе [Volume]:

[Unit]
Description=MariaDB Volume

[Volume]

Мы сохраняем модуль как ~/.config/containers/systemd/mariadb-volume.volume. Чтобы указать контейнеру MariaDB использовать том, мы используем параметр Volume внутри раздела [Container] модуля «.container» и сопоставляем том с Каталог /var/lib/mysql внутри контейнера:

[Unit]
Description=MariaDB container

[Container]
Image=docker.io/mariadb:latest
Environment=MYSQL_ROOT_PASSWORD=rootpassword
Environment=MYSQL_USER=testuser
Environment=MYSQL_PASSWORD=testpassword
Environment=MYSQL_DATABASE=testdb
Volume=mariadb-volume.volume:/var/lib/mysql

[Install]
WantedBy=multi-user.target

Когда мы используем именованный том, Systemd автоматически назначает ему зависимость в сервисном модуле, который он генерирует для нашего контейнера. Чтобы позволить systemd повторно сгенерировать необходимые службы, мы снова используем команду daemon-reload. Как только мы (пере)запустим контейнер MariaDB, том будет создан автоматически, в чем мы можем убедиться с помощью утилиты командной строки podman:

$ podman volume ls

Как и ожидалось, наш том появился в списке, сгенерированном командой:

DRIVER        VOLUME NAME
local         systemd-mariadb-volume

Мы также можем убедиться, что том смонтирован в /var/lib/mysql внутри контейнера, используя команду podman Inspect, передав имя контейнера в качестве аргумента и просмотрев «Монтирование». раздел:

$ podman inspect systemd-mariadb-service

Вот соответствующий раздел вывода:

"Mounts": [
     {
         "Type": "volume",
         "Name": "systemd-mariadb-volume",
         "Source": "/home/doc/.local/share/containers/storage/volumes/systemd-mariadb-volume/_data",
         "Destination": "/var/lib/mysql",
         "Driver": "local",
         "Mode": "",
         "Options": [
              "nosuid",
              "nodev",
              "rbind"
         ],
         "RW": true,
         "Propagation": "rprivate"
     }
],

Использование привязок

Что, если мы хотим использовать привязку вместо именованных томов? Привязка-монтирование полезно во время разработки, поскольку позволяет нам монтировать хост-файлы внутри контейнера. Недостатком использования привязки является то, что контейнеры становятся зависимыми от файловой системы хоста. Чтобы использовать привязку внутри модуля «.container», мы просто указываем относительный или абсолютный путь к хост-файлу, который мы хотим смонтировать. Предположим, например, что мы хотим смонтировать каталог /var/lib/mysql внутри контейнера с каталогом ~/mysql на хосте. Вот что мы могли бы написать в модуле «.container»:

[Unit]
Description=MariaDB container

[Container]
Image=docker.io/mariadb:latest
Environment=MYSQL_ROOT_PASSWORD=rootpassword
Environment=MYSQL_USER=testuser
Environment=MYSQL_PASSWORD=testpassword
Environment=MYSQL_DATABASE=testdb
Volume=%h/mysql:/var/lib/mysql

[Install]
WantedBy=multi-user.target

В приведенном выше примере вы можете заметить, что мы использовали заполнитель %h, который Systemd автоматически расширяет до абсолютного пути к нашему собственному каталогу HOME. Также возможно использовать относительные пути, которые разрешаются относительно позиции файла модуля.

Создание сетей

Чтобы создать стек, состоящий из нескольких контейнеров, аналогично тому, что мы делаем с docker-compose, мы должны поместить контейнеры в одну сеть, чтобы они могли взаимодействовать друг с другом. Чтобы создать сеть с помощью Quadlet, мы можем использовать устройства с расширением «.network».

Как и в случае с контейнерами и томами, по умолчанию сети именуются по имени файла модуля, в котором они определены, плюс префикс «systemd-». Мы можем явно указать имя или любой другой параметр, специфичный для сети, в разделе [Network] файла. В приведенном ниже примере мы указываем подсеть и адрес шлюза для сети (это эквивалент запуска podman с --subnet 192.168.30.0/24 и --gateway 192.168.30.1). параметры):

[Unit]
Description=MariaDB Network

[Network]
Subnet=192.168.30.0/24
Gateway=192.168.30.1

Мы сохраняем файл как ~/.config/containers/systemd/mariadb.network. Чтобы «поместить» контейнер в определенную сеть, мы используем параметр Network внутри раздела «Контейнер» его контейнерного модуля. Контейнер MariaDB, который мы определили ранее, становится:

[Unit]
Description=MariaDB container

[Container]
Image=docker.io/mariadb:latest
Environment=MYSQL_ROOT_PASSWORD=rootpassword
Environment=MYSQL_USER=testuser
Environment=MYSQL_PASSWORD=testpassword
Environment=MYSQL_DATABASE=testdb
Volume=mariadb-volume.volume:/var/lib/mysql
Network=mariadb.network

Создание стека из нескольких контейнеров

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

Поскольку для правильной работы контейнера phpMyAdmin требуется, чтобы сервер MariaDB был активен и работал, мы можем объявить эту зависимость, как и для любой другой службы Systemd, с помощью Requires и . После опций в разделе «[Unit]». Первый устанавливает жесткую зависимость от службы, передаваемой в качестве значения; последний гарантирует, что наш сервис запустится после него. Кстати, если вы не знакомы с Systemd, вы можете посмотреть наше руководство о том, как создать службу Systemd. Вот как выглядит модуль-контейнер для phpMyAdmin:

[Unit]
Description=phpMyAdmin container
Requires=mariadb-service.service
After=mariadb-service.service
 
[Container]
Image=docker.io/phpmyadmin:latest
Network=mariadb.network
Environment=PMA_HOST=systemd-mariadb-service
PublishPort=8080:80

[Install]
WantedBy=multi-user.target

В приведенном выше примере мы также использовали параметр PublishPort, который является эквивалентом podman -p  (--publish): он используется для сопоставления порта хоста с портом контейнера. В данном случае мы сопоставили порт 8080 в хост-системе с портом 80 внутри контейнера.

Мы также предоставили значение для переменной среды PMA_HOST с помощью опции Environment: она используется для указания адреса сервера базы данных (в этом случае мы использовали имя контейнера MariaDB, которое разрешается в фактический адрес). Обратите внимание, что в качестве значения переменной среды мы использовали имя контейнера MariaDB, а не имя модуля «.container». Чтобы начать нашу новую настройку, мы еще раз запускаем:

$ systemd --user daemon-reload

Затем мы можем запустить сгенерированный сервис «phpmyadmin-service», который, в свою очередь, запускает контейнер phpMyAdmin. Поскольку он жестко зависит от MariaDB, последний тоже запустится автоматически. У нас должна быть возможность связаться с phpMyadmin по адресу «localhost:8080». Для входа мы можем использовать учетные данные, указанные в контейнере MariaDB:

Заключительные мысли

В этом уроке мы узнали, как создавать и запускать контейнеры, тома и сети Podman в Systemd с помощью Quadlet. Вместо определения стеков из нескольких контейнеров в одном файле, как мы делаем при использовании docker-compose, в Quadlet мы определяем контейнеры, тома и сети, используя выделенные модули Systemd.

Статьи по данной тематике: