PodmanをUbuntu24.04で使うにあたってQuadletなるものに触れる

Posted by 雅楽斎 on Wednesday, May 1, 2024

TOC

Ubuntu 22.04から24.04でのPodmanを概観

Ubuntuに収録されているPodmanのバージョンをざっくりと振り返ります。

  • Ubuntu 22.04 Jammy Jellyfish → 3.4.4
  • Ubuntu 23.04 Lunar Lobster → 4.3.1
  • Ubuntu 23.10 Mantic Minotaur → 4.3.1
  • Ubuntu 24.04 Noble Numbat → 4.9.3

Quadletが使えるように

Podman 4.4でマージされたQuadletというものがUbuntu収録のPodmanでも使えるようになったので、今回は手元にあるけど用途を失ったRaspberry Pi 3Bで使い方を確認します。

諸々のバージョンやストレージドライバーは以下の通りです。

$ uname -a
Linux ubuntu 6.8.0-1004-raspi #4-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 20 02:29:55 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux

kernelが6.8なので5.13以降で使えるネイティブのOverlayが使えます。

$ podman --version
podman version 4.9.3
$ podman info | grep -E '(graphDriverName|Native)'
  graphDriverName: overlay
    Native Overlay Diff: "true"

Quadletの実態→podman generate systemdを簡単にしたもの?

podmanはpodというコンテナを運用します。複数のコンテナ起動をコントロールするDocker composeと同じ仕組みとしてpodman-composeもありますが、OS再起動を含めた制御はsystemdのユニットファイルを生成するというスタンスで、podmanのサブコマンドpodman generate systemdで半自動的にユニットファイルを生成できます。

Nginxを題材に、Docker Compose風運用をPodmanでする

で、このpodman genetare systemdがPodman 4.7で非推奨になりました。

Release v4.7.0 · containers/podman · GitHub

非推奨になったとはいえ単にsystemdをキックするユニットファイルを生成するだけなので、これまでの運用がすぐに無効化されるわけではないはずですが、Quadletを使うことでsystemdのユニットファイルを操作する必要がなくなるという触れ込みなので使ってみます。

Quadletとは→拡張されたsystemdとpodman-system-generatorコマンドによるsystemdユニットとしてのコンテナ管理

QuadletではQuadletファイルで定義されたコンテナをsystemdユニットとして登録・管理し、そのためのヘルパーコマンドとして/usr/lib/systemd/system-generators/podman-system-generatorがあります。これが/usr/libexec/podman/quadletという実行ファイルのシンボリックリンクになっていて、あえて言うならこれがQuadletと呼ぶしかないと思います。

ただ、実際にQuadletを動かす段になるとこの実行ファイルはなりを潜めて、あくまでsystemdがQuadletファイルをsystemdユニットとして動かす形になっています。

内部で実際にsystemdユニットとして動かしている内容は参照できますが(後述)、[X-Container]という見たことのないセクションが反映されていて、systemdの拡張部分としてQuadletが裏で動いているということの様です。

適当にコンテナを立てて試してみる

今回、とりあえずUbuntu 24.04環境としてRaspberry Pi 3BにHTTPサーバーとしてnginxコンテナを立てて動かすコンテナをQuadletで管理する、という例を試します。なお、HTTPサーバーで表示するのは先ごろ発売されたWEB+DB PRESSの最後の総集編のISOイメージをOS起動時にマウントしたパスをnginxでホームディレクトリとして公開することにします。

HTTPサーバーとしてのnginxコンテナは基本は以前のものと同じです。

Nginxを題材に、Docker Compose風運用をPodmanでする

systemdでISOイメージをOS起動時にマウントする

  • ISOの置き場所 /var/isoimg/webdb_sp.iso
  • ISOのマウント先 /mnt/webdb

マウントはroot権限で、nginxコンテナの起動は一般ユーザーでやることにします。

マウント用のユニットファイル

/etc/systemd/system/mnt-webdb.mountを作成

[Unit]
Description=WEBDB+PRESS PDF
Before=local-fs.target

[Mount]
What=/var/isoimg/webdb_sp.iso
Where=/mnt/webdb
Type=iso9660
Options=ro,user,noauto,unhide

