📋
Podman Compose (Rootless) で自動起動
概要
ユーザでログインすることなくpodman composeを自動起動させる。
nvidiaのGPUを有効にしたコンテナではハマりポイントがあるので、そこの対応策も示す。
- systemdを活用する。
- nvidiaのドライバ初期化を待つために、nvidia-smiを実行する。
因みに、nvidiaのGPUを有効にしたコンテナの生成方法はこちらで記事にしている。
環境
項目 | 内容 | Versionなど |
---|---|---|
ホストOS | Ubuntu | 24.04 Server |
コンテナマネージャ | Podman | 4.9.3 |
podman compose のバックエンド | podman-compose | 1.3.0 |
グラフィックボード | GTX 1650 | Turing(第六世代) |
systemdの設定
systemd に unit ファイルを登録
# コマンドを確認
podman compose systemd -h
# unitファイルを生成
# /etc/systemd/user/podman-compose@.service
sudo podman compose systemd -a create-unit
# systemd 再読み込み
sudo systemctl daemon-reload
生成されたunitファイルを編集
/etc/systemd/user/podman-compose@.service が生成されるが、このままでは上手く動作しないので手で修正する。ExecStopPostはお好みで。
/etc/systemd/user/podman-compose@.service
# /etc/systemd/user/podman-compose@.service
[Unit]
Description=%i rootless pod (podman-compose)
[Service]
Type=simple
EnvironmentFile=%h/.config/containers/compose/projects/%i.env
# これは nvidia の GPUを有効にしたコンテナのみ。
+ ExecStartPre=/usr/bin/nvidia-smi
# podman-composeでpodを生成するように修正
- ExecStartPre=-/usr/bin/podman-compose up --no-start
+ ExecStartPre=-/usr/bin/podman-compose --in-pod pod_%i up --no-start
ExecStartPre=/usr/bin/podman pod start pod_%i
ExecStart=/usr/bin/podman-compose wait
ExecStop=/usr/bin/podman pod stop pod_%i
# 停止するだけでなくpodを削除する。podman-compose down のイメージ。
+ ExecStopPost=/usr/bin/podman pod rm pod_%i
[Install]
WantedBy=default.target
個別のcomposeを登録
下記をコマンドでunitファイル内で利用するenvファイルを生成。
(一つのunitファイルから、複数のserviceを管理することが出来る)
podman compose systemd -a register
例えば、下記のようなファイルが生成され、先ほどのunitファイルから参照されることになる。
~/.config/containers/compose/projects/your-service.env
COMPOSE_PROJECT_DIR=/home/user/your-service
COMPOSE_FILE=compose.yml
COMPOSE_PATH_SEPARATOR=:
COMPOSE_PROJECT_NAME=your-service
Unitファイル有効化
register コマンドを実行した際に、指示が表示されるので、それ通りにコマンドを実行する。
# your-service の部分は対象のサービス名で置き換え
systemctl --user enable --now podman-compose@your-service
# 動作確認
systemctl --user status podman-compose@your-service
journalctl --user -xeu podman-compose@your-service
# podman側からも確認できる(pod化された以降のみ可)
podman pod stats pod_your-service
PC起動時(ログインしていない状態)でもユーザ空間のsystemd管理サービスを実行
# ログインしていない状態でもuser空間のsystemd管理サービスを動作させる。
# uservame の部分は、適切なユーザ名で置き換え。
sudo loginctl enable-linger username
以上でsystemdでpodman-composeで規定したコンテナ群を管理できるようになった。
以降は、podman compose ではなく、systemctlで管理する。
参考
podman-compose systemd のソース 該当部分
create-unit部分
script = os.path.realpath(sys.argv[0])
...
elif args.action == "create-unit":
fn = "/etc/systemd/user/podman-compose@.service"
out = f"""\
# {fn}
[Unit]
Description=%i rootless pod (podman-compose)
[Service]
Type=simple
EnvironmentFile=%h/{stacks_dir}/%i.env
ExecStartPre=-{script} up --no-start
ExecStartPre=/usr/bin/podman pod start pod_%i
ExecStart={script} wait
ExecStop=/usr/bin/podman pod stop pod_%i
[Install]
WantedBy=default.target
"""
if os.access(os.path.dirname(fn), os.W_OK):
log.debug("writing [%s]: ...", fn)
with open(fn, "w", encoding="utf-8") as f:
f.write(out)
log.debug("writing [%s]: done.", fn)
print(
"""
while in your project type `podman-compose systemd -a register`
"""
)
else:
print(out)
log.warning("Could not write to [%s], use 'sudo'", fn)
register部分
if args.action == "register":
proj_name = compose.project_name
fn = os.path.expanduser(f"~/{stacks_dir}/{proj_name}.env")
os.makedirs(os.path.dirname(fn), exist_ok=True)
log.debug("writing [%s]: ...", fn)
with open(fn, "w", encoding="utf-8") as f:
for k, v in compose.environ.items():
if k.startswith("COMPOSE_") or k.startswith("PODMAN_"):
f.write(f"{k}={v}\n")
log.debug("writing [%s]: done.", fn)
log.info("\n\ncreating the pod without starting it: ...\n\n")
username = getpass.getuser()
print(
f"""
you can use systemd commands like enable, start, stop, status, cat
all without `sudo` like this:
\t\tsystemctl --user enable --now 'podman-compose@{proj_name}'
\t\tsystemctl --user status 'podman-compose@{proj_name}'
\t\tjournalctl --user -xeu 'podman-compose@{proj_name}'
and for that to work outside a session
you might need to run the following command *once*
\t\tsudo loginctl enable-linger '{username}'
you can use podman commands like:
\t\tpodman pod ps
\t\tpodman pod stats 'pod_{proj_name}'
\t\tpodman pod logs --tail=10 -f 'pod_{proj_name}'
"""
)
Discussion