LinuxはQuadlet、MacはPodman Desktop

ローカル開発基盤のコンテナ管理を、ホストごとに決めました。インフラ構築では、起動方式だけでなくUIDと名前解決も合わせる必要がありました。

ホストOSPodman モードサービス管理
Compute ServerUbuntu 24.04rootlessQuadlet(.container → systemd)
Storage ServerUbuntu 24.04rootlessQuadlet(.container → systemd)
Desktop PCmacOSPodman Desktopcompose(GUI 管理)

Linux 2台はrootless Podman + Quadletでsystemd管理します。Macはpodman machineでstorage.home.arpaを解決できなかったため、Podman Desktopにしました。

以下ではQuadletの動作、UID、Lokiの権限、podman unshareとsudoの使い分けを確認します。


Quadlet 検証: Podman 4.9.x で動くか

Ubuntu 24.04のPodman v4.9.3にpodman quadletはありませんが、systemd-generatorによるQuadletは動きました。

確認方法

所定の場所に.containerを置くと、.serviceが生成されます。

  systemctl cat node-exporter.service
  
  # /run/systemd/generator/node-exporter.service
# Automatically generated by /usr/lib/systemd/system-generators/podman-system-generator
[Unit]
Description=Prometheus Node Exporter (Quadlet)
After=network-online.target
Wants=network-online.target
SourcePath=/etc/containers/systemd/node-exporter.container
...
  

Node Exporter の Quadlet ファイル例

ファイルパス: /etc/containers/systemd/node-exporter.container

  [Unit]
Description=Prometheus Node Exporter (Quadlet)
After=network-online.target
Wants=network-online.target

[Container]
Image=docker.io/prom/node-exporter:v1.10.1
ContainerName=node-exporter
Network=host
ReadOnly=true
DropCapability=ALL
Volume=/:/host:ro,rslave
Args=--path.rootfs=/host

[Install]
WantedBy=multi-user.target
  

配置後:

  systemctl daemon-reload
systemctl start node-exporter.service
systemctl status node-exporter.service
  

ENTRYPOINTと引数

最初のExec設定はExec=/bin/node_exporter --path.rootfs=/hostで失敗しました。prom/node-exporterのENTRYPOINTが既に/bin/node_exporterなので、同じコマンドが重複します。設定済みのENTRYPOINTへの引数はArgsで渡します。

systemd 連携の注意点

  • /run/systemd/generator 下に動的生成された Unit は systemctl enable できない
  • [Install] セクションの WantedBy=multi-user.target で自動起動を制御する

Rootless UID マッピングの理解

subuidと所有権

rootlessでは、UID 1000のホストユーザーとサブUID(100000〜)を分けます。対応しない所有者のファイルへ通常のユーザー権限ではアクセスできません。

100999:100999のファイルはksh3(UID 1000)から直接操作できません。podman unshareでユーザー名前空間の仮想rootとして扱います。

Loki の permission denied: 実例と分析

rootlessのGrafana Loki(grafana/loki:3.5)でエラーが出ました。

  open /loki/index_cache/... .tsdb-tmp: permission denied
  

/opt/containers/runtime/loki/dataはksh3:1000、0755です。コンテナはloki(UID=10005)で動き、マッピング後の所有者が一致しないため書き込めません。

UID マッピングフロー

ケースごとのUID対応です。

  ホスト: ksh3 (UID=1000)

Case A: keep-id なし (イメージ loki=10005)
  container root(0) -> host 100000 (subuid開始例)
  container loki(10005) -> host 110005
  実行UID = 110005 != ディレクトリ所有 1000 → 書けない

Case B: keep-id + loki(罠)
  container root(0) -> host 1000
  container loki(10005) -> host 110005
  実行UID = 110005 != 1000 → 書けない

Case C: keep-id + loki + :U
  :U によりホスト側 /data の所有者 chown → 110005
  実行UID = 110005 → 書ける
  しかしホストユーザー1000は所有者でなくなる → 編集しにくい

Case D: keep-id + User=0 ← 採用
  container root(0) -> host 1000
  実行UID = 1000 → 所有者一致 → 書ける (ホスト操作性維持)
  

Case Bではkeep-idを付けても、実行するLokiユーザーはサブUID側に残ります。rootのマッピング変更と、実行ユーザーの変更は別です。

選択肢比較

方法仕組み動くホスト編集最小権限
User=0 + keep-idroot をホスト UID にOKOK低
loki + ACLloki UID に ACL 付与OKOK中
loki + :U自動 chown (所有者 loki)OK低 (sudo 要)中
0777全開放OKOK非推奨

