- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに — コマンドは同じ、哲学は別物
- 内部動作 — デーモン vs fork-exec
- Rootless — デフォルトの違い
- 設定ファイル — どこに何があるか
- GPU — CDIが正解
- Compose — compose.yamlはそのまま使えるのか?
- 移行の罠コレクション — 知っていれば30分、知らなければ半日
- バージョンとコミュニティ — 誰が作り、どこで議論されるか
- おわりに
- 参考資料
はじめに — コマンドは同じ、哲学は別物
Podmanの第一印象は「dockerをpodmanに置き換えれば動くツール」です。実際 alias docker=podman でほとんどのコマンドがそのまま動き、公式にもDocker CLI互換を目標としています。しかしその表面の下のアーキテクチャはほぼ正反対です — そして移行で出会うすべての違い(設定ファイルの場所、GPU設定、compose、権限問題)は、このアーキテクチャの違いから流れ出ています。
この記事はその違いを根から整理します。なお、コマンドはPodman 5.x / Docker Engine 27+ 基準です。
内部動作 — デーモン vs fork-exec
Dockerの構造はクライアント-サーバーです。 docker run を打つと、CLIはRESTリクエストを dockerd デーモンに送り、デーモンがcontainerdに、containerdがruncに委譲してコンテナを作ります。すべてのコンテナの親は結局デーモンです。
Docker: docker CLI ──REST──▶ dockerd ──▶ containerd ──▶ runc ──▶ コンテナ
Podman: podman CLI ──fork/exec──▶ conmon ──▶ crun(runc) ──▶ コンテナ
Podmanにはデーモンがありません。 podman run は普通のプロセスのようにfork-execでコンテナを直接作ります。コンテナごとに小さな監視プロセス conmon が付いてstdioと終了コードを管理し、実際の生成はOCIランタイム crun(C言語製、runcより軽く速い)が行います。この構造の含意:
- 単一障害点がない。 dockerdが死ぬと(あるいはアップグレードすると)全コンテナの管理が止まりますが、Podmanにはそもそも中央プロセスがありません。
- rootデーモンソケットという攻撃面がない。
/var/run/docker.sockは事実上root権限そのもので、これを狙う攻撃が多発してきました。Podmanにはそのソケットが存在しません(互換ソケットは必要なときだけ、ユーザー権限で起動します)。 - systemdと自然に結合する。 コンテナが普通の子プロセスなので、systemdユニットで直接管理できます。最新Podmanの推奨は Quadlet —
.containerファイルを書くとsystemdサービスが生成されます(podman generate systemdは旧式になりました)。
Rootless — デフォルトの違い
両エンジンともrootlessモードを持ちますが、重心が違います。Dockerはrootfulがデフォルトでrootlessはオプトイン、Podmanはrootlessがデフォルトの体験です(Fedora/RHELではインストール直後から一般ユーザーで使います)。
rootlessの原理は userネームスペース です。コンテナ内のroot(UID 0)は外では自分のUIDに、コンテナ内の他のUIDは /etc/subuid・/etc/subgid に割り当てられた従属UID帯にマッピングされます。コンテナが脱獄しても、手にするのは一般ユーザーの権限だけです。
移行時に知っておくべきrootlessの制約:
- 1024未満のポートはバインド不可(デフォルト) —
sysctl net.ipv4.ip_unprivileged_port_startを下げるか、高いポートを使います。 - ネットワークはユーザースペーススタック(pasta/slirp4netns)経由 — ほとんどのワークロードには十分ですが、極端な性能が必要ならrootfulを検討。
- 保存場所が違う — 下の設定の節を参照。
docker system dfの感覚でディスクを探して戸惑うポイントです。 - 起動オーバーヘッドは僅かにありますが、長期稼働サービスでは無意味な水準です。
設定ファイル — どこに何があるか
Dockerの設定がデーモン中心(daemon.json)なのに対し、Podmanはライブラリ中心の分散設定です。システム全体は /etc/containers/、ユーザー別は ~/.config/containers/ が優先されます。
Docker Podman
────────────────────────────── ─────────────────────────────────────────
/etc/docker/daemon.json /etc/containers/containers.conf (エンジン・ランタイム設定)
~/.config/containers/containers.conf
(レジストリミラー等もdaemon.json) /etc/containers/registries.conf (レジストリ・ミラー・ブロック)
/etc/containers/storage.conf (ストレージドライバ・パス)
/etc/containers/policy.json (イメージ署名ポリシー)
~/.docker/config.json (認証) ~/.config/containers/auth.json (レジストリ認証)
イメージ・コンテナ保存場所
/var/lib/docker rootful: /var/lib/containers/storage
rootless: ~/.local/share/containers/storage
移行時に最もよく触るのは二つ:registries.conf に unqualifiedイメージの検索レジストリ を指定すること(Dockerは nginx を自動でdocker.ioと解釈しますが、Podmanはデフォルトでは尋ねるか設定に従います — unqualified-search-registries = ["docker.io"] を入れればDockerと同じになります)、そして社内ミラー/認証を registries.conf + auth.json へ移すことです。
GPU — CDIが正解
PodmanでNVIDIA GPUを使う標準経路は CDI(Container Device Interface) です。CDIは「このデバイスをコンテナに入れるには、どのデバイスノード・ライブラリ・環境変数が必要か」を記述するベンダー中立の仕様で、Dockerの --gpus のようなランタイムフック方式より透明で移植性が高い。Kubernetesの GPU Operator も内部でCDIを使っています。
# 1) nvidia-container-toolkit をインストール後、CDIスペックを生成
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml
# 2) 生成されたデバイス名を確認
nvidia-ctk cdi list
# nvidia.com/gpu=0, nvidia.com/gpu=all, (MIGなら) nvidia.com/gpu=0:0 ...
# 3) コンテナでGPUを使用
podman run --rm --device nvidia.com/gpu=all \
nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
- Dockerの
docker run --gpus allに対応するのが--device nvidia.com/gpu=allです(最新Podmanは--gpusも互換フラグとして受けますが、CDI表記が正式です)。 - rootlessでもGPUは使えます。 GPUドライバはカーネル空間で動くので、コンテナの権限レベルと性能は無関係です。システム全体の
/etc/cdi/nvidia.yamlが読めればそのまま使い、だめならユーザー空間にスペックを生成してそのディレクトリをPodmanに指定します。 - ドライバ更新後にGPUが見えなくなったら、十中八九 CDIスペックの再生成(
nvidia-ctk cdi generate)を忘れています。
Compose — compose.yamlはそのまま使えるのか?
結論から:ほぼそのまま使え、方法は二つです。
方法1 — Docker ComposeバイナリをPodmanソケットに接続(推奨)。 PodmanはDocker API互換ソケットを提供できます。これを有効にすると、標準の docker compose がバックエンドだけPodmanのまま動きます — compose.yamlの書き換えは不要です。
# ユーザーソケットを有効化(rootless)
systemctl --user enable --now podman.socket
# docker compose がPodmanソケットを見るよう指定
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
docker compose up -d # バックエンドはPodman
Go実装の正式なComposeスペック実装をそのまま使うため、互換性は最大です。podman compose コマンド自体も外部のコンポーズプロバイダ(インストールされていればdocker-compose)を呼ぶラッパーです。
方法2 — podman-compose。 Pythonで再実装された別プロジェクトです。デーモン/ソケットなしでpodmanコマンドを直接呼ぶ純粋な実装という長所がありますが、Composeスペックの隅(一部のネットワークオプション、profiles、高度なdepends_on条件など)で正式実装と微妙に差が出ることがあります。シンプルなスタックには十分で、複雑なcomposeファイルなら方法1が安全です。
移行時のcompose関連の注意:
restart: alwaysは、デーモンのないPodmanでは「ブート時の自動起動」を意味しません — ブート自動化はQuadlet/systemdに移すのがPodman流の正解です。- 本番志向なら、composeの代わりに
podman kube play(Kubernetes YAMLを直接実行)も検討を。ローカルとKubernetesのマニフェストを統一できます。
移行の罠コレクション — 知っていれば30分、知らなければ半日
- SELinuxボリュームラベル:Fedora/RHELでボリュームマウントがPermission deniedなら、十中八九SELinuxです。
-v ./data:/data:Z(専用)または:z(共有)を付けます。Ubuntuから来たcomposeファイルが最も引っかかる罠です。 - unqualifiedイメージ名:上の設定節の
unqualified-search-registriesを指定しないと、podman pull nginxがDockerと違う挙動になります。CIスクリプトならdocker.io/library/nginxのような完全修飾パスが最も堅牢です。 - rootlessの保存容量:イメージがホームディレクトリ(
~/.local/share/containers)に溜まります。ホームが小さいサーバーではstorage.confのgraphrootを移してください。 - Dockerソケットに依存するツール(Testcontainers、一部CI):方法1のPodmanソケット+
DOCKER_HOSTでほぼ解決します。 podman-dockerパッケージ:dockerコマンドをpodmanにつなぐシムです。スクリプト互換に便利ですが、「このサーバーのdockerは実はpodman」だとチームに必ず周知を。- 段階的移行が可能:二つのエンジンはストレージが分離しており、一台のマシンに共存できます。サービス単位で一つずつ移せばよいのです。
バージョンとコミュニティ — 誰が作り、どこで議論されるか
バージョン感覚(2026年基準): Podmanは 5.x 世代で、4.xから5.0への移行でネットワークのデフォルトがpastaに変わり、CDIサポートが成熟しました。RHEL 9/10に深く統合され、Fedoraは何リリースも前からPodmanがデフォルトのコンテナツールです。Docker Engineは 27+ 世代で、依然として最大のエコシステムと文書量を持ちます。
ガバナンスとコミュニティ:
- Docker — Docker, Inc.が主導する商用製品+オープンソース(moby/moby)の二重構造です。Docker Desktopは一定規模以上の企業では有料サブスクリプションが必要です(エンジン自体はオープンソース)。膨大なチュートリアルとStack Overflowの蓄積が最大の資産です。
- Podman — Red Hatが主導する containers GitHub組織の一員で、Buildah(イメージビルド)・Skopeo(イメージ検査/コピー)と一つの家族を成します。すべてApache-2.0のオープンソースで、Podman Desktopも無料です。議論はGitHub(containers/podman)、Podmanメーリングリスト、Matrixチャンネルで活発で、RHEL系エンタープライズ環境での採用が特に強い。
どちらを使うかの実用基準:チームがRHEL/Fedora系である、rootlessセキュリティが要件である、systemdベースの運用を好む — ならPodmanが自然です。Docker Desktop依存のツールが多い、エコシステムの文書量が重要 — ならDockerが今も無難です。そして両者は同じOCI標準の上にあるので、イメージはどちらでビルドしてもどちらでも動きます — 標準があることの恵みです。
おわりに
DockerからPodmanへの移行はコマンドの置換ではなく 運用モデルの置換 です — デーモンからfork-execへ、rootfulからrootlessへ、daemon.jsonからcontainers.confファミリーへ、--gpus からCDIへ、composeのデーモン依存からソケット互換またはsystemd/Quadletへ。幸いOCI標準のおかげで、イメージやcompose.yamlといった成果物はほぼそのまま持ち越せ、罠は上に整理した数点(SELinuxラベル、unqualifiedイメージ、保存パス)に収束します。コンテナの基礎を手で固めたいなら、このサイトの コンテナ実習室 と Linuxターミナル もどうぞ。