移行で実際につまずくところ
一言でいうと
dockerからpodmanへの切り替えは、コマンドの入れ替えではなく、運用モデルの入れ替えです。デーモンからfork-execへ、rootfulからrootlessへ、daemon.jsonからcontainers.confファミリーへ。
なぜ必要なのか
alias docker=podmanで、ほとんどのコマンドがそのまま動作します。そのため、切り替えは簡単に見えます。しかし、実際に移すと、いくつかの点で必ず引っかかります。その、いくつかを事前に知っていれば30分、知らなければ半日です。
どう動くのか
構造の違い
Docker: docker CLI ──REST──▶ dockerd ──▶ containerd ──▶ runc ──▶ 컨테이너
Podman: podman CLI ──fork/exec──▶ conmon ──▶ crun ──▶ 컨테이너
podmanには、デーモンがありません。podman runは、ごく普通のプロセスのように、コンテナを直接作ります。コンテナごとに、小さな監視プロセスのconmonが付いて、stdioとexit codeを管理し、実際の作成は、OCIランタイムのcrun(Cで書かれていて、runcより軽い)が行います。
この構造が持つ含意は大きいです。
- 単一障害点がありません: dockerdが落ちたり、アップグレードしたりすると、すべてのコンテナ管理が止まりますが、podmanには最初から、中央のプロセスがありません。
- ルートデーモンのソケットという攻撃面がありません。
- systemdと自然に結合します: コンテナがごく普通の子プロセスなので、systemdのユニットとして、直接管理できます。
必ず引っかかる5つのこと
1. restart: alwaysの動作が違います。デーモンがないので、「起動時の自動開始」を意味しません。podman流の正解は、Quadletです。
# ~/.config/containers/systemd/web.container
[Unit]
Description=Web service
[Container]
Image=docker.io/library/nginx:1.27
PublishPort=8080:80
Volume=/srv/www:/usr/share/nginx/html:Z
[Service]
Restart=always
[Install]
WantedBy=default.target
.containerファイルを置くと、systemdがそれを読んで、サービスユニットを生成します。podman generate systemdは、古い方式になりました。
2. SELinuxのボリュームラベル: RHEL/Fedoraで、ボリュームのマウントがPermission deniedなら、十中八九SELinuxです。-v ./data:/data:Z(専用)または:z(共有)のラベルを付けます。Ubuntuから持ってきたcomposeファイルが、最もよく引っかかる落とし穴です。
3. unqualifiedのイメージ名: podman pull nginxが、dockerと違う動作をします。registries.confに、unqualified-search-registries = ["docker.io"]を入れるか、CIなら完全なパスを書きます。
4. 保存場所: rootlessのイメージは、~/.local/share/containers/storageです。docker system dfの感覚で、/var/libを探しても、見つかりません。
5. 1024未満のポート: rootlessは、特権ポートにバインドできません。
composeはどうするのか
道は2つあります。
- 方法1(推奨): podmanが提供するDocker API互換ソケットを有効にして、標準の
docker composeをそのまま使います。compose.yamlを修正する必要がなく、互換性が最も高いです。systemctl --user enable --now podman.socket export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock docker compose up -d - 方法2:
podman-compose(Pythonでの再実装)です。ソケットなしで、podmanコマンドを直接呼び出しますが、Composeスペックの細かい部分で、微妙な違いがあります。
本番指向なら、composeの代わりとして、podman kube play(KubernetesのYAMLを直接実行する)も選択肢です。ローカルとクラスターのマニフェストを、統一できます。
現場での姿
段階的な切り替えが可能です。2つのエンジンは、ストレージが分離されているので、1台のマシンに共存できます。サービス単位で、1つずつ移せば済みます。
podman-dockerパッケージ: dockerコマンドをpodmanにつなげてくれる、shimパッケージです。スクリプトの互換には役立ちますが、チームメンバーに、このサーバーのdockerは実はpodmanであることを、必ず周知する必要があります。そうしないと、dockerのドキュメントを見て出したコマンドが、微妙に違う動作をしたときに、原因を見つけられません。
次のラボですること
イメージをロードしてコンテナを実行し、ボリュームとユーザーマッピングを確認し、特権ポートの失敗を再現して、Quadlet .containerファイルを作成します。最後に、dockerとの違いを、証拠と一緒に表にまとめます。