推奨パターン

  1. 速く動かしたい / 開発用途 → UserNS=keep-id + User=0
  2. 非 root 実行を維持したい → ACL 方式(UserNS=keep-id 不要、User= 指定なし)

Loki Quadlet 設定例(User=0 + keep-id 方式)

  [Unit]
Description=Grafana Loki (Quadlet - rootless)
After=network-online.target
Wants=network-online.target

[Container]
Image=docker.io/grafana/loki:3.5
ContainerName=loki
Exec=-config.file=/etc/loki/config.yaml
UserNS=keep-id
User=0
Network=host
PublishPort=3100:3100
Volume=/opt/containers/etc/loki:/etc/loki:ro
Volume=/opt/containers/runtime/loki/data:/loki:rw
Volume=/opt/containers/etc/loki/certs:/etc/certs:ro

[Service]
Restart=always
TimeoutStartSec=900s

[Install]
WantedBy=multi-user.target
  
  systemctl --user daemon-reload
systemctl --user restart loki.service
podman logs loki | grep -i permission || echo "permission errors none"
  

ACL 方式(非 root 維持)

  LOKI_UID=$(podman run --rm docker.io/grafana/loki:3.5 id -u)
LOKI_GID=$(podman run --rm docker.io/grafana/loki:3.5 id -g)

setfacl -m u:${LOKI_UID}:rwx /opt/containers/runtime/loki/data
setfacl -R -m u:${LOKI_UID}:rwx /opt/containers/runtime/loki/data
setfacl -d -m u:${LOKI_UID}:rwx /opt/containers/runtime/loki/data

systemctl --user restart loki.service
podman logs loki | grep -i permission || echo "permission errors none"
  

運用モデル: podman unshare と sudo の3段階

sudoなら所有権の制限を越えて操作できます。rootlessの通常操作とは別の、管理権限を使う経路として扱います。

フェーズ操作方法
通常時一般ユーザーとして操作、コンテナ内ファイルには「触れない」Rootless のデフォルト
調整時コンテナ内ファイルの微調整、パーミッション変更podman unshare
全権が必要な時ディレクトリ移設、バックアップ一括操作sudo

読み取り用のバックアップではsudo rsync -aがpodman unshareより単純な場合があります。MinIOの.minio.sysは、-aで所有者情報を維持してコピーしました。


macOS の DNS 問題: CLI から Podman Desktop へ

MacのCLI podman machineでは、Grafanaからstorage.home.arpaのPrometheus / Lokiへ接続できませんでした。

症状

  • ホストの Mac からは curl https://storage.home.arpa:9090 が通る
  • Grafana コンテナ内では名前解決エラーまたは connection refused
  • DNS ログに storage.home.arpa AAAA -> name does not exist

原因: Podman Desktop と CLI の名前解決の違い

観点DesktopCLI (machine)
/etc/hostsホストと共有独立(VM 内で別管理)
DNS 設定反映自動手動
ホスト汚染リスク高低
サンドボックス性弱強

このCLI環境のVMはホストDNS / hostsを共有せず、home.arpaを解決できませんでした。Composeのdns:も、VMが/etc/resolv.confを生成するため反映されませんでした。

解決策と判断

LinuxはQuadlet + rootlessを維持します。MacはGrafana UI、ブラウザ、VSCodeを使う開発端末なので、内部LANへの接続を優先しました。

MacをPodman Desktopに変えたところ、ホスト側の名前解決がVMへ渡り、storage.home.arpaへ接続できました。extra_hostsの固定指定も追加しました。

  services:
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
      - NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,*.home.arpa
    volumes:
      - /Users/ksh3/containers/iac/grafana/data:/var/lib/grafana
      - /Users/ksh3/containers/iac/grafana/provisioning:/etc/grafana/provisioning:ro
      - /Users/ksh3/containers/iac/grafana/certs:/etc/ssl:ro
    extra_hosts:
      - "storage.home.arpa:10.10.10.3"
    depends_on:
      - prometheus
  

注意事項

  • Podman 4.9.x には podman quadlet CLI がないが、systemd-generator が機能するので運用上は問題ない。Podman 5.x で CLI サポートが追加される
  • User=0 + keep-id は開発用途では最短だが、コンテナ内 root 実行なので最小権限ではない。本番寄せなら ACL 方式を検討
  • :U 方式はホスト側の所有者がコンテナ UID に変わるため、開発時の操作性が大きく下がる
  • SELinux 有効環境では Volume に :Z / :z を追加検討
  • NFS / root_squash 環境では :U や chown が失敗することがある
  • Podman Desktop は便利だが「安全なサンドボックス」ではなく「便利なブリッジ環境」。名前解決は自分で明示した方が確実