Skip to content
Published on

DockerからPodmanへ — デーモンレス・コンテナエンジン移行完全ガイド

シェア
Authors

はじめに — コマンドは同じ、哲学は別物

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.confunqualifiedイメージの検索レジストリ を指定すること(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.confgraphroot を移してください。
  • 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ターミナル もどうぞ。

参考資料