[Install]
WantedBy=local-fs.target
# mkdir /mnt/webdb

systemdでOS起動時にマウント

# systemctl daemon-reload
# systemctl start mnt-webdb.mount
# systemctl status mnt-webdb.mount
● mnt-webdb.mount - WEBDB+PRESS PDF
     Loaded: loaded (/etc/systemd/system/mnt-webdb.mount; disabled; vendor pres>
     Active: active (mounted) since Sun 2024-04-21 18:07:41 JST; 6s ago
      Where: /mnt/webdb
       What: /dev/loop0
      Tasks: 0 (limit: 18525)
     Memory: 48.0K
     CGroup: /system.slice/mnt-webdb.mount

Apr 21 18:07:41 ubuntu systemd[1]: Mounting WEBDB+PRESS PDF...
Apr 21 18:07:41 ubuntu systemd[1]: Mounted WEBDB+PRESS PDF.
# systemctl enable mnt-webdb.mount 
Created symlink /etc/systemd/system/local-fs.target.wants/mnt-webdb.mount → /etc/systemd/system/mnt-webdb.mount.
# ls -l /mnt/webdb/
total 395813
-r-xr-xr-x 1 root root 405298538 Aug 25  2023 index.pdf
-r-xr-xr-x 1 root root      2501 Aug 25  2023 readme.txt
dr-xr-xr-x 1 root root       228 Aug 25  2023 search
-r-xr-xr-x 1 root root       401 Aug 25  2023 search.pdx
dr-xr-xr-x 1 root root      9408 Aug 25  2023 webdb_pdf

httpサーバーとしてnginxコンテナを実行(動作確認)

  • nginxコンテナのdocker-compose.ymlの場所 /home/hogehoge/podmancompose/nginx-webdb
  • nginxコンテナが使用する物理ポート番号 50000
  • コンテナ名 nginx-webdb
  • ボリュームマウント /var/containers/nginx_webdb/default.conf:/etc/nginx/conf.d/default.conf/mnt/webdb:/usr/share/nginx/html

docker-compose.yml

/home/hogehoge/podmancompose/nginx-webdb/docker-compose.yml

version: "3"
services:
  nginx:
    image: docker.io/library/nginx:stable
    container_name: nginx-webdb
    ports:
      - "50000:80"
    restart: unless-stopped
    volumes:
      - /var/containers/nginx_webdb/default.conf:/etc/nginx/conf.d/default.conf
      - /mnt/webdb:/usr/share/nginx/html

ボリュームマウントするnginx設定ファイル

# install -d -o hogehoge -g hogehoge /var/containers/nginx_webdb

/var/containers/nginx_webdb/default.conf

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

podman-composeで動作確認

docker-compose.ymlのあるディレクトリで

$ podman-compose up -d

systemd管理用のユニットファイル生成

$ podman generate systemd --new --files --name nginx-webdb
/home/hogehoge/podmancompose/nginx-webdb/container-nginx-webdb.service

ISOイメージのマウントを依存ユニットに追加するので書き換え

$ diff -u container-nginx-webdb.service{.org,}
--- container-nginx-webdb.service.org	2024-04-21 18:07:59.660681476 +0900
+++ container-nginx-webdb.service	2024-04-21 18:12:42.686308562 +0900
@@ -6,7 +6,8 @@
 Description=Podman container-nginx-webdb.service
 Documentation=man:podman-generate-systemd(1)
 Wants=network-online.target
-After=network-online.target
+Requires=mnt-webdb.mount
+After=network-online.target mnt-webdb.mount
 RequiresMountsFor=%t/containers
 
 [Service]

コンテナを落としてsystemdに登録して動作確認

$ podman-compose down

$ cp container-nginx-webdb.service ~/.config/systemd/user/
$ systemctl --user enable container-nginx-webdb.service 
Created symlink /home/hogehoge/.config/systemd/user/default.target.wants/container-nginx-webdb.service → /home/hogehoge/.config/systemd/user/container-nginx-webdb.service.
$ systemctl --user start container-nginx-webdb.service 
$ systemctl --user status container-nginx-webdb.service 
● container-nginx-webdb.service - Podman container-nginx-webdb.service
     Loaded: loaded (/home/hogehoge/.config/systemd/user/container-nginx-webdb.>
     Active: active (running) since Sun 2024-04-21 18:21:20 JST; 29s ago
       Docs: man:podman-generate-systemd(1)
    Process: 163768 ExecStartPre=/bin/rm -f /run/user/1001/container-nginx-webd>
   Main PID: 164618 (conmon)
     CGroup: /user.slice/user-1001.slice/user@1001.service/app.slice/container->
             ├─164516 /usr/bin/fuse-overlayfs -o ,lowerdir=/var/containers/stor>
             ├─164595 /usr/sbin/dnsmasq -u root --conf-file=/run/user/1001/cont>
             ├─164596 containers-rootlessport
             ├─164606 containers-rootlessport-child
             ├─164618 /usr/bin/conmon --api-version 1 -c 52261826a3879b5bfab150>
             ├─164621 "nginx: master process nginx -g daemon off;"
             ├─164641 "nginx: worker process"
             ├─164642 "nginx: worker process"
             ├─164643 "nginx: worker process"
             ├─164644 "nginx: worker process"
             ├─164645 "nginx: worker process"
             ├─164646 "nginx: worker process"
             ├─164647 "nginx: worker process"
             └─164648 "nginx: worker process"

Apr 21 12:21:20 ubuntu conmon[164618]: 2024/04/21 18:21:20 [notice] 1#1: getrli>

動作を確認できたらコンテナを落とします。

$ podman-compose down

この後Quadletを使ってsystemdに登録するので、今回はsystemdから削除します。

$ systemctl --user stop container-nginx-webdb.service 
$ systemctl --user disable container-nginx-webdb.service

Quadletに触れる

今の時点では日本語の情報がびっくりするほどないですが、以下のサイトにかなりまとまっているので参考にします。

PodmanのQuadletでコンテナのsystemdサービス化を行う

Quadlet以前と以後の違い

以前のやり方では

  1. docker-compose.ymlを作ってpodman-composeでサービス起動を確認
  2. podman-composeでコンテナが起動した状態でpodman generate systemd --new でsystemdのユニットファイルを作成
  3. 作成したsystemdのユニットファイルを登録

の手順でしたが、Quadletを使った場合は

  1. Quadletファイルを作る
  2. 所定の場所にQuadletファイルを配置してsystemctl daemon-reload(一般ユーザーの場合はsystemctl --user daemon-reload)でsystemdユニットとして反映

となります。今までdocker-compose.ymlを作って起動してという流れでしたが、Quadletファイルを直接書ける場合はこの辺が綺麗サッパリなくなります。

とはいえ、これまで長くdocker-composeで管理してきたので、今回は試しにpodman-composeで動かしていた状態からQuadletファイルを作る手順で今回は勧めます。

なお、Podman公式に書かれているQuadletファイルはあまり現実的ではないサンプルなのでどこまで意味があるか謎ですがこんな感じです。

podman-systemd.unit — Podman documentation

[Unit]
Description=A minimal container

[Container]
# Use the centos image
Image=quay.io/centos/centos:latest

# Use volume and network defined below
Volume=test.volume:/data
Network=test.network

# In the container we just run sleep
Exec=sleep 60

[Service]
# Restart service when sleep finishes
Restart=always
# Extend Timeout to allow time to pull the image
TimeoutStartSec=900
# ExecStartPre flag and other systemd commands can go here, see systemd.unit(5) man page.
ExecStartPre=/usr/share/mincontainer/setup.sh

[Install]
# Start by default on boot
WantedBy=multi-user.target default.target

Podlet

Quadletファイルをdocker-compose.ymlから作るためのプロジェクトとしてpodletというものがあります(docker-compose.yml以外にもpodmanコマンド、実行中のpodmanコンテナからも作成できるという触れ込みです)

podlet - crates.io: Rust Package Registry

とりあえずダウンロードしようと思ったものの

https://github.com/containers/podlet/releases

  • podlet-aarch64-apple-darwin.tar.xz
  • podlet-x86_64-apple-darwin.tar.xz
  • podlet-x86_64-pc-windows-msvc.zip
  • podlet-x86_64-unknown-linux-gnu.tar.xz
  • podlet-x86_64-unknown-linux-musl.tar.xz

LinuxのARMがない!

ということでしかたなくamd64なLinux上で実行することにします。一応dockerhubにはamd64とarm64のコンテナがあるので、arm64のバイナリをインストールできるようになるまではこれを使う感じになるんですかね。

https://github.com/k9withabone/podlet/releases/download/v0.2.4/podlet-x86_64-unknown-linux-gnu.tar.xz

$ wget https://github.com/k9withabone/podlet/releases/download/v0.2.4/podlet-x86_64-unknown-linux-gnu.tar.xz
$ tar Jxvf podlet-x86_64-unknown-linux-gnu.tar.xz 
podlet-x86_64-unknown-linux-gnu/
podlet-x86_64-unknown-linux-gnu/podlet
podlet-x86_64-unknown-linux-gnu/LICENSE
podlet-x86_64-unknown-linux-gnu/README.md
podlet-x86_64-unknown-linux-gnu/CHANGELOG.md

podletはbusyboxスタイルのサブコマンドで入力を指定するようで、docker-compose.ymlからQuadletファイルを生成する場合はpodlet composeコマンドを実行します。

$ podlet-x86_64-unknown-linux-gnu/podlet -h
Generate podman quadlet files from a podman command, compose file, or existing
object

Usage: podlet [OPTIONS] <COMMAND>

Commands:
  podman    Generate a podman quadlet file from a podman command
  compose   Generate podman quadlet files from a compose file
  generate  Generate a podman quadlet file from an existing container,
                network, volume, or image
  help      Print this message or the help of the given subcommand(s)

Options:
  -f, --file [<FILE>]
          Generate a file instead of printing to stdout
  -u, --unit-directory
          Generate a file in the podman unit directory instead of printing to
          stdout [aliases: unit-dir]
  -n, --name <NAME>
          Override the name of the generated file (without the extension)
      --overwrite
          Overwrite existing files when generating a file
      --skip-services-check
          Skip the check for existing services of the same name
  -p, --podman-version <PODMAN_VERSION>
          Podman version generated quadlet files should conform to [default:
          4.8] [aliases: compatibility, compat] [possible values: 4.4, 4.5, 4.6,
          4.7, 4.8]
  -a, --absolute-host-paths [<RESOLVE_DIR>]
          Convert relative host paths to absolute paths
  -d, --description <DESCRIPTION>
          Add a description to the unit
      --wants <WANTS>
          Add (weak) requirement dependencies to the unit
      --requires <REQUIRES>
          Similar to --wants, but adds stronger requirement dependencies
      --before <BEFORE>
          Configure ordering dependency between units
      --after <AFTER>
          Configure ordering dependency between units
  -i, --install
          Add an [Install] section to the unit
      --wanted-by <WANTED_BY>
          Add (weak) parent dependencies to the unit
      --required-by <REQUIRED_BY>
          Similar to --wanted-by, but adds stronger parent dependencies
  -h, --help
          Print help (see more with '--help')
  -V, --version
          Print version

$ podlet-x86_64-unknown-linux-gnu/podlet compose -h
Generate podman quadlet files from a compose file

Usage: podlet compose [OPTIONS] [COMPOSE_FILE]

Arguments:
  [COMPOSE_FILE]  The compose file to convert

Options:
      --pod <POD>  Create a Kubernetes YAML file for a pod instead of separate
                   containers
  -h, --help       Print help (see more with '--help')
  
$ podlet-x86_64-unknown-linux-gnu/podlet --version
podlet 0.2.4

で、今回のnginxコンテナのdocker-compose.ymlから生成したQuadletファイルは以下。まぁかなりシンプルなんでエラーも出ずに出力されます。

$ podlet-x86_64-unknown-linux-gnu/podlet compose docker-compose.yml 
# nginx.container
[Container]
ContainerName=nginx-webdb
Image=docker.io/library/nginx:stable
PublishPort=50000:80
Volume=/var/containers/nginx_webdb/default.conf:/etc/nginx/conf.d/default.conf
Volume=/mnt/webdb:/usr/share/nginx/html

[Service]
Restart=always

RequiresとAfterを指定しましょう。最終的にこのコマンド実行はOS起動時の自動起動を設定するために変更しています。記事の末尾を参照ください。

$ podlet-x86_64-unknown-linux-gnu/podlet --requires "mnt-webdb.mount" --after "network-online.target mnt-webdb.mount" compose docker-compose.yml
# nginx.container
[Unit]
Requires=mnt-webdb.mount

[Container]
ContainerName=nginx-webdb
Image=docker.io/library/nginx:stable
PublishPort=50000:80
Volume=/var/containers/nginx_webdb/default.conf:/etc/nginx/conf.d/default.conf
Volume=/mnt/webdb:/usr/share/nginx/html

[Service]
Restart=always

Afterがないんだが…バグだそうです。0.3がリリースされたらおそらくAfterが追加されるんでしょう。

–after option not working · Issue #64 · containers/podlet · GitHub

--file .でカレントディレクトリに出力します。

$ podlet-x86_64-unknown-linux-gnu/podlet --file . --requires "mnt-webdb.mount" --after "network-online.target mnt-webdb.mount" compose docker-compose.yml
Wrote to file: ./nginx.container

Quadletを使う

この.containerファイルを下の候補の中のどこかに格納します。

  • /etc/containers/systemd/
  • /usr/share/containers/systemd/
  • $XDG_CONFIG_HOME/containers/systemd/ または ~/.config/containers/systemd/
  • /etc/containers/systemd/users/$(UID)
  • /etc/containers/systemd/users/

今回はpodman実行ユーザーから管理する場所という意味で~/.config/containers/systemd/に格納します。で、このディレクトリがないので作ります。

$ mkdir ~/.config/containers/systemd

さっきpodletのバグで付与してくれなかったAfter行を追加します。

$ diff -u nginx.container{.org,}
--- nginx.container.org	2024-05-01 19:15:45.173014110 +0900
+++ nginx.container	2024-05-01 19:16:25.446989802 +0900
@@ -1,5 +1,6 @@
 [Unit]
 Requires=mnt-webdb.mount
+After=network-online.target mnt-webdb.mount
 
 [Container]
 ContainerName=nginx-webdb

これをQuadletでsystemdのユニットファイルに変換します。--dryrunを指定すると生成する中身を表示するだけみたいなので、とりあえず実行します。

$ /usr/lib/systemd/system-generators/podman-system-generator --user --dryrun
quadlet-generator[20549]: Error occurred resolving path "/etc/containers/systemd/users/1000": lstat /etc/containers/systemd/users/1000: no such file or directory
quadlet-generator[20549]: Loading source unit file /home/hogehoge/.config/containers/systemd/nginx.container
---nginx.service---
[Unit]
Requires=mnt-webdb.mount
After=network-online.target mnt-webdb.mount
SourcePath=/home/hogehoge/.config/containers/systemd/nginx.container
RequiresMountsFor=%t/containers
RequiresMountsFor=/var/containers/nginx_webdb/default.conf
RequiresMountsFor=/mnt/webdb

[X-Container]
ContainerName=nginx-webdb
Image=docker.io/library/nginx:stable
PublishPort=50000:80
Volume=/var/containers/nginx_webdb/default.conf:/etc/nginx/conf.d/default.conf
Volume=/mnt/webdb:/usr/share/nginx/html

[Service]
Restart=always

Environment=PODMAN_SYSTEMD_UNIT=%n
KillMode=mixed
ExecStop=/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
ExecStopPost=-/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
Delegate=yes
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
ExecStart=/usr/bin/podman run --name=nginx-webdb --cidfile=%t/%N.cid --replace --rm --cgroups=split --sdnotify=conmon -d -v /var/containers/nginx_webdb/default.conf:/etc/nginx/conf.d/default.conf -v /mnt/webdb:/usr/share/nginx/html --publish 50000:80 docker.io/library/nginx:stable
  • 思ったより長い
  • ユニットファイルを格納する候補の4番目の場所(/etc/containers/systemd/users/$(UID))がないというエラーが出ているが知ったこっちゃないのでこのメッセージを出さなくしてほしい

ということで、実際に反映するならsystemctl --user daemon-reloadを実行します。

$ systemctl --user daemon-reload
$ systemctl --user list-unit-files -t service | grep nginx
nginx.service                                    generated -      

nginx.serviceという名前で登録されました。

$ systemctl --user status nginx.service 
○ nginx.service
     Loaded: loaded (/home/hogehoge/.config/containers/systemd/nginx.container;>
     Active: inactive (dead)

まだ死んでいるので起動します。

$ systemctl --user start nginx.service 
$ systemctl --user status nginx.service 
● nginx.service
     Loaded: loaded (/home/hogehoge/.config/containers/systemd/nginx.container;>
     Active: active (runこning) since Wed 2024-05-01 19:44:47 JST; 5s ago
   Main PID: 20649 (conmon)
      Tasks: 22 (limit: 940)
     Memory: 22.5M (peak: 22.9M)
        CPU: 1.491s
     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/nginx.serv>
             ├─libpod-payload-a9e1c6d5179f3d9908cda97df8e4125bac8d25cd7118dd37a>
             │ ├─20651 "nginx: master process nginx -g daemon off;"
             │ ├─20669 "nginx: worker process"
             │ ├─20670 "nginx: worker process"
             │ ├─20671 "nginx: worker process"
             │ └─20672 "nginx: worker process"
             └─runtime
               ├─20630 /usr/bin/slirp4netns --disable-host-loopback --mtu=65520>
               ├─20633 rootlessport
               ├─20639 rootlessport-child
               └─20649 /usr/bin/conmon --api-version 1 -c a9e1c6d5179f3d9908cda>

May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: us>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: ng>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: bu>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: OS>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: ge>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: st>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: st>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: st>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: st>
May 01 19:44:48 ubuntu nginx-webdb[20649]: 2024/05/01 10:44:48 [notice] 1#1: st>

HTTPサーバーが起動しているか確認します。

$ curl http://localhost:50000/
<html>
<head><title>Index of /</title></head>
<body>
<h1>Index of /</h1><hr><pre><a href="../">../</a>
<a href="search/">search/</a>                                            24-Aug-2023 15:00       -
<a href="webdb_pdf/">webdb_pdf/</a>                                         24-Aug-2023 15:00       -
<a href="index.pdf">index.pdf</a>                                          24-Aug-2023 15:00    387M
<a href="readme.txt">readme.txt</a>                                         24-Aug-2023 15:00    2501
<a href="search.pdx">search.pdx</a>                                         24-Aug-2023 15:00     401
</pre><hr></body>
</html>

ということでQuadletの動作確認ができました。

Quadletを使った場合のOS起動時の自動起動について

Quadletファイルをsystemdで実行する場合、

[Service]
Restart=always

が設定されているので、OSの再起動をした場合に自動的にPodmanコンテナが起動するように思えますが、実際には自動起動することはありません。

かと言ってsystemctl enableで自動起動するようにすれば良いのかというとそういうことではなく、enableとdisableによる制御自体ができません。

$ systemctl --user enable nginx.service 
Failed to enable unit: Unit /run/user/1000/systemd/generator/nginx.service is transient or generated.
$ systemctl --user disable nginx.service 
The unit files have no installation config (WantedBy=, RequiredBy=, UpheldBy=,
Also=, or Alias= settings in the [Install] section, and DefaultInstance= for
template units). This means they are not meant to be enabled or disabled using systemctl.
 
Possible reasons for having these kinds of units are:
• A unit may be statically enabled by being symlinked from another unit's
  .wants/, .requires/, or .upholds/ directory.
• A unit's purpose may be to act as a helper for some other unit which has
  a requirement dependency on it.
• A unit may be started when needed via activation (socket, path, timer,
  D-Bus, udev, scripted systemctl call, ...).
• In case of template units, the unit is meant to be enabled with some
  instance name specified.

また、OS起動時に自動起動されるユニットの一覧を確認しても入っていません。

$ systemctl --user list-dependencies default.target
default.target
● └─basic.target
●   ├─paths.target
●   ├─sockets.target
●   │ ├─dbus.socket
●   │ ├─dirmngr.socket
●   │ ├─gpg-agent-browser.socket
●   │ ├─gpg-agent-extra.socket
●   │ ├─gpg-agent-ssh.socket
●   │ ├─gpg-agent.socket
●   │ ├─keyboxd.socket
●   │ ├─pk-debconf-helper.socket
●   │ └─snapd.session-agent.socket
●   └─timers.target
●     └─launchpadlib-cache-clean.timer

で、podmanのQuadletファイルの例は最終行に以下の記述があり、

[Install]
# Start by default on boot
WantedBy=multi-user.target default.target

説明もあります。

Enabling unit files The services created by Podman are considered transient by systemd, which means they don’t have the same persistence rules as regular units. In particular, it is not possible to “systemctl enable” them in order for them to become automatically enabled on the next boot.

To compensate for this, the generator manually applies the [Install] section of the container definition unit files during generation, in the same way systemctl enable does when run later.

このInstall行でOS起動時に実行されるターゲットを指定することでOS起動時の自動起動を実現するのがセオリーみたいですが、systemdの流儀から外れるので将来的に回収してほしいところ。Podletのオプションとしても--install --wanted-by "default.target"が必要です(実際にはAfterも追記する必要があります)

$ podlet-x86_64-unknown-linux-gnu/podlet --requires "mnt-webdb.mount" --after "network-online.target mnt-webdb.mount" --install --wanted-by "default.target" compose docker-compose.yml
# nginx.container
[Unit]
Requires=mnt-webdb.mount

[Container]
ContainerName=nginx-webdb
Image=docker.io/library/nginx:stable
PublishPort=50000:80
Volume=/var/containers/nginx_webdb/default.conf:/etc/nginx/conf.d/default.conf
Volume=/mnt/webdb:/usr/share/nginx/html

[Service]
Restart=always

[Install]
WantedBy=default.target
$ podlet-x86_64-unknown-linux-gnu/podlet --file . --requires "mnt-webdb.mount" --after "network-online.target mnt-webdb.mount" --install --wanted-by "default.target" compose docker-compose.yml
Wrote to file: ./nginx.container

OS起動時に実行される対象に入っているかを確認します。

$ systemctl --user list-dependencies default.target
default.target
○ ├─nginx.service
● └─basic.target
●   ├─paths.target
●   ├─sockets.target
●   │ ├─dbus.socket
●   │ ├─dirmngr.socket
●   │ ├─gpg-agent-browser.socket
●   │ ├─gpg-agent-extra.socket
●   │ ├─gpg-agent-ssh.socket
●   │ ├─gpg-agent.socket
●   │ ├─keyboxd.socket
●   │ ├─pk-debconf-helper.socket
●   │ └─snapd.session-agent.socket
●   └─timers.target
●     └─launchpadlib-cache-clean.timer

また、(ssh等で)ログインしていない場合に止まるのはPodmanに限らず起こることなので、コンテナの実行ユーザーはlingerを有効にします。

# loginctl enable-linger hogehoge

雑感

良さそうなこと

  • docker-compose/podman-compose依存を脱却(ソラでQuadletファイルを書けるなら完全に不要)
  • docker/podman外のsystemd管理のサービスとの依存関係を作りやすい

良くないかもしれないこと

  • [X-Container]のImageにタグ付きでコンテナレジストリが入るので、おそらくsystemdからの実行が走る度にコンテナレジストリへのチェックが入る。普段は問題ないが、非互換の更新がコンテナレジストリに入った場合に更新されるとまずそうなので、イメージのlatest指定はやめたほうが良さそう
  • コンテナレジストリに繋がらない場合にはサービスが起動しないという動作になりそうな気がする(インターネットに繋がっていることはnetwork-online.targetをAfterに指定すれば担保できそうな気はする)
    • 実行するコンテナがdocker-compose/podman-compose pullでできた方が管理の都合は良いかもしれない(その場合はQuadletは使えない?)
  • Quadletファイルを直接書ける場合を除くと手間的にはpodman generate systemdでユニットファイルを作って登録するのとあまり変わらない

こんなところでしょうか。systemdが動く環境であれば移行するのは正統性があるのかなと感じるので、簡素なサービスであればじゃんじゃん使うべきかなと思います。

スポンサーリンク


comments powered by Disqus